Skip to main content
summaryrefslogblamecommitdiffstats
blob: 9a17ff82ea2fcb8c5072413530a348a6810dd329 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
                                                                                
                                 







                                                                                 
                                           
 
                           

                             
                         
                          



                      

                                                      
                                                
                                       
                                                               
                                                        
                                                              
                                                                       


                                                
                                          
                                             

                                               
                                             
                                                








                                                                                                     
                                                                     
             
   
                                                                                          


                                                                          


                                                                                                                   
                                                                     



                                                                                                                 
                                                    
 



                                                                                   

                                                                    



                                                                                                      

                      
                                                                                    



                                                        
                                                                        
                                                                                  




                                                                                               





                                               
                                                                          








                                                                                            
                                                                         


                                                                                       
                 


           

















                                                                                                                        

                                                                  
                                                                    






                                                                                             

                                                   
                                                                    
















































































































































































                                                                                                                                                







                                                                                                               
                                                                              

                                                                     




                                                                                                             





                                 
                                                                                                                
           





                                                      
                                    
                                                                                                 
           
                   
                                                                                                      











                                                                                                                


                                                                                                     
                                    
                                                                                                 
           



                                                                                                    


           
                                                                                                                







                                                      
                                                                                      
                                                                                                     


                                                                                                             
                                    

                                      
                                                                                                    
                                                          




                                                                           
                                           
                                                       

                                                                                   

                                                                                                     
                                
                                                                           
                         
                                            
                 
                                                                                       


           







                                                                                                                



                                                                                                                
                                    
                     
           























































                                                                                                                 


           


                                                                             
                                                                            




                                                                                                                     
                                                                             
                                                                                                 






                                                                                                                           
                                 




                         
                                                                    
           
                                                                                         





                                         









                                                                                               








                                                                                                           
                                                  
                               

                                                                                          

                                                                                          


                                                                                         
                                                            
                                                                              
                                                                       
                                                                                               
                                

                                                                                                 
                                                                            

                                                                                                                                   
                                                                                       
                                                                                                                  
                                                                                                                                      
                                                                                                                                  

                                                                                                                            
                                         


                                 
                                                        
                                                                              
                                
                                                                                            
                                                                    

                                                                                                       

                                                                                                                                 
                                                                                                      

                                                                                                                       
                                 




                         


                                                                                                                
                                   




                                                                                                            



                                                                                       

                 

                                                                                  


                                                                                                           
 

                                                                                                          
                                                                                                       
                                                                               
                                                                     

                                                                                                          



                                                                                                               
                                 






                                                                                                                        




                                                                                                               



                                                                                                                         
                                                                                           

                                                                                                                           
                                                                                             


                         
                                                                                  



                                                                                                                         
                                                                                     


                                                                                                   
                                                                                         



                                                                                                                         
                                                                                    



                                                                                                   





































































































                                                                                                                         


                                                                             
 



                                            











































                                                                                                                         




















                                                                                                               
                                                                                                        
           
                                                                             
           











                                                                               

                 






                                                                            
                 
         
 
/*******************************************************************************
 * Copyright (c) 2006, 2012 Obeo.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 * 
 * Contributors:
 *     Obeo - initial API and implementation
 *******************************************************************************/
package org.eclipse.emf.compare.diff.merge;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.eclipse.emf.common.notify.Adapter;
import org.eclipse.emf.common.notify.impl.AdapterImpl;
import org.eclipse.emf.common.util.TreeIterator;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.compare.diff.internal.DiffReferenceUtil;
import org.eclipse.emf.compare.diff.metamodel.DiffModel;
import org.eclipse.emf.compare.diff.metamodel.DiffResourceSet;
import org.eclipse.emf.compare.diff.metamodel.ResourceDependencyChange;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.EcorePackage;
import org.eclipse.emf.ecore.InternalEObject;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.emf.ecore.util.FeatureMap;
import org.eclipse.emf.ecore.util.InternalEList;
import org.eclipse.emf.ecore.xmi.XMIResource;

/**
 * Defines here a new copier to alter the way references are copied when an EObject is. References
 * corresponding to unmatched object need specific handling.
 * <p>
 * <b>This map's content should be cleared when all differences of {@link #diffModel} are merged.</b>
 * </p>
 * 
 * @author <a href="mailto:laurent.goubet@obeo.fr">Laurent Goubet</a>
 * @since 0.8
 */
