blob: 22d91e0cd6f6170936283600e3cdca32bc82e9a1 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2003, 2005 IBM Corporation and others.
* 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:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.wst.common.internal.emf.utilities;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import org.eclipse.emf.common.notify.Adapter;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EAttribute;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EFactory;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EPackage;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.ETypedElement;
import org.eclipse.emf.ecore.EcorePackage;
import org.eclipse.emf.ecore.resource.Resource;
/**
* Insert the type's description here. Creation date: (12/13/2000 9:10:55 PM)
*
* @author: Administrator
*/
public class EtoolsCopyUtility {
protected static final String REFENUMLITERAL_TYPE_NAME = "EEnumLiteral"; //$NON-NLS-1$
private final EcorePackage pkg = EcorePackage.eINSTANCE;
private final ETypedElement METAENAME = pkg.getENamedElement_Name();
protected HashMap copiedObjects;
protected List deferredReferenceCopies;
protected boolean preserveIds = false;
protected boolean copyAdapters = false;
protected HashMap copiedAdapters;
protected class DeferredSingleReferenceCopyAction extends DeferredReferenceUtilityAction {
public DeferredSingleReferenceCopyAction(EReference aReference, Object aValue, String aSuffix, EObject aCopyContainer) {
super(aReference, aValue, aSuffix, aCopyContainer);
}
public void performAction() {
EObject value = (EObject) getReferenceValue();
getCopyContainer().eSet(getReference(), getCopyIfFound(value));
}
}
protected class DeferredManyReferenceCopyAction extends DeferredReferenceUtilityAction {
public DeferredManyReferenceCopyAction(EReference aReference, List aValue, String aSuffix, EObject aCopyContainer) {
super(aReference, aValue, aSuffix, aCopyContainer);
}
public void performAction() {
List copyList = (List) getCopyContainer().eGet(getReference());
Iterator it = ((List) getReferenceValue()).iterator();
EObject next;
while (it.hasNext()) {
next = (EObject) it.next();
copyList.add(getCopyIfFound(next));
}
}
}
/**
* Insert the method's description here. Creation date: (12/13/2000 9:14:26 PM)
*
* @param aRefObject
* org.eclipse.emf.ecore.EObject
*/
public EtoolsCopyUtility() {
}
/**
* Create a <code>DeferredManyReferenceCopyAction</code> and add it to the list of deferred
* copy actions.
*/
protected void addDeferredManyReferenceCopy(EReference reference, List aValue, String idSuffix, EObject aCopyContainer) {
getDeferredReferenceCopies().add(new DeferredManyReferenceCopyAction(reference, aValue, idSuffix, aCopyContainer));
}
/**
* Create a <code>DeferredSingleReferenceCopyAction</code> and add it to the list of deferred
* copy actions.
*/
protected void addDeferredSingleReferenceCopy(EReference reference, EObject aValue, String idSuffix, EObject aCopyContainer) {
getDeferredReferenceCopies().add(new DeferredSingleReferenceCopyAction(reference, aValue, idSuffix, aCopyContainer));
}
/**
* Check for an already copied object first.
*/
protected EObject containmentCopy(EObject anObject, String idSuffix) {
EObject copied = getCopy(anObject);
if (copied == null)
copied = primCopy(anObject, idSuffix);
return copied;
}
/**
* Check for an already copied object first.
*/
protected EObject containmentCopyObject(EObject anObject, String idSuffix) {
EObject copied = getCopy(anObject);
if (copied == null)
copied = primCopyObject(anObject, idSuffix);
return copied;
}
protected Resource containmentCopy(Resource aResource, String newUri) {
/* copied resources are never cached */
return primCopy(aResource, newUri);
}
/**
* Copy all Resources and RefObjects within <code>aGroup</code> and add them to
* <code>aGroup</code>. Non composite references will be deferred until all objects are
* copied from <code>aGroup</code>.
*
* Copy Resources first and then copy RefObjects.
*/
public void copy(CopyGroup aGroup) {
if (aGroup != null) {
EtoolsCopySession session = new EtoolsCopySession(this);
session.setPreserveIds(aGroup.getPreserveIds());
session.copy(aGroup);
session.flush();
}
}
public EObject copy(EObject aRefObject) {
return copy(aRefObject, null);
}
/**
* This method should be used if you are only going to copy <code>aRefObject</code> in this
* copy execution.
*/
public EObject copy(EObject aRefObject, String idSuffix) {
EtoolsCopySession session = new EtoolsCopySession(this);
EObject copied = session.copy(aRefObject, idSuffix);
session.flush();
return copied;
}
/**
* This method should be used if you are only going to copy <code>aRefObject</code> in this
* copy execution. This method only copies <code>aRefObject</code> with its properties, not
* references.
*/
public EObject copyObject(EObject aRefObject, String idSuffix) {
EtoolsCopySession session = new EtoolsCopySession(this);
EObject copied = session.copyObject(aRefObject, idSuffix);
session.flush();
return copied;
}
/**
* This method should be used if you are only going to copy <code>aResource</code> in this
* copy execution. The copied Resource will have a URI equal to <code>newUri</code>.
*/
public Resource copy(Resource aResource, String newUri) {
EtoolsCopySession session = new EtoolsCopySession(this);
Resource copied = session.copy(aResource, newUri);
session.flush();
return copied;
}
/**
* If an attribute is set and its value is not <code>null</code>, then perform copy
* <code>attribute</code> value from <code>aRefObject</code> to <code>copyRef</code>.
* Null is a valid value if the attribute is set.
*/
protected void copyAttribute(EAttribute attribute, EObject aRefObject, String idSuffix, EObject copyRef) {
if (!attribute.isChangeable())
return; //ignore
if (attribute.isMany()) {
List value = (List) aRefObject.eGet(attribute);
if (value != null)
copyManyAttribute(attribute, value, aRefObject, idSuffix, copyRef);
} else if (aRefObject.eIsSet(attribute)) {
Object value = aRefObject.eGet(attribute);
if (value == null)
copyRef.eSet(attribute, value);
else
copySingleAttribute(attribute, value, aRefObject, idSuffix, copyRef);
} else if (attribute == METAENAME) {
//set name to the ID (this is computed as a default), only get here if isSetName is
// false.
copyRef.eSet(attribute, aRefObject.eGet(attribute));
}
}
/**
* Iterate over the attributes of the receiver and copy each attribute.
*/
protected void copyCurrentAttributes(EObject aRefObject, String idSuffix, EObject copyRef) {
List attributes = aRefObject.eClass().getEAllAttributes();
if (attributes != null) {
Iterator it = attributes.iterator();
EAttribute ra;
while (it.hasNext()) {
ra = (EAttribute) it.next();
copyAttribute(ra, aRefObject, idSuffix, copyRef);
}
}
}
/**
* This method will iterate over the references of the receiver. If a reference's value is not
* <code>null</code>, then a series of tests are done before setting the value with the
* copied object, <code>copyRef</code>.
*
* Tests: 1. Do nothing if the reference equals the metaEContainer or metaEContains references.
*/
protected void copyCurrentReferences(EObject aRefObject, String idSuffix, EObject copyRef) {
List references = aRefObject.eClass().getEAllReferences();
if (references != null) {
Iterator it = references.iterator();
EReference rr;
while (it.hasNext()) {
rr = (EReference) it.next();
if (shouldCopyReference(rr))
copyReference(rr, aRefObject, idSuffix, copyRef);
}
}
}
/**
* Iterate over <code>anExtent</code> and copy each element to <code>copyExtent</code>.
*/
protected void copyExtent(EList anExtent, EList copyExtent) {
Iterator it = anExtent.iterator();
EObject refObject;
while (it.hasNext()) {
refObject = (EObject) it.next();
copyExtent.add(containmentCopy(refObject, null));
}
}
/**
* Copy a many value attribute which is treated as a many valued reference.
*
* Tests:
*
* 1. If the type is <bold>not </bold> <code>null</code>, then set the value on
* <code>copyRef</code> without making a copy. 2. If the type is <code>null</code>, then
* obtain the list from <code>copyRef</code> and add a copy of each value from the original
* list to it.
*/
protected void copyManyAttribute(EAttribute attribute, List aValue, EObject aRefObject, String idSuffix, EObject copyRef) {
if (attribute.getEType() == null)
copyRef.eSet(attribute, aValue);
else {
List copyList = (List) copyRef.eGet(attribute);
Iterator it = aValue.iterator();
Object next;
while (it.hasNext()) {
next = it.next();
if (next instanceof EObject)
copyList.add(containmentCopy((EObject) next, idSuffix));
else
copyList.add(next);
}
}
}
/**
* This method will iterate over the references of the receiver. If a reference's value is not
* <code>null</code>, then a series of tests are done before setting the value with the
* copied object, <code>copyRef</code>.
*
* Tests: 1. If the reference is many, obtain the list from the receiving object and make a copy
* of each value if the reference is composite before adding to the list; otherwise, just add
* each value to the of the <code>copyRef</code>.
*/
protected void copyManyReference(EReference aReference, List aList, EObject aRefObject, String idSuffix, EObject copyRef) {
if (!aList.isEmpty()) {
if (aReference.isContainment()) {
List copyList = (List) copyRef.eGet(aReference);
Iterator it = aList.iterator();
EObject targetValue;
while (it.hasNext()) {
targetValue = (EObject) it.next();
copyList.add(containmentCopy(targetValue, idSuffix));
}
} else
addDeferredManyReferenceCopy(aReference, aList, idSuffix, copyRef);
}
}
/**
* This method will iterate over the references of the receiver. If a reference's value is not
* <code>null</code>, then perform the copy.
*/
protected void copyReference(EReference aReference, EObject aRefObject, String idSuffix, EObject copyRef) {
if (aReference.isMany()) {
List value = (List) aRefObject.eGet(aReference);
if (value != null)
copyManyReference(aReference, value, aRefObject, idSuffix, copyRef);
} else if (aRefObject.eIsSet(aReference)) {
Object value = aRefObject.eGet(aReference);
copySingleReference(aReference, (EObject) value, aRefObject, idSuffix, copyRef);
}
}
/**
* Copy all RefObjects from <code>aGroup</code> and add the copy back to <code>aGroup</code>.
*/
protected void copyRefObjects(CopyGroup aGroup) {
Association association;
EObject refObject;
String idSuffix;
if (aGroup.primGetRefObjects() != null) {
Iterator it = aGroup.primGetRefObjects().iterator();
while (it.hasNext()) {
association = (Association) it.next();
refObject = (EObject) association.getKey();
idSuffix = (String) association.getValue();
if (idSuffix == null)
idSuffix = aGroup.getDefaultIdSuffix();
aGroup.addCopied(containmentCopy(refObject, idSuffix));
}
}
}
/**
* Copy all Resources from <code>aGroup</code> and add the copy back to <code>aGroup</code>.
*/
protected void copyResources(CopyGroup aGroup) {
Association association;
Resource resource;
String uri;
if (aGroup.primGetResources() != null) {
Iterator it = aGroup.primGetResources().iterator();
while (it.hasNext()) {
association = (Association) it.next();
resource = (Resource) association.getKey();
uri = (String) association.getValue();
Resource copied = containmentCopy(resource, uri);
copyModificationFlag(resource, copied);
aGroup.addCopied(copied);
}
}
}
/**
* Copy a single value attribute.
*
* Tests:
*
* 1. If an attribute type is not <code>null</code> then it is an object type and it must be
* copied. Do not copy the value if the attribute is an Enumeration type. 2. If an attribute
* type is <bold>not </bold> <code>null</code> then copy the value before setting it on
* <code>copyRef</code>.
*/
protected void copySingleAttribute(EAttribute attribute, Object aValue, EObject aRefObject, String idSuffix, EObject copyRef) {
if (attribute.getEType() == null) {
copyRef.eSet(attribute, aValue);
} else {
//MOF108
// if (attribute.isObjectType())
if (attribute.getEType() instanceof EClass)
copyRef.eSet(attribute, containmentCopy((EObject) aValue, idSuffix));
else
copyRef.eSet(attribute, aValue);
}
}
/**
* This method will iterate over the references of the receiver. If a reference's value is not
* <code>null</code>, then a series of tests are done before setting the value with the
* copied object, <code>copyRef</code>.
*
* Tests: 1. If the reference is <bold>not </bold> many, make a copy of the value if the
* reference is composite before setting the value with <code>copyRef</code>; otherwise, just
* set the value as is.
*/
protected void copySingleReference(EReference aReference, EObject aValue, EObject aRefObject, String idSuffix, EObject copyRef) {
//Exceptional case; the relationship is not the container relationship
//And is not navigable in the other direction; go ahead and copy
if (aValue != aRefObject.eContainer() || aReference.getEOpposite() == null) {
if (aReference.isContainment())
copyRef.eSet(aReference, containmentCopy(aValue, idSuffix));
else
addDeferredSingleReferenceCopy(aReference, aValue, idSuffix, copyRef);
}
}
/**
* Copy all Resources and RefObjects within <code>aGroup</code> and add them to
* <code>aGroup</code>. Non composite references will be deferred until all objects are
* copied from <code>aGroup</code>.
*
* Copy Resources first and then copy RefObjects.
*/
public static void createCopy(CopyGroup aGroup) {
EtoolsCopyUtility utility = new EtoolsCopyUtility();
utility.copy(aGroup);
}
/**
* Copies attributes
*/
public static void createAttributeCopy(EObject aRefObject, EObject copyObject) {
EtoolsCopyUtility utility = new EtoolsCopyUtility();
utility.copyCurrentAttributes(aRefObject, null, copyObject);
}
/**
* Copies all set attributes and references based on containment. Thus, it will copy the entire
* containment tree. Use the idSuffix to define the suffix that will be appended to the existing
* IDs of copied objects.
*/
public static EObject createCopy(EObject aRefObject) {
return createCopy(aRefObject, null);
}
/**
* Copies all set attributes and references based on containment. Thus, it will copy the entire
* containment tree. Use the idSuffix to define the suffix that will be appended to the existing
* IDs of copied objects.
*/
public static EObject createCopy(EObject aRefObject, String idSuffix) {
EtoolsCopyUtility utility = new EtoolsCopyUtility();
return utility.copy(aRefObject, idSuffix);
}
/**
* Copy <code>aResource</code> using <code>newUri</code> for the URI.
*/
public static Resource createCopy(Resource aResource, String newUri) {
EtoolsCopyUtility utility = new EtoolsCopyUtility();
return utility.copy(aResource, newUri);
}
protected void executeDeferredCopyActions() {
if (primGetDeferredReferenceCopies() != null) {
Iterator it = primGetDeferredReferenceCopies().iterator();
DeferredReferenceUtilityAction action;
while (it.hasNext()) {
action = (DeferredReferenceUtilityAction) it.next();
action.performAction();
}
primGetDeferredReferenceCopies().clear();
}
}
/**
* Insert the method's description here. Creation date: (12/13/2000 9:17:35 PM)
*
* @return java.util.HashMap
*/
protected java.util.HashMap getCopiedObjects() {
if (copiedObjects == null)
copiedObjects = new HashMap(200);
return copiedObjects;
}
protected java.util.HashMap getCopiedAdapters() {
if (copiedAdapters == null)
copiedAdapters = new HashMap(200);
return copiedAdapters;
}
/**
* Return a cached copy.
*/
public EObject getCopy(EObject anObject) {
if (anObject == null)
return null;
return (EObject) getCopiedObjects().get(anObject);
}
/**
* Return a cached copy, if none, return the argument.
*/
public EObject getCopyIfFound(EObject anObject) {
EObject copied = getCopy(anObject);
return copied == null ? anObject : copied;
}
/**
* Insert the method's description here. Creation date: (12/16/2000 9:11:32 AM)
*
* @return java.util.List
*/
protected java.util.List getDeferredReferenceCopies() {
if (deferredReferenceCopies == null)
deferredReferenceCopies = new ArrayList(100);
return deferredReferenceCopies;
}
/**
* Return an instance of EObject that is the same type as <code>aRefObject</code>.
*/
public EObject newInstance(EObject aRefObject) {
if (aRefObject == null)
return null;
EPackage epkg = (EPackage) aRefObject.eClass().eContainer();
EFactory factory = epkg.getEFactoryInstance();
EClass refObj = aRefObject.eClass();
return factory.create(refObj);
}
/**
* Return an instance of Resource that uses the same ResourceFactory as the one used by
* <code>aResource</code>. If <code>newUri</code> is <code>null</code> then use the URI
* from <code>aResource</code>.
*/
public Resource newInstance(Resource aResource, String newUri) {
if (aResource == null)
return null;
Resource newResource;
String originalUri = aResource.getURI().toString();
newUri = newUri == null ? originalUri : newUri;
Resource.Factory factory = null;
if (aResource.getResourceSet() == null)
factory = Resource.Factory.Registry.INSTANCE.getFactory(URI.createURI(originalUri));
else
factory = aResource.getResourceSet().getResourceFactoryRegistry().getFactory(URI.createURI(originalUri));
newResource = factory.createResource(URI.createURI(newUri));
return newResource;
}
/**
* Should the id be copied in the case where no suffix is specified? Defaults to false
*/
public boolean preserveIds() {
return preserveIds;
}
/**
* Copies all set attributes and references based on containment. Thus, it will copy the entire
* containment tree. Use the idSuffix to define the suffix that will be appended to the existing
* IDs of copied objects. If an idSuffix does not exist, do not set an id on the copied object.
*/
protected EObject primCopy(EObject aRefObject, String idSuffix) {
if (aRefObject == null)
return null;
EObject copyRef = primCopyObject(aRefObject, idSuffix);
copyCurrentReferences(aRefObject, idSuffix, copyRef);
return copyRef;
}
/**
* Copies all set attributes based on containment. Thus, it will copy the entire containment
* tree. Use the idSuffix to define the suffix that will be appended to the existing IDs of
* copied objects. If an idSuffix does not exist, do not set an id on the copied object.
*/
protected EObject primCopyObject(EObject aRefObject, String idSuffix) {
if (aRefObject == null)
return null;
EObject copyRef = newInstance(aRefObject);
recordCopy(aRefObject, copyRef);
copyCurrentAttributes(aRefObject, idSuffix, copyRef);
if (isCopyAdapters())
copyAdapters(aRefObject, copyRef);
return copyRef;
}
protected void copyAdapters(EObject aRefObject, EObject copyRef) {
List adapters = aRefObject.eAdapters();
for (int i = 0; i < adapters.size(); i++) {
Adapter adapter = (Adapter) adapters.get(i);
copyAdapter(aRefObject, copyRef, adapter);
}
}
protected void copyAdapter(EObject aRefObject, EObject copyRef, Adapter adapter) {
if (!(adapter instanceof CloneablePublic))
return;
CloneablePublic copyAdapter = (CloneablePublic) getCopiedAdapters().get(adapter);
if (copyAdapter == null) {
copyAdapter = (CloneablePublic) ((CloneablePublic) adapter).clone();
getCopiedAdapters().put(adapter, copyAdapter);
}
if (copyAdapter != null)
copyRef.eAdapters().add(copyAdapter);
}
/**
* Copies all set attributes and references based on containment. Thus, it will copy the entire
* containment tree. Use the idSuffix to define the suffix that will be appended to the existing
* IDs of copied objects.
*/
protected Resource primCopy(Resource aResource, String newUri) {
if (aResource == null)
return null;
Resource copyResource = newInstance(aResource, newUri);
copyExtent(aResource.getContents(), copyResource.getContents());
return copyResource;
}
protected void copyModificationFlag(Resource aResource, Resource copied) {
if (aResource.isModified())
copied.setModified(true);
}
/**
* Insert the method's description here. Creation date: (12/16/2000 9:11:32 AM)
*
* @return java.util.List
*/
private java.util.List primGetDeferredReferenceCopies() {
return deferredReferenceCopies;
}
public void recordCopy(EObject aSource, EObject aCopy) {
getCopiedObjects().put(aSource, aCopy);
}
public void recordCopy(Adapter aSource, Adapter aCopy) {
getCopiedAdapters().put(aSource, aCopy);
}
/**
* Should the id be copied in the case where no suffix is specified?
*/
public void setPreserveIds(boolean value) {
preserveIds = value;
}
protected boolean shouldCopyReference(EReference aReference) {
return aReference.isChangeable();
}
/**
* @return
*/
public boolean isCopyAdapters() {
return copyAdapters;
}
/**
* Flag used to indicate whether adapters should be copied as well. In order for an adapter to
* be copied, it must implement the {@link CloneablePublic}interface.
*/
public void setCopyAdapters(boolean b) {
copyAdapters = b;
}
}