Skip to content

Commit

Permalink
Performance optimization [Handling file property values]
Browse files Browse the repository at this point in the history
  • Loading branch information
max-dev committed Sep 3, 2014
1 parent bb58309 commit de42007
Show file tree
Hide file tree
Showing 7 changed files with 168 additions and 82 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,21 +15,22 @@
*/
package org.lightadmin.core.web;

import com.google.common.collect.Maps;
import org.lightadmin.core.config.LightAdminConfiguration;
import org.lightadmin.core.config.domain.GlobalAdministrationConfiguration;
import org.lightadmin.core.storage.OperationBuilder;
import org.lightadmin.core.web.support.DynamicRepositoryEntityLinks;
import org.lightadmin.core.web.support.FilePropertyValue;
import org.lightadmin.core.web.support.FileResourceLoader;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mapping.PersistentEntity;
import org.springframework.data.mapping.PersistentProperty;
import org.springframework.data.rest.core.invoke.RepositoryInvoker;
import org.springframework.data.rest.webmvc.ControllerUtils;
import org.springframework.data.rest.webmvc.RepositoryRestController;
import org.springframework.data.rest.webmvc.ResourceNotFoundException;
import org.springframework.data.rest.webmvc.RootResourceInformation;
import org.springframework.data.rest.webmvc.support.BackendId;
import org.springframework.hateoas.Link;
import org.springframework.hateoas.Resource;
import org.springframework.hateoas.ResourceSupport;
import org.springframework.http.HttpHeaders;
Expand All @@ -48,6 +49,8 @@

import static org.lightadmin.core.persistence.metamodel.PersistentPropertyType.isOfFileType;
import static org.lightadmin.core.storage.OperationBuilder.operationBuilder;
import static org.springframework.data.rest.webmvc.ControllerUtils.toEmptyResponse;
import static org.springframework.data.rest.webmvc.ControllerUtils.toResponseEntity;
import static org.springframework.http.HttpStatus.METHOD_NOT_ALLOWED;
import static org.springframework.http.HttpStatus.OK;
import static org.springframework.web.bind.annotation.RequestMethod.*;
Expand Down Expand Up @@ -85,6 +88,29 @@ public void filePropertyOfEntity(RootResourceInformation repoRequest, ServletRes
}
}

@RequestMapping(value = BASE_MAPPING + "/binary", method = GET)
public ResponseEntity<?> filePropertyValueOfEntity(RootResourceInformation repoRequest, @BackendId Serializable id, @PathVariable String property) throws Exception {
PersistentEntity<?, ?> persistentEntity = repoRequest.getPersistentEntity();
RepositoryInvoker invoker = repoRequest.getInvoker();

Object domainObj = invoker.invokeFindOne(id);

if (null == domainObj) {
throw new ResourceNotFoundException();
}

PersistentProperty<?> prop = persistentEntity.getPersistentProperty(property);
if (null == prop) {
throw new ResourceNotFoundException();
}

if (isOfFileType(prop)) {
return toResponseEntity(OK, new HttpHeaders(), new Resource<FilePropertyValue>(evaluateFilePropertyValue(domainObj, prop)));
}

return toEmptyResponse(METHOD_NOT_ALLOWED);
}

@RequestMapping(value = BASE_MAPPING + "/file", method = DELETE)
public ResponseEntity<?> deleteFileOfPropertyOfEntity(RootResourceInformation repoRequest, @BackendId Serializable id, @PathVariable String property) throws Exception {
PersistentEntity<?, ?> persistentEntity = repoRequest.getPersistentEntity();
Expand All @@ -102,12 +128,12 @@ public ResponseEntity<?> deleteFileOfPropertyOfEntity(RootResourceInformation re
}

if (!isOfFileType(prop)) {
return ControllerUtils.toEmptyResponse(METHOD_NOT_ALLOWED);
return toEmptyResponse(METHOD_NOT_ALLOWED);
}

operation().deleteOperation(domainObj).perform(prop);

return ControllerUtils.toEmptyResponse(OK);
return toEmptyResponse(OK);
}

@RequestMapping(value = BASE_MAPPING + "/file", method = {POST})
Expand All @@ -119,17 +145,37 @@ public ResponseEntity<? extends ResourceSupport> saveFilePropertyOfEntity(final
if (!fileMap.isEmpty()) {
final Map.Entry<String, MultipartFile> fileEntry = fileMap.entrySet().iterator().next();

return ControllerUtils.toResponseEntity(OK, new HttpHeaders(), fileResource(fileEntry));
return toResponseEntity(OK, new HttpHeaders(), fileResource(fileEntry));
}

return ControllerUtils.toEmptyResponse(METHOD_NOT_ALLOWED);
return toEmptyResponse(METHOD_NOT_ALLOWED);
}