public class EMFCompareEObjectCopier extends org.eclipse.emf.ecore.util.EcoreUtil.Copier {
	/** This class' serial version UID. */
	private static final long serialVersionUID = 2701874812215174395L;

	/** If there are any ResourceDependencyChanges in the diffModel, they'll be cached in this. */
	private final List<ResourceDependencyChange> dependencyChanges = new ArrayList<ResourceDependencyChange>();

	/* (non-javadoc) defined transient since not serializable. */
	/**
	 * The DiffModel on which differences this copier will be used. Note that this could be <code>null</code>
	 * if {@link #diffResourceSet} is not.
	 */
	private final transient DiffModel diffModel;

	/* (non-javadoc) defined transient since not serializable. */
	/** The Diff Resource Set on which differences this copier will be used. */
	private final transient DiffResourceSet diffResourceSet;

	/**
	 * Creates a Copier given the DiffModel it will be used for.
	 * <p>
	 * <b>Note</b> that this should never be used if the given <code>diff</code> is contained in a
	 * DiffResourceSet.
	 * </p>
	 * 
	 * @param diff
	 *            The DiffModel which elements will be merged using this copier.
	 */
	public EMFCompareEObjectCopier(DiffModel diff) {
		super();
		diffModel = diff;
		if (diffModel.eContainer() instanceof DiffResourceSet) {
			diffResourceSet = (DiffResourceSet)diffModel.eContainer();
			for (final EObject child : diffModel.eContainer().eContents()) {
				if (child instanceof ResourceDependencyChange) {
					dependencyChanges.add((ResourceDependencyChange)child);
				}
			}
		} else {
			diffResourceSet = null;
		}
	}

	/**
	 * Creates a Copier given the DiffResourceSet it will be used for.
	 * 
	 * @param diff
	 *            The Diff Resource Set which elements will be merged using this copier.
	 * @since 1.3
	 */
	public EMFCompareEObjectCopier(DiffResourceSet diff) {
		super();
		diffModel = null;
		diffResourceSet = diff;
		for (final EObject child : diffResourceSet.eContents()) {
			if (child instanceof ResourceDependencyChange) {
				dependencyChanges.add((ResourceDependencyChange)child);
			}
		}
	}

	/**
	 * Adds the given <code>newValue</code> to the given <code>list</code> at the given <code>index</code>. If
	 * the value cannot be inserted at said index, we'll attach an adapter to it in order to remember its
	 * "expected" position. The list will be reordered later on.
	 * 
	 * @param collection
	 *            The collection to which we are to add a value.
	 * @param newValue
	 *            The value that we need to add to that collection.
	 * @param index
	 *            Index at which to insert the value.
	 */
	private static void addAtIndex(Collection<EObject> collection, EObject newValue, int index) {
		if (collection instanceof InternalEList<?>) {
			final InternalEList<? super EObject> internalEList = (InternalEList<? super EObject>)collection;
			final int listSize = internalEList.size();
			if (index > -1 && index < listSize) {
				internalEList.addUnique(index, newValue);
			} else {
				internalEList.addUnique(newValue);
			}
			attachRealPositionEAdapter(newValue, index);
			reorderList(internalEList);
		} else if (collection instanceof List<?>) {
			final List<? super EObject> list = (List<? super EObject>)collection;
			final int listSize = list.size();
			if (index > -1 && index < listSize) {
				list.add(index, newValue);
			} else {
				list.add(newValue);
			}
			attachRealPositionEAdapter(newValue, index);
			reorderList(list);
		} else {
			collection.add(newValue);
		}
	}

	/**
	 * If we could not merge a given object at its expected position in a list, we'll attach an Adapter to it
	 * in order to "remember" that "expected" position. That will allow us to reorder the list later on if
	 * need be.
	 * 
	 * @param object
	 *            The object on which to attach an Adapter.
	 * @param expectedPosition
	 *            The expected position of <code>object</code> in its list.
	 */
	private static void attachRealPositionEAdapter(Object object, int expectedPosition) {
		if (object instanceof EObject) {
			((EObject)object).eAdapters().add(new PostionAdapter(expectedPosition));
		}
	}

