org.lightadmin.core.persistence.support.DynamicDomainObjectMerger.java Source code

Java tutorial

Introduction

Here is the source code for org.lightadmin.core.persistence.support.DynamicDomainObjectMerger.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.persistence.support;

import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import org.lightadmin.core.config.domain.DomainTypeAdministrationConfiguration;
import org.lightadmin.core.config.domain.GlobalAdministrationConfiguration;
import org.lightadmin.core.config.domain.field.PersistentFieldMetadata;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanWrapper;
import org.springframework.core.convert.ConversionService;
import org.springframework.data.mapping.*;
import org.springframework.data.repository.support.Repositories;
import org.springframework.data.rest.core.support.DomainObjectMerger;
import org.springframework.data.util.DirectFieldAccessFallbackBeanWrapper;

import java.util.Collection;
import java.util.Iterator;

import static com.google.common.collect.Lists.newArrayList;
import static org.lightadmin.core.config.domain.field.FieldMetadataUtils.getPersistentField;
import static org.springframework.data.rest.core.support.DomainObjectMerger.NullHandlingPolicy.APPLY_NULLS;
import static org.springframework.util.ObjectUtils.nullSafeEquals;

public class DynamicDomainObjectMerger extends DomainObjectMerger {

    private static final Logger logger = LoggerFactory.getLogger(DynamicDomainObjectMerger.class);

    private final GlobalAdministrationConfiguration configuration;

    public DynamicDomainObjectMerger(Repositories repositories, ConversionService conversionService,
            GlobalAdministrationConfiguration configuration) {
        super(repositories, conversionService);

        this.configuration = configuration;
    }

    /**
     * Merges the given target object into the source one.
     *
     * @param from       can be {@literal null}.
     * @param target     can be {@literal null}.
     * @param nullPolicy how to handle {@literal null} values in the source object.
     */
    @Override
    public void merge(final Object from, final Object target, final NullHandlingPolicy nullPolicy) {
        if (from == null || target == null) {
            return;
        }

        final BeanWrapper fromWrapper = beanWrapper(from);
        final BeanWrapper targetWrapper = beanWrapper(target);

        final DomainTypeAdministrationConfiguration domainTypeAdministrationConfiguration = configuration
                .forManagedDomainType(target.getClass());
        final PersistentEntity<?, ?> entity = domainTypeAdministrationConfiguration.getPersistentEntity();

        entity.doWithProperties(new SimplePropertyHandler() {
            @Override
            public void doWithPersistentProperty(PersistentProperty<?> persistentProperty) {
                Object sourceValue = fromWrapper.getPropertyValue(persistentProperty.getName());
                Object targetValue = targetWrapper.getPropertyValue(persistentProperty.getName());

                if (entity.isIdProperty(persistentProperty)) {
                    return;
                }

                if (nullSafeEquals(sourceValue, targetValue)) {
                    return;
                }

                if (propertyIsHiddenInFormView(persistentProperty, domainTypeAdministrationConfiguration)) {
                    return;
                }

                if (nullPolicy == APPLY_NULLS || sourceValue != null) {
                    targetWrapper.setPropertyValue(persistentProperty.getName(), sourceValue);
                }
            }
        });

        entity.doWithAssociations(new SimpleAssociationHandler() {
            @Override
            @SuppressWarnings("unchecked")
            public void doWithAssociation(Association<? extends PersistentProperty<?>> association) {
                PersistentProperty<?> persistentProperty = association.getInverse();

                Object fromValue = fromWrapper.getPropertyValue(persistentProperty.getName());
                Object targetValue = targetWrapper.getPropertyValue(persistentProperty.getName());

                if (propertyIsHiddenInFormView(persistentProperty, domainTypeAdministrationConfiguration)) {
                    return;
                }

                if ((fromValue == null && nullPolicy == APPLY_NULLS)) {
                    targetWrapper.setPropertyValue(persistentProperty.getName(), fromValue);
                }

                if (persistentProperty.isCollectionLike()) {
                    Collection<Object> sourceCollection = (Collection) fromValue;
                    Collection<Object> targetCollection = (Collection) targetValue;

                    Collection<Object> candidatesForAddition = candidatesForAddition(sourceCollection,
                            targetCollection, persistentProperty);
                    Collection<Object> candidatesForRemoval = candidatesForRemoval(sourceCollection,
                            targetCollection, persistentProperty);

                    removeReferencedItems(targetCollection, candidatesForRemoval);

                    addReferencedItems(targetCollection, candidatesForAddition);

                    return;
                }

                if (!nullSafeEquals(fromValue, targetWrapper.getPropertyValue(persistentProperty.getName()))) {
                    targetWrapper.setPropertyValue(persistentProperty.getName(), fromValue);
                }
            }
        });
    }

    private boolean propertyIsHiddenInFormView(PersistentProperty persistentProperty,
            DomainTypeAdministrationConfiguration configuration) {
        PersistentFieldMetadata persistentField = getPersistentField(
                configuration.getFormViewFragment().getFields(), persistentProperty.getName());

        return persistentField == null;
    }

    private void addReferencedItems(Collection<Object> targetCollection, Collection<Object> candidatesForAddition) {
        for (Object candidateForAddition : candidatesForAddition) {
            targetCollection.add(candidateForAddition);
        }
    }

    private void removeReferencedItems(Collection<Object> targetCollection,
            Collection<Object> candidatesForRemoval) {
        Iterator<Object> itr = targetCollection.iterator();
        while (itr.hasNext()) {
            Object obj = itr.next();
            if (mathesAny(candidatesForRemoval, obj)) {
                itr.remove();
            }
        }
    }

    private Collection<Object> candidatesForRemoval(Collection<Object> sourceCollection,
            Collection<Object> targetCollection, PersistentProperty<?> persistentProperty) {
        Collection<Object> candidatesForRemoval = newArrayList();
        for (Object targetItem : targetCollection) {
            if (!mathesAny(sourceCollection, targetItem)) {
                candidatesForRemoval.add(targetItem);
            }
        }
        return candidatesForRemoval;
    }

    private Collection<Object> candidatesForAddition(Collection<Object> sourceCollection,
            Collection<Object> targetCollection, PersistentProperty<?> persistentProperty) {
        Collection<Object> candidatesForAddition = newArrayList();
        for (Object sourceItem : sourceCollection) {
            if (!mathesAny(targetCollection, sourceItem)) {
                candidatesForAddition.add(sourceItem);
            }
        }
        return candidatesForAddition;
    }

    private boolean mathesAny(Collection<Object> collection, final Object item) {
        final PersistentEntity<?, ?> persistentEntity = configuration.forManagedDomainType(item.getClass())
                .getPersistentEntity();
        final PersistentProperty<?> idProperty = persistentEntity.getIdProperty();

        return Iterables.any(collection, new Predicate<Object>() {
            @Override
            public boolean apply(Object object) {
                return itemsEqual(object, item, idProperty);
            }
        });
    }

    private boolean itemsEqual(Object item1, Object item2, final PersistentProperty<?> idProperty) {
        if (nullSafeEquals(item1, item2)) {
            return true;
        }

        Object sourceItemIdValue = beanWrapper(item1).getPropertyValue(idProperty.getName());
        Object itemIdValue = beanWrapper(item2).getPropertyValue(idProperty.getName());

        return nullSafeEquals(itemIdValue, sourceItemIdValue);
    }

    private DirectFieldAccessFallbackBeanWrapper beanWrapper(Object item1) {
        return new DirectFieldAccessFallbackBeanWrapper(item1);
    }
}