Package org.springmodules.prevayler.id

Source Code of org.springmodules.prevayler.id.DefaultIdMerger

package org.springmodules.prevayler.id;

import java.lang.reflect.Field;
import java.util.Collection;
import java.util.IdentityHashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import org.springmodules.prevayler.id.support.PrevaylerIdMergeException;
import org.springmodules.prevayler.support.PrevaylerConfigurationException;
import org.springmodules.prevayler.system.PrevalenceInfo;

/**
* {@link IdMerger} default implementation.
*
* @author Sergio Bossa
*/
public class DefaultIdMerger implements IdMerger {
   
    private static final long serialVersionUID = 476105208506333743L;
   
    private static final ThreadLocal localIdentityMap = new ThreadLocal();
   
    private PrevalenceInfo prevalenceInfo;
   
    public DefaultIdMerger(PrevalenceInfo info) {
        this.prevalenceInfo = info;
    }
   
    public DefaultIdMerger() {
    }
   
    public void setPrevalenceInfo(PrevalenceInfo info) {
        this.prevalenceInfo = info;
    }
   
    public void merge(Object source, Object destination) {
        Class sourceClass = source.getClass();
        Class destinationClass = destination.getClass();
        if (! sourceClass.equals(destinationClass)) {
            throw new IllegalArgumentException("Source and destination objects are not of the same class!");
        }
        else if (source == destination) {
            return;
        }
        else {
            this.localIdentityMap.set(new IdentityHashMap());
            this.doMerge(source, destination);
        }
    }
   
    private void doMerge(Object sourceValue, Object destinationValue) {
        if (sourceValue != null && destinationValue != null) {
            if (sourceValue.getClass().isArray()) {
                this.traverseArray((Object[]) sourceValue, (Object[]) destinationValue);
            }
            else if (Collection.class.isAssignableFrom(sourceValue.getClass())) {
                this.traverseCollection((Collection) sourceValue, (Collection) destinationValue);
            }
            else if (Map.class.isAssignableFrom(sourceValue.getClass())) {
                this.traverseMap((Map) sourceValue, (Map) destinationValue);
            }
            else if (this.prevalenceInfo.getPrevalentClass(sourceValue.getClass()) != null) {
                this.mergePrevalentObjectIdentifiers(sourceValue, destinationValue);
            }
        }
    }

    private void traverseArray(Object[] sourceArray, Object[] destinationArray) {
        for (int i = 0; i < sourceArray.length; i++) {
            this.doMerge(sourceArray[i], destinationArray[i]);
        }
    }
   
    private void traverseCollection(Collection sourceCollection, Collection destinationCollection) {
        Iterator sIt = sourceCollection.iterator();
        Iterator dIt = destinationCollection.iterator();
        while (sIt.hasNext()) {
            this.doMerge(sIt.next(), dIt.next());
        }
    }
   
    private void traverseMap(Map sourceMap, Map destinationMap) {
        Iterator sIt = sourceMap.entrySet().iterator();
        Iterator dIt = destinationMap.entrySet().iterator();
        while (sIt.hasNext()) {
            Map.Entry sourceEntry = (Entry) sIt.next();
            Map.Entry destinationEntry = (Entry) dIt.next();
            this.doMerge(sourceEntry.getKey(), destinationEntry.getKey());
            this.doMerge(sourceEntry.getValue(), destinationEntry.getValue());
        }
    }

    private void mergePrevalentObjectIdentifiers(Object sourceEntity, Object destinationEntity) {
        try {
            Class sourcePrevalentClass = this.prevalenceInfo.getPrevalentClass(sourceEntity.getClass());
            Class destinationPrevalentClass = this.prevalenceInfo.getPrevalentClass(destinationEntity.getClass());
            // If entities have prevalent classes:
            if (sourcePrevalentClass != null && destinationPrevalentClass != null) {
                if (sourcePrevalentClass.equals(destinationPrevalentClass)) {
                    // Copy the identifier from source to destination:
                    Field sourceIdField = this.prevalenceInfo.getIdResolutionStrategy().resolveId(sourceEntity);
                    Field destinationIdField = this.prevalenceInfo.getIdResolutionStrategy().resolveId(destinationEntity);
                    destinationIdField.set(destinationEntity, sourceIdField.get(sourceEntity));
                    // Cascade the merge:
                    this.cascadeMerge(sourceEntity, destinationEntity);
                }
                else {
                    throw new IllegalStateException("Classes don't match!");
                }
            }
            else {
                throw new PrevaylerConfigurationException("Object with no configured prevalent class!");
            }
        }
        catch (IllegalAccessException actual) {
            throw new IllegalStateException("Cannot access id value!", actual);
        }
    }
   
    private void cascadeMerge(Object source, Object destination) {
        // We are traversing the source object graph, and we'll have to put in an identity map the source object.
        IdentityHashMap localIdentityMap = (IdentityHashMap) DefaultIdMerger.localIdentityMap.get();
        if (! localIdentityMap.containsKey(source)) {
            localIdentityMap.put(source, new Integer(1));
            this.doCascadeMerge(source, destination);
        }
    }
   
    private void doCascadeMerge(Object source, Object destination) {
        Class currentClass = source.getClass();
        while (currentClass != null) {
            try {
                Field[] fields = currentClass.getDeclaredFields();
                for (int counter = 0; counter < fields.length; counter++) {
                    Field currentField = fields[counter];
                    currentField.setAccessible(true);

                    Object sourceValue = currentField.get(source);
                    Object destinationValue = currentField.get(destination);
                    this.doMerge(sourceValue, destinationValue);   
                }
                currentClass = currentClass.getSuperclass();
            }
            catch(IllegalAccessException ex) {
                throw new PrevaylerIdMergeException(ex.getMessage(), ex);
            }
        }
    }
}
TOP

Related Classes of org.springmodules.prevayler.id.DefaultIdMerger

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.