	/**
	 * Initially copied from {@link org.eclipse.emf.ecore.resource.impl.ResourceImpl#getEObject(List<String>)}
	 * .
	 * 
	 * @param container
	 *            The container in which we need to find an EObject.
	 * @param uriFragmentPath
	 *            Segments of the URI we need an EObject for.
	 * @return The EObject contained in <code>container</code> that lies at <code>uriFragmentPath</code>.
	 * @since 1.3
	 */
	private static EObject getEObject(EObject container, List<String> uriFragmentPath) {
		final int size = uriFragmentPath.size();
		EObject eObject = container;
		for (int i = 1; i < size && eObject != null; ++i) {
			eObject = ((InternalEObject)eObject).eObjectForURIFragmentSegment(uriFragmentPath.get(i));
		}

		return eObject;
	}

	/**
	 * Initially copied from {@link org.eclipse.emf.ecore.resource.impl.ResourceImpl#getEObject(String)}.
	 * 
	 * @param container
	 *            The container in which we need to find an EObject.
	 * @param fragment
	 *            The fragment we need an EObject for.
	 * @return The EObject contained in <code>container</code> that lies at <code>uriFragment</code>.
	 * @since 1.3
	 */
	private static EObject getEObject(EObject container, String fragment) {
		String uriFragment = fragment;
		final int length = uriFragment.length();
		if (length > 0) {
			if (uriFragment.charAt(0) == '/') {
				final ArrayList<String> uriFragmentPath = new ArrayList<String>(4);
				int start = 1;
				for (int i = 1; i < length; ++i) {
					if (uriFragment.charAt(i) == '/') {
						if (start == i) {
							uriFragmentPath.add(""); //$NON-NLS-1$							
						} else {
							uriFragmentPath.add(uriFragment.substring(start, i));
						}
						start = i + 1;
					}
				}
				uriFragmentPath.add(uriFragment.substring(start));
				return getEObject(container, uriFragmentPath);
			} else if (uriFragment.charAt(length - 1) == '?') {
				final int index = uriFragment.lastIndexOf('?', length - 2);
				if (index > 0) {
					uriFragment = uriFragment.substring(0, index);
				}
			}
		}

		return getEObjectByID(container, uriFragment);
	}

	/**
	 * Initially copied from {@link org.eclipse.emf.ecore.resource.impl.ResourceImpl#getEObjectByID(String)}.
	 * 
	 * @param container
	 *            The container in which we need to find an EObject.
	 * @param id
	 *            The id we need an EObject for.
	 * @return The EObject contained in <code>container</code> that corresponds to ID <code>id</code>.
	 * @since 1.3
	 */
	private static EObject getEObjectByID(EObject container, String id) {
		EObject result = null;

		final TreeIterator<EObject> iterator = EcoreUtil.getAllProperContents(container, false);
		while (result == null && iterator.hasNext()) {
			final EObject eObject = iterator.next();
			final String eObjectId = EcoreUtil.getID(eObject);
			if (eObjectId != null) {
				if (eObjectId.equals(id)) {
					result = eObject;
				}
			}
		}

		return result;
	}

	/**
	 * Moves the Object located at index <code>currentIndex</code> from list <code>list</code> to index
	 * <code>expectedIndex</code>.
	 * 
	 * @param list
	 *            The list from which we need an object moved.
	 * @param currentIndex
	 *            The current index of the Object that is to be moved.
	 * @param expectedIndex
	 *            The index at which to move the Object.
	 * @param <T>
	 *            type of the list's elements.
	 */
	private static <T> void movetoIndex(List<T> list, int currentIndex, int expectedIndex) {
		final int size = list.size();
		if (size <= 1 || currentIndex < 0 || currentIndex >= size) {
			return;
		}

		if (expectedIndex != -1 && expectedIndex != currentIndex && expectedIndex <= size - 1) {
			if (list instanceof InternalEList<?>) {
				((InternalEList<T>)list).move(expectedIndex, currentIndex);
			} else {
				list.add(expectedIndex, list.remove(currentIndex));
			}
		}
	}