private FilePropertyValue evaluateFilePropertyValue(Object instance, PersistentProperty persistentProperty) {
try {
boolean fileExists = operation().fileExistsOperation(instance).perform(persistentProperty);

if (!fileExists) {
return new FilePropertyValue(fileExists);
}

Link fileLink = entityLinks().linkForFilePropertyLink(instance, persistentProperty);

byte[] fileData = operation().getOperation(instance).perform(persistentProperty);

return new FilePropertyValue(fileLink, fileData);

} catch (Exception e) {
throw new ResourceNotFoundException(e.getMessage());
}
}

private Resource<?> fileResource(Map.Entry<String, MultipartFile> fileEntry) throws IOException {
SimpleMapResource resource = new SimpleMapResource();
resource.put("fileName", fileEntry.getValue().getOriginalFilename());
resource.put("fileContent", fileEntry.getValue().getBytes());
return resource;
private Resource<FilePropertyValue> fileResource(Map.Entry<String, MultipartFile> fileEntry) throws IOException {
MultipartFile multipartFile = fileEntry.getValue();

FilePropertyValue filePropertyValue = new FilePropertyValue(multipartFile.getOriginalFilename(), multipartFile.getBytes());

return new Resource<FilePropertyValue>(filePropertyValue);
}

private OperationBuilder operation() {
Expand All @@ -148,14 +194,7 @@ private FileResourceLoader fileResourceLoader() {
return beanFactory.getBean(FileResourceLoader.class);
}

private static class SimpleMapResource extends Resource<Map<String, Object>> {

public SimpleMapResource() {
super(Maps.<String, Object>newLinkedHashMap());
}

public void put(String key, Object value) {
getContent().put(key, value);
}
private DynamicRepositoryEntityLinks entityLinks() {
return beanFactory.getBean(DynamicRepositoryEntityLinks.class);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonUnwrapped;
import org.lightadmin.api.config.utils.EntityNameExtractor;
import org.lightadmin.core.config.LightAdminConfiguration;
import org.lightadmin.core.config.domain.DomainTypeAdministrationConfiguration;
Expand Down Expand Up @@ -113,7 +112,7 @@ private Map<DomainConfigurationUnitType, Map<String, Object>> dynamicPropertiesP
for (DomainConfigurationUnitType unit : units) {
Map<String, Object> dynamicProperties = newLinkedHashMap();
for (PersistentProperty persistentProperty : persistentProperties) {
dynamicProperties.put(persistentProperty.getName(), evaluateFilePropertyValue(persistentProperty, value, managedDomainTypeConfiguration, binaryDataExportNeeded(unit)));
dynamicProperties.put(persistentProperty.getName(), evaluateFilePropertyValue(persistentProperty, value));
}
for (FieldMetadata customField : customFields(managedDomainTypeConfiguration.fieldsForUnit(unit))) {
dynamicProperties.put(customField.getUuid(), customField.getValue(value));
Expand All @@ -139,73 +138,18 @@ public void doWithPersistentProperty(PersistentProperty<?> property) {
return result;
}

private Object evaluateFilePropertyValue(PersistentProperty persistentProperty, Object value, DomainTypeAdministrationConfiguration configuration, boolean binaryDataExportNeeded) {
private FilePropertyValue evaluateFilePropertyValue(PersistentProperty persistentProperty, Object value) {
try {
boolean fileExists = operationBuilder.fileExistsOperation(value).perform(persistentProperty);

if (!fileExists) {
return new FilePropertyValue(fileExists);
}

Link fileLink = entityLinks.linkForFilePropertyLink(value, persistentProperty);

if (!binaryDataExportNeeded) {
return new FilePropertyValue(fileLink);
}

byte[] fileData = operationBuilder.getOperation(value).perform(persistentProperty);

return new FilePropertyValue(fileLink, fileData);

return new FilePropertyValue(entityLinks.linkForFilePropertyLink(value, persistentProperty));
} catch (Exception e) {
return null;
}
}

private boolean binaryDataExportNeeded(DomainConfigurationUnitType unit) {
return unit == FORM_VIEW;
}

static class FilePropertyValue {
private boolean fileExists;
private Link fileLink;
private byte[] value;

FilePropertyValue(boolean fileExists) {
this.fileExists = fileExists;
}

public FilePropertyValue(Link fileLink) {
this(true);
this.fileLink = fileLink;
}

public FilePropertyValue(Link fileLink, byte[] value) {
this(fileLink);
this.value = value;
}

@JsonUnwrapped
@JsonProperty("file_exists")
public boolean isFileExists() {
return fileExists;
}

@JsonUnwrapped
@JsonInclude(NON_NULL)
@JsonProperty("file_link")
public Link getFileLink() {
return fileLink;
}

@JsonUnwrapped
@JsonInclude(NON_EMPTY)
@JsonProperty("value")
public byte[] getValue() {
return value;
}
}

static class PersistentEntityWrapper {
private String stringRepresentation;
private boolean managedDomainType;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/*
* Copyright 2012-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.lightadmin.core.web.support;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonUnwrapped;
import org.springframework.hateoas.Link;

import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_EMPTY;
import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_NULL;

/**
* TODO: Document me!
*
* @author Maxim Kharchenko (kharchenko.max@gmail.com)
*/
public class FilePropertyValue {
private boolean fileExists;
private Link fileLink;
private String fileName;
private byte[] value;

public FilePropertyValue(boolean fileExists) {
this.fileExists = fileExists;
}

public FilePropertyValue(Link fileLink) {
this(true);
this.fileLink = fileLink;
}

public FilePropertyValue(Link fileLink, byte[] value) {
this(fileLink);
this.value = value;
}

public FilePropertyValue(String fileName, byte[] value) {
this.fileName = fileName;
this.value = value;
}

@JsonUnwrapped
@JsonInclude(NON_NULL)
@JsonProperty("file_name")
public String getFileName() {
return fileName;
}

@JsonUnwrapped
@JsonProperty("file_exists")
public boolean isFileExists() {
return fileExists;
}

@JsonUnwrapped
@JsonInclude(NON_NULL)
@JsonProperty("file_link")
public Link getFileLink() {
return fileLink;
}

@JsonUnwrapped
@JsonInclude(NON_EMPTY)
@JsonProperty("value")
public byte[] getValue() {
return value;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -184,10 +184,12 @@ function LoadDomainEntityAction(resourceName) {
break;
case 'FILE':
var fileSelected = propertyValue['file_exists'];
var fileUploaderController = new FileUploaderController(resourceName, form, propertyName);
if (fileSelected) {
new FileUploaderController(resourceName, form, propertyName).selectFile(domainEntity.getPrimaryKeyValue(), propertyValue);
fileUploaderController.selectFile(domainEntity.getPrimaryKeyValue(), propertyValue);
}
editor.val(propertyValue['value']);
var filePropertyValue = fileUploaderController.loadFile(domainEntity.getPrimaryKeyValue());
editor.val(filePropertyValue['value']);
break;
case 'STRING':
if (editor.hasClass('wysiwyg')) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,23 @@ function FileUploaderController(resourceName, form, attr) {
});
}

function loadFilePropertyValue(resourceName, entityId, propertyName) {
var filePropertyValue = {};
$.ajax({
url: ApplicationConfig.getDomainEntityFilePropertyValueRestUrl(resourceName, entityId, propertyName),
dataType: 'json',
async: false,
success: function (rawFilePropertyValue) {
filePropertyValue = rawFilePropertyValue;
}
});
return filePropertyValue;
}

return {
loadFile: function(entityId) {
return loadFilePropertyValue(resourceName, entityId, attr);
},
selectFile: function (entityId, attr_value) {
var property = ConfigurationMetadataService.getProperty(resourceName, attr, 'formView');

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ var FileUploaderDecorator = (function () {

var result = $.parseJSON(response.response);

$(file_input_id).val(result['content']['fileContent']);
$(file_input_id).val(result['value']);
}
}
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@
getDomainEntityFilePropertyRestUrl: function(resourceName, entityId, propertyName) {
return this.getDomainEntityPropertyRestUrl(resourceName, entityId, propertyName) + '/file';
},
getDomainEntityFilePropertyValueRestUrl: function(resourceName, entityId, propertyName) {
return this.getDomainEntityPropertyRestUrl(resourceName, entityId, propertyName) + '/binary';
},
getDomainEntityUrl: function(resourceName, entityId) {
return this.getDomainEntityCollectionUrl(resourceName) + '/' + entityId;
},
Expand Down

0 comments on commit de42007

Please sign in to comment.