org.lightadmin.core.web.support.DynamicPersistentEntityResourceProcessor.java Source code

Java tutorial

Introduction

Here is the source code for org.lightadmin.core.web.support.DynamicPersistentEntityResourceProcessor.java

Source

/*
 * 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 org.lightadmin.api.config.utils.EntityNameExtractor;
import org.lightadmin.core.config.domain.DomainTypeAdministrationConfiguration;
import org.lightadmin.core.config.domain.DomainTypeBasicConfiguration;
import org.lightadmin.core.config.domain.GlobalAdministrationConfiguration;
import org.lightadmin.core.config.domain.field.FieldMetadata;
import org.lightadmin.core.config.domain.unit.DomainConfigurationUnitType;
import org.lightadmin.core.persistence.metamodel.PersistentPropertyType;
import org.lightadmin.core.storage.FileResourceStorage;
import org.springframework.data.mapping.*;
import org.springframework.data.rest.core.mapping.ResourceMappings;
import org.springframework.data.rest.webmvc.PersistentEntityResource;
import org.springframework.data.rest.webmvc.mapping.AssociationLinks;
import org.springframework.data.util.DirectFieldAccessFallbackBeanWrapper;
import org.springframework.hateoas.Link;
import org.springframework.hateoas.ResourceProcessor;

import java.util.Collections;
import java.util.List;
import java.util.Map;

import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_EMPTY;
import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_NULL;
import static com.google.common.collect.Lists.newArrayList;
import static com.google.common.collect.Maps.newHashMap;
import static com.google.common.collect.Maps.newLinkedHashMap;
import static org.lightadmin.core.config.domain.configuration.support.ExceptionAwareTransformer.exceptionAwareNameExtractor;
import static org.lightadmin.core.config.domain.field.FieldMetadataUtils.customFields;
import static org.lightadmin.core.config.domain.field.FieldMetadataUtils.transientFields;
import static org.lightadmin.core.config.domain.unit.DomainConfigurationUnitType.*;
import static org.lightadmin.core.persistence.metamodel.PersistentPropertyType.FILE;
import static org.lightadmin.core.web.support.DynamicPersistentEntityResourceProcessor.PersistentEntityWrapper.persistentEntity;

@SuppressWarnings(value = { "unchecked", "unused" })
public class DynamicPersistentEntityResourceProcessor implements ResourceProcessor<PersistentEntityResource<?>> {

    private final GlobalAdministrationConfiguration adminConfiguration;
    private final DynamicRepositoryEntityLinks entityLinks;
    private final DomainEntityLinks domainEntityLinks;
    private final FileResourceStorage fileResourceStorage;
    private final AssociationLinks associationLinks;

    public DynamicPersistentEntityResourceProcessor(GlobalAdministrationConfiguration adminConfiguration,
            FileResourceStorage fileResourceStorage, DynamicRepositoryEntityLinks entityLinks,
            DomainEntityLinks domainEntityLinks, ResourceMappings resourceMappings) {
        this.adminConfiguration = adminConfiguration;
        this.domainEntityLinks = domainEntityLinks;
        this.entityLinks = entityLinks;
        this.fileResourceStorage = fileResourceStorage;
        this.associationLinks = new AssociationLinks(resourceMappings);
    }

    @Override
    public PersistentEntityResource<?> process(PersistentEntityResource<?> persistentEntityResource) {
        PersistentEntity persistentEntity = persistentEntityResource.getPersistentEntity();
        Object value = persistentEntityResource.getContent();
        Link[] links = persistentEntityResource.getLinks()
                .toArray(new Link[persistentEntityResource.getLinks().size()]);

        String stringRepresentation = stringRepresentation(value, persistentEntity);
        Link domainLink = domainLink(persistentEntityResource);
        boolean managedDomainType = adminConfiguration.isManagedDomainType(persistentEntity.getType());
        String primaryKey = primaryKey(persistentEntity);

        Map<DomainConfigurationUnitType, Map<String, Object>> dynamicProperties = dynamicPropertiesPerUnit(value,
                persistentEntity);

        PersistentEntityWrapper persistentEntityWrapper = persistentEntity(value, dynamicProperties,
                stringRepresentation, domainLink, managedDomainType, primaryKey);

        return new PersistentEntityResource<Object>(persistentEntity, persistentEntityWrapper, links);
    }

    private String primaryKey(PersistentEntity persistentEntity) {
        return persistentEntity.getIdProperty().getName();
    }

    private String stringRepresentation(Object value, PersistentEntity persistentEntity) {
        DomainTypeBasicConfiguration domainTypeBasicConfiguration = adminConfiguration
                .forDomainType(persistentEntity.getType());
        EntityNameExtractor nameExtractor = domainTypeBasicConfiguration.getEntityConfiguration()
                .getNameExtractor();

        return exceptionAwareNameExtractor(nameExtractor, domainTypeBasicConfiguration).apply(value);
    }

    private Link domainLink(PersistentEntityResource persistentEntityResource) {
        PersistentEntity persistentEntity = persistentEntityResource.getPersistentEntity();
        if (domainEntityLinks.supports(persistentEntity.getType())) {
            return domainEntityLinks.linkFor(persistentEntityResource);
        }
        return null;
    }

    private Map<DomainConfigurationUnitType, Map<String, Object>> dynamicPropertiesPerUnit(Object value,
            PersistentEntity persistentEntity) {
        if (!adminConfiguration.isManagedDomainType(persistentEntity.getType())) {
            return Collections.emptyMap();
        }

        DomainTypeAdministrationConfiguration managedDomainTypeConfiguration = adminConfiguration
                .forManagedDomainType(persistentEntity.getType());

        List<DomainConfigurationUnitType> units = newArrayList(LIST_VIEW, FORM_VIEW, SHOW_VIEW, QUICK_VIEW);

        List<PersistentProperty> persistentProperties = findPersistentFileProperties(persistentEntity);
        List<Association> associations = findLinkableAssociations(persistentEntity);

        Map<DomainConfigurationUnitType, Map<String, Object>> dynamicPropertiesPerUnit = newHashMap();
        for (DomainConfigurationUnitType unit : units) {
            Map<String, Object> dynamicProperties = newLinkedHashMap();
            for (PersistentProperty persistentProperty : persistentProperties) {
                dynamicProperties.put(persistentProperty.getName(), filePropertyValue(persistentProperty, value));
            }
            for (Association association : associations) {
                dynamicProperties.put(association.getInverse().getName(),
                        associationPropertyValue(association, value));
            }
            for (FieldMetadata customField : customFields(managedDomainTypeConfiguration.fieldsForUnit(unit))) {
                dynamicProperties.put(customField.getUuid(), customField.getValue(value));
            }
            for (FieldMetadata transientField : transientFields(
                    managedDomainTypeConfiguration.fieldsForUnit(unit))) {
                dynamicProperties.put(transientField.getUuid(), transientField.getValue(value));
            }
            dynamicPropertiesPerUnit.put(unit, dynamicProperties);
        }
        return dynamicPropertiesPerUnit;
    }

    private Object associationPropertyValue(Association association, Object instance) {
        PersistentProperty persistentProperty = association.getInverse();
        PersistentEntity persistentEntity = persistentProperty.getOwner();

        if (persistentProperty.isMap()) {
            return null;
        }

        if (persistentProperty.isCollectionLike()) {
            return associatedPersistentEntities(association, instance);
        }

        Object associationValue = beanWrapper(instance).getPropertyValue(persistentProperty.getName());

        return associatedPersistentEntity(persistentProperty, associationValue);
    }

    private List<PersistentEntityWrapper> associatedPersistentEntities(Association association, Object instance) {
        PersistentProperty persistentProperty = association.getInverse();

        Object associationValue = beanWrapper(instance).getPropertyValue(persistentProperty.getName());
        if (associationValue == null) {
            return null;
        }

        List<PersistentEntityWrapper> result = newArrayList();

        if (persistentProperty.isArray()) {
            for (Object item : (Object[]) associationValue) {
                result.add(associatedPersistentEntity(persistentProperty, item));
            }
            return result;
        }

        for (Object item : (Iterable<Object>) associationValue) {
            result.add(associatedPersistentEntity(persistentProperty, item));
        }
        return result;
    }

    private PersistentEntityWrapper associatedPersistentEntity(PersistentProperty persistentProperty,
            Object associationValue) {
        if (associationValue == null) {
            return null;
        }

        Class associationType = persistentProperty.getActualType();
        boolean managedDomainType = adminConfiguration.isManagedDomainType(associationType);
        PersistentEntity associationPersistentEntity = adminConfiguration.forDomainType(associationType)
                .getPersistentEntity();

        String stringRepresentation = stringRepresentation(associationValue, associationPersistentEntity);
        String primaryKey = primaryKey(associationPersistentEntity);
        Object primaryKeyValue = beanWrapper(associationValue).getPropertyValue(primaryKey);

        Link domainLink = null;
        if (domainEntityLinks.supports(associationType)) {
            domainLink = domainEntityLinks.linkToSingleResource(associationType, primaryKeyValue);
        }

        return PersistentEntityWrapper.associatedPersistentEntity(stringRepresentation, managedDomainType,
                primaryKey, primaryKeyValue, domainLink);
    }

    private static DirectFieldAccessFallbackBeanWrapper beanWrapper(Object instance) {
        return new DirectFieldAccessFallbackBeanWrapper(instance);
    }

    private List<PersistentProperty> findPersistentFileProperties(PersistentEntity persistentEntity) {
        final List<PersistentProperty> result = newArrayList();
        persistentEntity.doWithProperties(new SimplePropertyHandler() {
            @Override
            public void doWithPersistentProperty(PersistentProperty<?> property) {
                if (PersistentPropertyType.forPersistentProperty(property) == FILE) {
                    result.add(property);
                }
            }
        });
        return result;
    }

    private List<Association> findLinkableAssociations(PersistentEntity persistentEntity) {
        final List<Association> result = newArrayList();
        persistentEntity.doWithAssociations(new SimpleAssociationHandler() {
            @Override
            public void doWithAssociation(Association<? extends PersistentProperty<?>> association) {
                if (associationLinks.isLinkableAssociation(association.getInverse())) {
                    result.add(association);
                }
            }
        });
        return result;
    }

    private FilePropertyValue filePropertyValue(PersistentProperty persistentProperty, Object value) {
        try {
            if (!fileResourceStorage.fileExists(value, persistentProperty)) {
                return new FilePropertyValue(false);
            }
            return new FilePropertyValue(entityLinks.linkForFilePropertyLink(value, persistentProperty));
        } catch (Exception e) {
            return null;
        }
    }

    static class PersistentEntityWrapper {
        private String stringRepresentation;
        private boolean managedDomainType;
        private String primaryKey;
        private Link domainLink;
        private Object persistentEntity;
        private Map<DomainConfigurationUnitType, Map<String, Object>> dynamicProperties;

        private PersistentEntityWrapper(Object persistentEntity,
                Map<DomainConfigurationUnitType, Map<String, Object>> dynamicProperties,
                String stringRepresentation, Link domainLink, boolean managedDomainType, String primaryKey) {
            this.stringRepresentation = stringRepresentation;
            this.domainLink = domainLink;
            this.managedDomainType = managedDomainType;
            this.persistentEntity = persistentEntity;
            this.dynamicProperties = dynamicProperties;
            this.primaryKey = primaryKey;
        }

        public static PersistentEntityWrapper associatedPersistentEntity(String stringRepresentation,
                boolean managedDomainType, String primaryKey, Object primaryKeyValue, Link domainLink) {
            Map<String, Object> persistentEntity = newHashMap();
            persistentEntity.put(primaryKey, primaryKeyValue);

            return new PersistentEntityWrapper(persistentEntity, null, stringRepresentation, domainLink,
                    managedDomainType, primaryKey);
        }

        public static PersistentEntityWrapper persistentEntity(Object instance,
                Map<DomainConfigurationUnitType, Map<String, Object>> dynamicProperties,
                String stringRepresentation, Link domainLink, boolean managedDomainType, String primaryKey) {
            return new PersistentEntityWrapper(instance, dynamicProperties, stringRepresentation, domainLink,
                    managedDomainType, primaryKey);
        }

        @JsonProperty("string_representation")
        public String getStringRepresentation() {
            return stringRepresentation;
        }

        @JsonProperty("primary_key")
        public String getPrimaryKey() {
            return primaryKey;
        }

        @JsonProperty("managed_type")
        public boolean isManagedDomainType() {
            return managedDomainType;
        }

        @JsonProperty("domain_link")
        @JsonInclude(NON_NULL)
        public Link getDomainLink() {
            return domainLink;
        }

        @JsonProperty("original_properties")
        @JsonInclude(NON_NULL)
        public Object getPersistentEntity() {
            return persistentEntity;
        }

        @JsonProperty("dynamic_properties")
        @JsonInclude(NON_EMPTY)
        public Map<DomainConfigurationUnitType, Map<String, Object>> getDynamicProperties() {
            return dynamicProperties;
        }
    }
}