	/**
	 * Reorders the given list if it contains EObjects associated with a PositionAdapter which are not located
	 * at their expected positions.
	 * 
	 * @param list
	 *            The list that is to be reordered.
	 * @param <T>
	 *            type of the list's elements.
	 */
	private static <T> void reorderList(List<T> list) {
		final int size = list.size();
		if (size <= 1) {
			return;
		}

		final List<?> copy = Collections.unmodifiableList(list);
		for (int i = 0; i < size; i++) {
			final Object current = copy.get(i);
			if (current instanceof EObject) {
				int expectedIndex = -1;
				final Iterator<Adapter> adapters = ((EObject)current).eAdapters().iterator();
				while (expectedIndex == -1 && adapters.hasNext()) {
					final Adapter adapter = adapters.next();
					if (adapter instanceof PostionAdapter) {
						expectedIndex = ((PostionAdapter)adapter).getExpectedIndex();
					}
				}
				if (expectedIndex != -1 && expectedIndex != i && expectedIndex <= size - 1) {
					if (list instanceof InternalEList<?>) {
						((InternalEList<T>)list).move(expectedIndex, i);
					} else {
						list.add(expectedIndex, list.remove(i));
					}
				}
			}
		}
	}

	/**
	 * {@inheritDoc}
	 * 
	 * @see org.eclipse.emf.ecore.util.EcoreUtil$Copier#copyReferences()
	 */
	@Override
	public void copyReferences() {
		final Set<Map.Entry<EObject, EObject>> entrySetCopy = new HashSet<Map.Entry<EObject, EObject>>(
				entrySet());
		for (final Map.Entry<EObject, EObject> entry : entrySetCopy) {
			final EObject eObject = entry.getKey();
			final EObject copyEObject = entry.getValue();
			for (EStructuralFeature feature : DiffReferenceUtil.getCopiableReferences(eObject)) {
				if (DiffReferenceUtil.isSimpleReference(feature)) {
					copyReference((EReference)feature, eObject, copyEObject);
				} else if (DiffReferenceUtil.isFeatureMap(feature)) {
					copyFeatureMap(eObject, feature);
				}
			}
		}
	}

	/**
	 * This will copy the given <tt>value</tt> to the reference <tt>targetReference</tt> of <tt>target</tt>.
	 * 
	 * @param targetReference
	 *            The reference to add a value to.
	 * @param target
	 *            The object to copy to.
	 * @param value
	 *            The value that is to be copied.
	 * @return The copied value.
	 * @deprecated Use {@link #copyReferenceValue(EReference, EObject, EObject, int)} instead
	 */
	@Deprecated
	public EObject copyReferenceValue(EReference targetReference, EObject target, EObject value) {
		return copyReferenceValue(targetReference, target, value, -1);
	}

	/**
	 * This will copy the given <tt>value</tt> to the reference <tt>targetReference</tt> of <tt>target</tt>.
	 * 
	 * @param targetReference
	 *            The reference to add a value to.
	 * @param target
	 *            The object to copy to.
	 * @param value
	 *            The value that is to be copied.
	 * @param matchedValue
	 *            Matched value of <tt>value</tt> if it is known. Will behave like
	 *            {@link #copyReferenceValue(EReference, EObject, EObject)} if <code>null</code>.
	 * @return The copied value.
	 * @deprecated use {@link #copyReferenceValue(EReference, EObject, EObject, int)} instead
	 */
	@Deprecated
	public EObject copyReferenceValue(EReference targetReference, EObject target, EObject value,
			EObject matchedValue) {
		return copyReferenceValue(targetReference, target, value, matchedValue, -1);
	}

	/**
	 * This will copy the given <tt>value</tt> to the reference <tt>targetReference</tt> of <tt>target</tt>.
	 * 
	 * @param targetReference
	 *            The reference to add a value to.
	 * @param target
	 *            The object to copy to.
	 * @param value
	 *            The value that is to be copied.
	 * @param matchedValue
	 *            Matched value of <tt>value</tt> if it is known. Will behave like
	 *            {@link #copyReferenceValue(EReference, EObject, EObject)} if <code>null</code>.
	 * @param index
	 *            an optional index in case the target is a List (-1 is a good default, the value will be
	 *            appended to the list)
	 * @return The copied value.
	 */
	@SuppressWarnings("unchecked")
	public EObject copyReferenceValue(EReference targetReference, EObject target, EObject value,
			EObject matchedValue, int index) {
		EObject actualValue = value;
		if (value == null && matchedValue != null) {
			handleLinkedResourceDependencyChange(matchedValue);
			actualValue = get(matchedValue);
		}
		if (matchedValue != null) {
			put(actualValue, matchedValue);

			final Object referenceValue = target.eGet(targetReference);
			if (referenceValue instanceof Collection<?>) {
				addAtIndex((Collection<EObject>)referenceValue, matchedValue, index);
			} else {
				target.eSet(targetReference, matchedValue);
			}
			return matchedValue;
		}
		return copyReferenceValue(targetReference, target, actualValue, index);
	}

	/**
	 * This will copy the given <tt>value</tt> to the reference <tt>targetReference</tt> of <tt>target</tt>.
	 * 
	 * @param targetReference
	 *            The reference to add a value to.
	 * @param target
	 *            The object to copy to.
	 * @param value
	 *            The value that is to be copied.
	 * @param index
	 *            An optional index in case the target is a List. -1 can be used to either append to the end
	 *            of the list, or copy the value of a single-valued reference (
	 *            <code>targetReference.isMany() == false</code>).
	 * @return The copied value.
	 * @since 1.3
	 */
	@SuppressWarnings("unchecked")
	public EObject copyReferenceValue(EReference targetReference, EObject target, EObject value, int index) {
		final EObject copy;
		final EObject targetValue = get(value);
		if (targetValue != null) {
			copy = targetValue;
		} else {
			if (value.eResource() == null || value.eResource().getURI().isPlatformPlugin()) {
				// We can't copy that object
				copy = value;
			} else {
				copy = copy(value);
			}
		}

		final Object referenceValue = target.eGet(targetReference);
		if (referenceValue instanceof List && targetReference.isMany()) {
			if (copy.eIsProxy() && copy instanceof InternalEObject) {
				// only add if the element is not already there.
				final URI proxURI = ((InternalEObject)copy).eProxyURI();
				boolean found = false;
				final Iterator<EObject> it = ((List<EObject>)referenceValue).iterator();
				while (!found && it.hasNext()) {
					final EObject obj = it.next();
					if (obj instanceof InternalEObject) {
						found = proxURI.equals(((InternalEObject)obj).eProxyURI());
					}
				}
				if (!found) {
					final List<EObject> targetList = (List<EObject>)referenceValue;
					addAtIndex(targetList, copy, index);
				}
			} else {
				final List<EObject> targetList = (List<EObject>)referenceValue;
				final int currentIndex = targetList.indexOf(copy);
				if (currentIndex == -1) {
					addAtIndex(targetList, copy, index);
				} else {
					// The order could be wrong in case of eOpposites
					movetoIndex(targetList, currentIndex, index);
				}
			}
		} else {
			if (copy.eIsProxy() && copy instanceof InternalEObject) {
				// only change value if the URI changes
				final URI proxURI = ((InternalEObject)copy).eProxyURI();
				if (referenceValue instanceof InternalEObject) {
					if (!proxURI.equals(((InternalEObject)referenceValue).eProxyURI())) {
						target.eSet(targetReference, copy);
					}
				}
			} else {
				target.eSet(targetReference, copy);
			}
		}
		return copy;
	}

	/**
	 * Ensures the original and copied objects all share the same XMI ID.
	 */
	public void copyXMIIDs() {
		for (final Map.Entry<EObject, EObject> entry : entrySet()) {
			final EObject original = entry.getKey();
			final EObject copy = entry.getValue();
			if (original.eResource() instanceof XMIResource && copy.eResource() instanceof XMIResource) {
				final XMIResource originResource = (XMIResource)original.eResource();
				final XMIResource copyResource = (XMIResource)copy.eResource();
				if (originResource.getID(original) != null) {
					copyResource.setID(copy, originResource.getID(original));
					final TreeIterator<EObject> originalIterator = original.eAllContents();
					final TreeIterator<EObject> copyIterator = copy.eAllContents();
					while (originalIterator.hasNext()) {
						final EObject nextOriginalChild = originalIterator.next();
						final EObject nextCopyChild = copyIterator.next();
						copyResource.setID(nextCopyChild, originResource.getID(nextOriginalChild));
					}
				}
			}
		}
	}

	/**
	 * Returns the DiffModel associated with this copier if any.
	 * 
	 * @return The DiffModel associated with this copier. Could be <code>null</code>.
	 */
	public DiffModel getDiffModel() {
		return diffModel;
	}

	/**
	 * Returns the DiffResourceSet associated with this copier if any.
	 * 
	 * @return The DiffResourceSet associated with this copier. Could be <code>null</code>.
	 * @since 1.3
	 */
	public DiffResourceSet getDiffResourceSet() {
		return diffResourceSet;
	}

	/**
	 * {@inheritDoc}
	 * 
	 * @see org.eclipse.emf.ecore.util.EcoreUtil$Copier#copyReference(org.eclipse.emf.ecore.EReference,
	 *      org.eclipse.emf.ecore.EObject, org.eclipse.emf.ecore.EObject)
	 */
	@SuppressWarnings("unchecked")
	@Override
	protected void copyReference(EReference eReference, EObject eObject, EObject copyEObject) {
		// No use trying to copy the reference if it isn't set in the origin
		if (!eObject.eIsSet(eReference)) {
			return;
		}
		final Object referencedEObject = eObject.eGet(eReference, resolveProxies);
		if (eReference == EcorePackage.eINSTANCE.getEPackage_EFactoryInstance()) {
			// Let the super do its work.
			super.copyReference(eReference, eObject, copyEObject);
		} else if (eReference.isMany()) {
			final List<?> referencedObjectsList = (List<?>)referencedEObject;
			if (referencedObjectsList == null) {
				copyEObject.eSet(getTarget(eReference), null);
			} else if (referencedObjectsList.size() == 0) {
				copyEObject.eSet(getTarget(eReference), referencedObjectsList);
			} else {
				for (final Object referencedEObj : referencedObjectsList) {
					final Object copyReferencedEObject = get(referencedEObj);
					if (copyReferencedEObject != null) {
						// The referenced object has been copied via this Copier
						((List<Object>)copyEObject.eGet(getTarget(eReference))).add(copyReferencedEObject);
					} else if (referencedEObj instanceof EObject) {
						// referenced object lies in another resource, simply reference it
						final Object copyReferencedObject = findReferencedObjectCopy((EObject)referencedEObj);
						((List<Object>)copyEObject.eGet(getTarget(eReference))).add(copyReferencedObject);
					} else {
						((List<Object>)copyEObject.eGet(getTarget(eReference))).add(referencedEObj);
					}
				}
			}
		} else {
			if (referencedEObject == null) {
				copyEObject.eSet(getTarget(eReference), null);
			} else {
				final Object copyReferencedEObject = get(referencedEObject);
				if (copyReferencedEObject != null) {
					// The referenced object has been copied via this Copier
					copyEObject.eSet(getTarget(eReference), copyReferencedEObject);
				} else if (referencedEObject instanceof EObject) {
					final Object copyReferencedObject = findReferencedObjectCopy((EObject)referencedEObject);
					copyEObject.eSet(getTarget(eReference), copyReferencedObject);
				} else {
					((List<Object>)copyEObject.eGet(getTarget(eReference))).add(referencedEObject);
				}
			}
		}
	}

	/**
	 * We couldn't find a copy of <em>referencedObject</em>. We still need to find its matched object in the
	 * target resource in order not to simply reference the "old" resource from a copied object.
	 * 
	 * @param referencedEObject
	 *            object referenced from <em>eObject</em> that needs to be copied or found in the target
	 *            resource.
	 * @return Copy of the referenced object, located in the target resource if we could find it.
	 * @since 1.3
	 */
	protected Object findReferencedObjectCopy(EObject referencedEObject) {
		Object copyReferencedObject = referencedEObject;
		if (referencedEObject.eResource() == null) {
			return findReferencedObjectCopyNullResource(referencedEObject);
		}

		// Is the referencedObject in either left or right?
		final Resource referencedResource = referencedEObject.eResource();
		final String uriFragment = referencedEObject.eResource().getURIFragment(referencedEObject);
		Resource leftResource = null;
		Resource rightResource = null;

		if (diffResourceSet != null) {
			final Iterator<DiffModel> diffModels = diffResourceSet.getDiffModels().iterator();
			while (diffModels.hasNext() && leftResource == null && rightResource == null) {
				final DiffModel aDiffModel = diffModels.next();
				DiffModel referencedDiffModel = null;
				if (!aDiffModel.getLeftRoots().isEmpty()
						&& aDiffModel.getLeftRoots().get(0).eResource() != null) {
					final Resource resource = aDiffModel.getLeftRoots().get(0).eResource();
					if (referencedEObject.eResource() == resource) {
						referencedDiffModel = aDiffModel;
					}
				}
				if (referencedDiffModel == null) {
					if (!aDiffModel.getRightRoots().isEmpty()
							&& aDiffModel.getRightRoots().get(0).eResource() != null) {
						final Resource resource = aDiffModel.getRightRoots().get(0).eResource();
						if (referencedEObject.eResource() == resource) {
							referencedDiffModel = aDiffModel;
						}
					}
				}
				if (referencedDiffModel != null) {
					leftResource = referencedDiffModel.getLeftRoots().get(0).eResource();
					rightResource = referencedDiffModel.getRightRoots().get(0).eResource();
				}
			}
		} else if (diffModel != null) {
			if (!diffModel.getLeftRoots().isEmpty() && diffModel.getLeftRoots().get(0).eResource() != null) {
				leftResource = diffModel.getLeftRoots().get(0).eResource();
			}
			if (!diffModel.getRightRoots().isEmpty() && diffModel.getRightRoots().get(0).eResource() != null) {
				rightResource = diffModel.getRightRoots().get(0).eResource();
			}
		}

		if (referencedResource == leftResource && rightResource != null) {
			/*
			 * FIXME we should be using the MatchModel, but can't access it. let's hope the referenced object
			 * has already been copied
			 */
			copyReferencedObject = rightResource.getEObject(uriFragment);
			if (copyReferencedObject == null) {
				// FIXME can we find the referenced object without the match model?
			}
		} else if (referencedResource == rightResource && leftResource != null) {
			/*
			 * FIXME we should be using the MatchModel, but can't access it. let's hope the referenced object
			 * has already been copied
			 */
			copyReferencedObject = leftResource.getEObject(uriFragment);
			if (copyReferencedObject == null) {
				// FIXME can we find the referenced object without the match model?
			}
		} else {
			// Reference lies in another resource. Simply return it as is.
		}

		return copyReferencedObject;
	}

	/**
	 * We couldn't find a copy of <em>referencedObject</em>. We still need to find its matched object in the
	 * target resource in order not to simply reference the "old" resource from a copied object.
	 * <p>
	 * This will only be called after we've made sure that the referenced Object is not attached to a
	 * resource. We thus can only look within its containment tree.
	 * </p>
	 * <p>
	 * Take good not that this treatment will be extremely costly and should be avoided whenever possible.
	 * </p>
	 * 
	 * @param referencedObject
	 *            object referenced from <em>eObject</em> that needs to be copied or found in the target
	 *            containment tree.
	 * @return Copy of the referenced object, located in the target containment tree if we could find it.
	 * @since 1.3
	 */
	protected Object findReferencedObjectCopyNullResource(EObject referencedObject) {
		Object copyReferencedObject = referencedObject;

		final EObject rootContainer = EcoreUtil.getRootContainer(referencedObject);

		EObject leftRoot = null;
		EObject rightRoot = null;

		if (diffResourceSet != null) {
			final Iterator<DiffModel> diffModels = diffResourceSet.getDiffModels().iterator();
			while (diffModels.hasNext() && leftRoot == null && rightRoot == null) {
				final DiffModel aDiffModel = diffModels.next();
				DiffModel referencedDiffModel = null;
				int rootIndex = 0;

				for (int i = 0; i < aDiffModel.getLeftRoots().size(); i++) {
					if (rootContainer == aDiffModel.getLeftRoots().get(i)) {
						referencedDiffModel = aDiffModel;
						rootIndex = i;
					}
				}
				if (referencedDiffModel == null) {
					for (int i = 0; i < aDiffModel.getRightRoots().size(); i++) {
						if (rootContainer == aDiffModel.getRightRoots().get(i)) {
							referencedDiffModel = aDiffModel;
							rootIndex = i;
						}
					}
				}
				if (referencedDiffModel != null) {
					if (referencedDiffModel.getLeftRoots().size() >= rootIndex) {
						leftRoot = referencedDiffModel.getLeftRoots().get(rootIndex);
					}
					if (referencedDiffModel.getRightRoots().size() >= rootIndex) {
						rightRoot = referencedDiffModel.getRightRoots().get(rootIndex);
					}
				}
			}
		} else if (diffModel != null) {
			int rootIndex = -1;
			for (int i = 0; i < diffModel.getLeftRoots().size(); i++) {
				if (rootContainer == diffModel.getLeftRoots().get(i)) {
					rootIndex = i;
				}
			}
			for (int i = 0; i < diffModel.getRightRoots().size(); i++) {
				if (rootContainer == diffModel.getRightRoots().get(i)) {
					rootIndex = i;
				}
			}
			if (diffModel.getLeftRoots().size() >= rootIndex) {
				leftRoot = diffModel.getLeftRoots().get(rootIndex);
			}
			if (diffModel.getRightRoots().size() >= rootIndex) {
				rightRoot = diffModel.getRightRoots().get(rootIndex);
			}
		}

		// Trims the starting '#//' out
		final String uriFragment = EcoreUtil.getURI(referencedObject).toString().substring(2);
		if (rootContainer == leftRoot && rightRoot != null) {
			/*
			 * FIXME we should be using the MatchModel, but can't access it. let's hope the referenced object
			 * has already been copied
			 */
			copyReferencedObject = getEObject(rightRoot, uriFragment);
			if (copyReferencedObject == null) {
				// FIXME can we find the referenced object without the match model?
			}
		} else if (rootContainer == rightRoot && leftRoot != null) {
			/*
			 * FIXME we should be using the MatchModel, but can't access it. let's hope the referenced object
			 * has already been copied
			 */
			copyReferencedObject = getEObject(leftRoot, uriFragment);
			if (copyReferencedObject == null) {
				// FIXME can we find the referenced object without the match model?
			}
		} else {
			// Reference lies in another resource. Simply copy it
			copyReferencedObject = referencedObject;
		}

		return copyReferencedObject;
	}

	/**
	 * Copies the feature as a FeatureMap.
	 * 
	 * @param eObject
	 *            The EObject from which the feature is copied
	 * @param eStructuralFeature
	 *            The feature which needs to be copied.
	 */
	private void copyFeatureMap(EObject eObject, EStructuralFeature eStructuralFeature) {
		final FeatureMap featureMap = (FeatureMap)eObject.eGet(eStructuralFeature);
		final FeatureMap copyFeatureMap = (FeatureMap)get(eObject).eGet(getTarget(eStructuralFeature));
		int copyFeatureMapSize = copyFeatureMap.size();
		for (int k = 0; k < featureMap.size(); ++k) {
			final EStructuralFeature feature = featureMap.getEStructuralFeature(k);
			if (feature instanceof EReference) {
				final Object referencedEObject = featureMap.getValue(k);
				Object copyReferencedEObject = get(referencedEObject);
				if (copyReferencedEObject == null && referencedEObject != null) {
					final EReference reference = (EReference)feature;
					if (!useOriginalReferences || reference.isContainment()
							|| reference.getEOpposite() != null) {
						continue;
					}
					copyReferencedEObject = referencedEObject;
				}
				// If we can't add it, it must already be in the list so find it and move it
				// to the end.
				//
				if (!copyFeatureMap.add(feature, copyReferencedEObject)) {
					for (int l = 0; l < copyFeatureMapSize; ++l) {
						if (copyFeatureMap.getEStructuralFeature(l) == feature
								&& copyFeatureMap.getValue(l) == copyReferencedEObject) {
							copyFeatureMap.move(copyFeatureMap.size() - 1, l);
							--copyFeatureMapSize;
							break;
						}
					}
				}
			} else {
				copyFeatureMap.add(featureMap.get(k));
			}
		}
	}

	/**
	 * This will be called when merging reference changes in order to remove linked dependency changes.
	 * 
	 * @param element
	 *            The element that is being merged.
	 */
	private void handleLinkedResourceDependencyChange(EObject element) {
		for (final ResourceDependencyChange dependencyChange : new ArrayList<ResourceDependencyChange>(
				dependencyChanges)) {
			final Resource resource = dependencyChange.getRoots().get(0).eResource();
			if (resource == element.eResource() && dependencyChange.eContainer() != null) {
				// There are no explicit mergers for resource addition/removal.
				EcoreUtil.remove(dependencyChange);
				dependencyChanges.remove(dependencyChange);
				// map the element to itself : we wish a direct link to the same resource.
				put(element, element);
				break;
			}
		}
	}

	/**
	 * This adapter will be used to remember the accurate position of an EObject in its target list.
	 * 
	 * @author <a href="mailto:laurent.goubet@obeo.fr">Laurent Goubet</a>
	 */
	private static class PostionAdapter extends AdapterImpl {
		/** The index at which we expect to find this object. */
		private int expectedIndex;

		/**
		 * Creates our adapter.
		 * 
		 * @param index
		 *            The index at which we expect to find this object.
		 */
		public PostionAdapter(int index) {
			this.expectedIndex = index;
		}

		/**
		 * Returns the index at which we expect to find this object.
		 * 
		 * @return The index at which we expect to find this object.
		 */
		public int getExpectedIndex() {
			return expectedIndex;
		}
	}
}

Back to the top