blob: da5e0b93fd207718826d1aaf9a91e5e2fd3e20df [file] [log] [blame]
/**
* Copyright (c) 2002-2012 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 - Initial API and implementation
*/
package org.eclipse.emf.ecore.util;
import java.io.PrintStream;
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Random;
import java.util.RandomAccess;
import java.util.Set;
import java.util.StringTokenizer;
import org.eclipse.emf.common.notify.Adapter;
import org.eclipse.emf.common.notify.AdapterFactory;
import org.eclipse.emf.common.notify.Notifier;
import org.eclipse.emf.common.util.AbstractTreeIterator;
import org.eclipse.emf.common.util.BasicDiagnostic;
import org.eclipse.emf.common.util.Diagnostic;
import org.eclipse.emf.common.util.ECollections;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.common.util.SegmentSequence;
import org.eclipse.emf.common.util.TreeIterator;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EAnnotation;
import org.eclipse.emf.ecore.EAttribute;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EClassifier;
import org.eclipse.emf.ecore.EDataType;
import org.eclipse.emf.ecore.EGenericType;
import org.eclipse.emf.ecore.EModelElement;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EOperation;
import org.eclipse.emf.ecore.EPackage;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.ETypeParameter;
import org.eclipse.emf.ecore.EcoreFactory;
import org.eclipse.emf.ecore.EcorePackage;
import org.eclipse.emf.ecore.InternalEObject;
import org.eclipse.emf.ecore.impl.EPackageImpl;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
/**
* This class contains convenient static methods for working with EMF objects.
*/
public class EcoreUtil
{
// // Suppress default constructor for noninstantiability.
// private EcoreUtil()
// {
// }
/**
* Returns the specified notifier's existing adapter of the specified type.
* @param notifier the adapted object.
* @param type the type of adapter.
* @return an adapter associated with the specified notifier or null.
*/
public static Adapter getExistingAdapter(Notifier notifier, Object type)
{
return getAdapter(notifier.eAdapters(), type);
}
/**
* Returns the specified eObject's adapter of the specified type. If none exists, create and
* add a new adapter using a registered adapter factory if one exists for the specified type.
* @param eObject the adapted object.
* @param type the type of adapter.
* @return an adapter associated with the specified eObject or null.
*/
public static Adapter getRegisteredAdapter(EObject eObject, Object type)
{
Adapter result = getExistingAdapter(eObject, type);
if (result == null)
{
Resource resource = eObject.eResource();
if (resource != null)
{
ResourceSet resourceSet = resource.getResourceSet();
if (resourceSet != null)
{
AdapterFactory factory = getAdapterFactory(resourceSet.getAdapterFactories(), type);
if (factory != null)
{
result = factory.adaptNew(eObject, type);
}
}
}
}
return result;
}
/**
* Returns the specified resource's adapter of the specified type. If none exists, create and
* add a new adapter using a registered adapter factory if one exists for the specified type.
* @param resource the adapted resource.
* @param type the type of adapter.
* @return an adapter associated with the specified eObject or null.
*/
public static Adapter getRegisteredAdapter(Resource resource, Object type)
{
Adapter result = getExistingAdapter(resource, type);
if (result == null)
{
ResourceSet resourceSet = resource.getResourceSet();
if (resourceSet != null)
{
AdapterFactory factory = getAdapterFactory(resourceSet.getAdapterFactories(), type);
if (factory != null)
{
result = factory.adaptNew(resource, type);
}
}
}
return result;
}
/**
* Returns the adapter of the specified type.
* @param adapters list of adapters to search.
* @param type the type of adapter.
* @return an adapter from the list or null.
*/
public static Adapter getAdapter(List<Adapter> adapters, Object type)
{
for (int i = 0, size = adapters.size(); i < size; ++i)
{
Adapter adapter = adapters.get(i);
if (adapter.isAdapterForType(type))
{
return adapter;
}
}
return null;
}
/**
* Returns the adapter factory for the specified adapter type.
* @param adapterFactories list of adapter factories to search.
* @param type the type of adapter.
* @return an adapter factory from the list or null.
*/
public static AdapterFactory getAdapterFactory(List<AdapterFactory> adapterFactories, Object type)
{
for (int i = 0, size = adapterFactories.size(); i < size; ++i)
{
AdapterFactory factory = adapterFactories.get(i);
if (factory.isFactoryForType(type))
{
return factory;
}
}
return null;
}
/**
* Returns the resolved object represented by proxy. Proxy chains are followed.
* If resourceSet is null, the global package registry is consulted to obtain a
* package registered against the proxy URI, less its fragment, in the same manner
* as the default resource set implementation's fall-back behaviour.
* @param proxy the proxy to be resolved.
* @param resourceSet the resource set in which to resolve.
* @return the resolved object, or the proxy if unable to resolve.
*/
public static EObject resolve(EObject proxy, ResourceSet resourceSet)
{
URI proxyURI = ((InternalEObject)proxy).eProxyURI();
if (proxyURI != null)
{
try
{
EObject resolvedObject = null;
if (resourceSet != null)
{
try
{
resolvedObject = resourceSet.getEObject(proxyURI, true);
}
catch (RuntimeException exception)
{
resolvedObject = resourceSet.getEObject(proxyURI, false);
}
}
else
{
EPackage ePackage = EPackage.Registry.INSTANCE.getEPackage(proxyURI.trimFragment().toString());
if (ePackage != null)
{
Resource resource = ePackage.eResource();
if (resource != null)
{
resolvedObject = resource.getEObject(proxyURI.fragment().toString());
}
}
}
if (resolvedObject != null && resolvedObject != proxy)
{
return resolve(resolvedObject, resourceSet);
}
}
catch (RuntimeException exception)
{
// Failure to resolve is ignored.
}
}
return proxy;
}
/**
* Returns the resolved object represented by proxy. Proxy chains are followed.
* If resourceContext is null or not in a resource set, the global package registry is
* consulted to obtain a package registered against the proxy URI, less its fragment,
* in the same manner as the default resource set implementation's fall-back behaviour.
* @param proxy the proxy to be resolved.
* @param resourceContext a context resource whose resource set is used for the resolve.
* @return the resolved object, or the proxy if unable to resolve.
*/
public static EObject resolve(EObject proxy, Resource resourceContext)
{
return resolve(proxy, resourceContext != null ? resourceContext.getResourceSet() : null);
}
/**
* Returns the resolved object represented by proxy. Proxy chains are followed.
* If objectContext is null or not in a resource that is in a resource set, the
* global package registry is consulted to obtain a package registered against
* the proxy URI, less its fragment, in the same manner as the default resource
* set implementation's fall-back behaviour.
* @param proxy the proxy to be resolved.
* @param objectContext a context object whose resource set is used for the resolve.
* @return the resolved object, or the proxy if unable to resolve.
*/
public static EObject resolve(EObject proxy, EObject objectContext)
{
Resource resourceContext = objectContext != null ? objectContext.eResource() : null;
return resolve(proxy, resourceContext != null ? resourceContext.getResourceSet() : null);
}
/**
* Visits all proxies in the resource set and tries to resolve them.
* @param resourceSet the objects to visit.
*/
public static void resolveAll(ResourceSet resourceSet)
{
List<Resource> resources = resourceSet.getResources();
for (int i = 0; i < resources.size(); ++i)
{
resolveAll(resources.get(i));
}
}
/**
* Visits all proxies in the resource and tries to resolve them.
* @param resource the objects to visit.
*/
public static void resolveAll(Resource resource)
{
for (EObject eObject : resource.getContents())
{
resolveAll(eObject);
}
}
/**
* Visits all proxies referenced by the object and recursively any of its contained objects.
* @param eObject the object to visit.
*/
public static void resolveAll(EObject eObject)
{
eObject.eContainer();
resolveCrossReferences(eObject);
for (Iterator<EObject> i = eObject.eAllContents(); i.hasNext(); )
{
EObject childEObject = i.next();
resolveCrossReferences(childEObject);
}
}
private static void resolveCrossReferences(EObject eObject)
{
for (Iterator<EObject> i = eObject.eCrossReferences().iterator(); i.hasNext(); i.next())
{
// The loop resolves the cross references by visiting them.
}
}
/**
* Returns the first collection member that {@link EClassifier#isInstance is an instance} of the type.
* @param objects a collection of objects to check.
* @param type the type of object to find.
* @return the first object of the specified type.
*/
public static Object getObjectByType(Collection<?> objects, EClassifier type)
{
for (Object object : objects)
{
if (type.isInstance(object))
{
return object;
}
}
return null;
}
/**
* Returns a collection containing each collection member that {@link EClassifier#isInstance is an instance} of the type.
* @param objects a collection of objects to check.
* @param type the type of object to find.
* @return a collection of objects of the specified type.
*/
public static <T> Collection<T> getObjectsByType(Collection<?> objects, EClassifier type)
{
Collection<T> result = new ArrayList<T>();
for (Object object : objects)
{
if (type.isInstance(object))
{
@SuppressWarnings("unchecked") T t = (T)object;
result.add(t);
}
}
return result;
}
/**
* Returns a self-contained copy of the eObject.
* @param eObject the object to copy.
* @return the copy.
* @see Copier
*/
public static <T extends EObject> T copy(T eObject)
{
Copier copier = new Copier();
EObject result = copier.copy(eObject);
copier.copyReferences();
@SuppressWarnings("unchecked")T t = (T)result;
return t;
}
/**
* Returns a collection of the self-contained copies of each {@link EObject} in eObjects.
* @param eObjects the collection of objects to copy.
* @return the collection of copies.
* @see Copier
*/
public static <T> Collection<T> copyAll(Collection<? extends T> eObjects)
{
Copier copier = new Copier();
Collection<T> result = copier.copyAll(eObjects);
copier.copyReferences();
return result;
}
/**
* A mapping building traverser of a collection of {@link EObject#eAllContents content trees};
* the map is from {@link EObject} to <code>EObject</code>, i.e., from original to copy;
* use {@link EcoreUtil#copy EcoreUtil.copy} or {@link EcoreUtil#copyAll EcoreUtil.copyAll} to do routine copies.
* Since this implementation extends a Map implementation, it acts as the result of the over all copy.
* The client can call {@link #copy copy} and {@link #copyAll copyAll} repeatedly.
* When all the objects have been copied,
* the client should call {@link #copyReferences copyReferences}
* to copy the {@link #copyReference appropriate} {@link EObject#eCrossReferences cross references}.
*<pre>
* Copier copier = new Copier();
* EObject result = copier.copy(eObject);
* Collection results = copier.copyAll(eObjects);
* copier.copyReferences();
*</pre>
* The copier delegates to {@link #copyContainment copyContainment}, {@link #copyAttribute copyAttribute} during the copy phase
* and to {@link #copyReference copyReference}, during the cross reference phase.
* This allows tailored handling through derivation.
*/
public static class Copier extends LinkedHashMap<EObject, EObject>
{
private static final long serialVersionUID = 1L;
/**
* Whether proxies should be resolved during copying.
*/
protected boolean resolveProxies = true;
/**
* Whether non-copied references should be used during copying.
*/
protected boolean useOriginalReferences = true;
/**
* Creates an instance.
*/
public Copier()
{
super();
}
/**
* Creates an instance that resolves proxies or not as specified.
* @param resolveProxies whether proxies should be resolved while copying.
*/
public Copier(boolean resolveProxies)
{
this.resolveProxies = resolveProxies;
}
/**
* Creates an instance that resolves proxies or not and uses non-copied references or not as specified.
* @param resolveProxies whether proxies should be resolved while copying.
* @param useOriginalReferences whether non-copied references should be used while copying.
*/
public Copier(boolean resolveProxies, boolean useOriginalReferences)
{
this.resolveProxies = resolveProxies;
this.useOriginalReferences = useOriginalReferences;
}
/**
* Returns a collection containing a copy of each EObject in the given collection.
* @param eObjects the collection of objects to copy.
* @return the collection of copies.
*/
public <T> Collection<T> copyAll(Collection<? extends T> eObjects)
{
Collection<T> result = new ArrayList<T>(eObjects.size());
for (Object object : eObjects)
{
@SuppressWarnings("unchecked") T t = (T)copy((EObject)object);
if (t != null)
{
result.add(t);
}
}
return result;
}
/**
* Returns a copy of the given eObject.
* @param eObject the object to copy.
* @return the copy.
*/
public EObject copy(EObject eObject)
{
if (eObject == null)
{
return null;
}
else
{
EObject copyEObject = createCopy(eObject);
if (copyEObject != null)
{
put(eObject, copyEObject);
EClass eClass = eObject.eClass();
for (int i = 0, size = eClass.getFeatureCount(); i < size; ++i)
{
EStructuralFeature eStructuralFeature = eClass.getEStructuralFeature(i);
if (eStructuralFeature.isChangeable() && !eStructuralFeature.isDerived())
{
if (eStructuralFeature instanceof EAttribute)
{
copyAttribute((EAttribute)eStructuralFeature, eObject, copyEObject);
}
else
{
EReference eReference = (EReference)eStructuralFeature;
if (eReference.isContainment())
{
copyContainment(eReference, eObject, copyEObject);
}
}
}
}
copyProxyURI(eObject, copyEObject);
}
return copyEObject;
}
}
/**
* Copies the proxy URI from the original to the copy, if present.
* @param eObject the object being copied.
* @param copyEObject the copy being initialized.
*/
protected void copyProxyURI(EObject eObject, EObject copyEObject)
{
if (eObject.eIsProxy())
{
((InternalEObject)copyEObject).eSetProxyURI(((InternalEObject)eObject).eProxyURI());
}
}
/**
* Returns a new instance of the object's target class.
* @param eObject the object to copy.
* @return a new instance of the target class.
* @see #getTarget(EObject)
* @see EcoreUtil#create(EClass)
*/
protected EObject createCopy(EObject eObject)
{
EClass eClass = getTarget(eObject);
return eClass == null ? null : create(eClass);
}
/**
* Returns the target class used to create a copy instance for the given instance object.
* @param eObject the object to be copied.
* @return the target class used to create a copy instance.
* @since 2.10
*/
protected EClass getTarget(EObject eObject)
{
return getTarget(eObject.eClass());
}
/**
* Returns the target class used to create a copy instance for objects of the given source class.
* @param eClass the source class.
* @return the target class used to create a copy instance.
* @see #getTarget(EStructuralFeature, EObject, EObject)
*/
protected EClass getTarget(EClass eClass)
{
return eClass;
}
/**
* Returns a setting for the feature and copy instance to be populated with the original object's source feature's value.
* @param eStructuralFeature the source feature.
* @return the target feature used to populate a copy instance.
* @see #getTarget(EStructuralFeature)
* @see #getTarget(EObject)
* @since 2.10
*/
protected EStructuralFeature.Setting getTarget(EStructuralFeature eStructuralFeature, EObject eObject, EObject copyEObject)
{
EStructuralFeature targetEStructuralFeature = getTarget(eStructuralFeature);
return targetEStructuralFeature == null ? null : ((InternalEObject)copyEObject).eSetting(targetEStructuralFeature);
}
/**
* Returns the target feature used to populate a copy instance from the given source feature.
* @param eStructuralFeature the source feature.
* @return the target feature used to populate a copy instance.
* @see #getTarget(EClass)
*/
protected EStructuralFeature getTarget(EStructuralFeature eStructuralFeature)
{
return eStructuralFeature;
}
/**
* Called to handle the copying of a containment feature;
* this adds a list of copies or sets a single copy as appropriate for the multiplicity.
* @param eReference the feature to copy.
* @param eObject the object from which to copy.
* @param copyEObject the object to copy to.
*/
protected void copyContainment(EReference eReference, EObject eObject, EObject copyEObject)
{
if (eObject.eIsSet(eReference))
{
EStructuralFeature.Setting setting = getTarget(eReference, eObject, copyEObject);
if (setting != null)
{
Object value = eObject.eGet(eReference);
if (eReference.isMany())
{
@SuppressWarnings("unchecked")
List<EObject> target = (List<EObject>)value;
setting.set(copyAll(target));
}
else
{
setting.set(copy((EObject)value));
}
}
}
}
/**
* Called to handle the copying of an attribute;
* this adds a list of values or sets a single value as appropriate for the multiplicity.
* @param eAttribute the attribute to copy.
* @param eObject the object from which to copy.
* @param copyEObject the object to copy to.
*/
protected void copyAttribute(EAttribute eAttribute, EObject eObject, EObject copyEObject)
{
if (eObject.eIsSet(eAttribute))
{
if (FeatureMapUtil.isFeatureMap(eAttribute))
{
FeatureMap featureMap = (FeatureMap)eObject.eGet(eAttribute);
copyFeatureMap(featureMap);
}
else
{
EStructuralFeature.Setting setting = getTarget(eAttribute, eObject, copyEObject);
if (setting != null)
{
copyAttributeValue(eAttribute, eObject, eObject.eGet(eAttribute), setting);
}
}
}
}
/**
* Call to handle copying the contained objects within a feature map.
* @param featureMap the feature map the copy.
* @since 2.10
*/
protected void copyFeatureMap(FeatureMap featureMap)
{
for (int i = 0, size = featureMap.size(); i < size; ++i)
{
EStructuralFeature feature = featureMap.getEStructuralFeature(i);
if (feature instanceof EReference && ((EReference)feature).isContainment())
{
Object value = featureMap.getValue(i);
if (value != null)
{
// The containment references are hooked up later during copyReferences.
//
copy((EObject)value);
}
}
}
}
/**
* Called to handle copying of an attribute's value to the target setting.
* @param eAttribute the attribute of the source object corresponding to the value.
* @param eObject the object being copied.
* @param value the value to be copied.
* @param setting the feature-value pair that is the target of of the copy.
* @since 2.10
*/
protected void copyAttributeValue(EAttribute eAttribute, EObject eObject, Object value, EStructuralFeature.Setting setting)
{
setting.set(value);
}
/**
* Hooks up cross references; it delegates to {@link #copyReference copyReference}.
*/
public void copyReferences()
{
for (Map.Entry<EObject, EObject> entry : entrySet())
{
EObject eObject = entry.getKey();
EObject copyEObject = entry.getValue();
EClass eClass = eObject.eClass();
for (int j = 0, size = eClass.getFeatureCount(); j < size; ++j)
{
EStructuralFeature eStructuralFeature = eClass.getEStructuralFeature(j);
if (eStructuralFeature.isChangeable() && !eStructuralFeature.isDerived())
{
if (eStructuralFeature instanceof EReference)
{
EReference eReference = (EReference)eStructuralFeature;
if (!eReference.isContainment() && !eReference.isContainer())
{
copyReference(eReference, eObject, copyEObject);
}
}
else if (FeatureMapUtil.isFeatureMap(eStructuralFeature))
{
FeatureMap copyFeatureMap = (FeatureMap)getTarget(eStructuralFeature, eObject, copyEObject);
if (copyFeatureMap != null)
{
FeatureMap featureMap = (FeatureMap)eObject.eGet(eStructuralFeature);
int copyFeatureMapSize = copyFeatureMap.size();
for (int k = 0, featureMapSize = featureMap.size(); k < featureMapSize; ++k)
{
EStructuralFeature feature = featureMap.getEStructuralFeature(k);
if (feature instanceof EReference)
{
Object referencedEObject = featureMap.getValue(k);
Object copyReferencedEObject = get(referencedEObject);
if (copyReferencedEObject == null && referencedEObject != null)
{
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(getTarget(featureMap.getEStructuralFeature(k)), featureMap.getValue(k));
}
}
}
}
}
}
}
}
/**
* Called to handle the copying of a cross reference;
* this adds values or sets a single value as appropriate for the multiplicity
* while omitting any bidirectional reference that isn't in the copy map.
* @param eReference the reference to copy.
* @param eObject the object from which to copy.
* @param copyEObject the object to copy to.
*/
protected void copyReference(EReference eReference, EObject eObject, EObject copyEObject)
{
if (eObject.eIsSet(eReference))
{
EStructuralFeature.Setting setting = getTarget(eReference, eObject, copyEObject);
if (setting != null)
{
Object value = eObject.eGet(eReference, resolveProxies);
if (eReference.isMany())
{
@SuppressWarnings("unchecked") InternalEList<EObject> source = (InternalEList<EObject>)value;
@SuppressWarnings("unchecked") InternalEList<EObject> target = (InternalEList<EObject>)setting;
if (source.isEmpty())
{
target.clear();
}
else
{
boolean isBidirectional = eReference.getEOpposite() != null;
int index = 0;
for (Iterator<EObject> k = resolveProxies ? source.iterator() : source.basicIterator(); k.hasNext();)
{
EObject referencedEObject = k.next();
EObject copyReferencedEObject = get(referencedEObject);
if (copyReferencedEObject == null)
{
if (useOriginalReferences && !isBidirectional)
{
target.addUnique(index, referencedEObject);
++index;
}
}
else
{
if (isBidirectional)
{
int position = target.indexOf(copyReferencedEObject);
if (position == -1)
{
target.addUnique(index, copyReferencedEObject);
}
else if (index != position)
{
target.move(index, copyReferencedEObject);
}
}
else
{
target.addUnique(index, copyReferencedEObject);
}
++index;
}
}
}
}
else
{
if (value == null)
{
setting.set(null);
}
else
{
Object copyReferencedEObject = get(value);
if (copyReferencedEObject == null)
{
if (useOriginalReferences && eReference.getEOpposite() == null)
{
setting.set(value);
}
}
else
{
setting.set(copyReferencedEObject);
}
}
}
}
}
}
}
/**
* Returns the root container;
* it may be this object itself
* and it will have a <code>null</code> {@link EObject#eContainer container}.
* <p>
* The root container must be {@link Resource#getContents directly contained} in a resource
* for its {@link EObject#eAllContents tree} to be {@link Resource#save(java.util.Map) serializable}.
* </p>
* @param eObject the object to get the root container for.
* @return the root container.
* @see #getRootContainer(EObject, boolean)
* @see EObject#eResource()
* @see EObject#eContainer()
*/
public static EObject getRootContainer(EObject eObject)
{
EObject result = eObject;
if (eObject != null)
{
int count = 0;
for (EObject parent = eObject.eContainer(); parent != null; parent = parent.eContainer())
{
if (++count > 100000)
{
return getRootContainer(parent);
}
result = parent;
if (parent == eObject)
{
throw new IllegalStateException("There is a cycle in the containment hierarchy of " + eObject);
}
}
}
return result;
}
/**
* Returns the root container;
* it may be this object itself
* and it will have a <code>null</code> {@link EObject#eContainer container}.
* Container proxies are resolved or not as specified
* <p>
* The root container must be {@link Resource#getContents directly contained} in a resource
* for its {@link EObject#eAllContents tree} to be {@link Resource#save(java.util.Map) serializable}.
* </p>
* @param eObject the object to get the root container for.
* @param resolve whether to resolve container proxies.
* @return the root container.
* @see #getRootContainer(EObject)
* @see EObject#eResource()
* @see InternalEObject#eInternalContainer()
*/
public static EObject getRootContainer(EObject eObject, boolean resolve)
{
if (resolve)
{
return getRootContainer(eObject);
}
else
{
EObject result = eObject;
if (eObject != null)
{
int count = 0;
for (InternalEObject parent = ((InternalEObject)eObject).eInternalContainer(); parent != null; parent = parent.eInternalContainer())
{
if (++count > 100000)
{
return getRootContainer(parent, false);
}
result = parent;
if (parent == eObject)
{
throw new IllegalStateException("There is a cycle in the containment hierarchy of " + eObject);
}
}
}
return result;
}
}
/**
* Returns whether the second object is directly or indirectly contained by the first object,
* i.e., whether the second object is in the {@link EObject#eContents content tree} of the first.
* Container proxies are not resolved.
* @param ancestorEObject the ancestor object in question.
* @param eObject the object to test.
* @return whether the first object is an ancestor of the second object.
* @see EObject#eContainer
*/
public static boolean isAncestor(EObject ancestorEObject, EObject eObject)
{
if (eObject != null)
{
if (eObject == ancestorEObject)
{
return true;
}
int count = 0;
for (InternalEObject eContainer = ((InternalEObject)eObject).eInternalContainer();
eContainer != null && eContainer != eObject;
eContainer = eContainer.eInternalContainer())
{
if (++count > 100000)
{
return isAncestor(ancestorEObject, eContainer);
}
if (eContainer == ancestorEObject)
{
return true;
}
}
}
return false;
}
/**
* Returns whether the given resource is that of the object,
* i.e., whether the object is in the {@link Resource#getContents content tree} of the resource.
* @param ancestorResource the ancestor resource in question.
* @param eObject the object to test.
* @return whether the resource is an ancestor of the object.
* @see EObject#eContainer
* @see EObject#eResource
*/
public static boolean isAncestor(Resource ancestorResource, EObject eObject)
{
if (eObject != null)
{
InternalEObject internalEObject = (InternalEObject)eObject;
if (internalEObject.eDirectResource() == ancestorResource)
{
return true;
}
int count = 0;
for (InternalEObject parent = internalEObject.eInternalContainer(); parent != null && parent != eObject; parent = parent.eInternalContainer())
{
if (++count > 100000)
{
return isAncestor(ancestorResource, parent);
}
if (parent.eDirectResource() == ancestorResource)
{
return true;
}
}
}
return false;
}
/**
* Returns whether the given resource set is that of the object,
* i.e., whether the object is in the {@link Resource#getContents content tree} of the resource set.
* @param ancestorResourceSet the ancestor resource set in question.
* @param eObject the object to test.
* @return whether the resource set is an ancestor of the object.
* @see EObject#eContainer
* @see EObject#eResource
* @see Resource#getResourceSet
*/
public static boolean isAncestor(ResourceSet ancestorResourceSet, EObject eObject)
{
if (eObject != null)
{
InternalEObject internalEObject = (InternalEObject)eObject;
Resource resource = internalEObject.eDirectResource();
if (resource != null && resource.getResourceSet() == ancestorResourceSet)
{
return true;
}
int count = 0;
for (InternalEObject parent = internalEObject.eInternalContainer(); parent != null && parent != eObject; parent = parent.eInternalContainer())
{
if (++count > 100000)
{
return isAncestor(ancestorResourceSet, parent);
}
resource = parent.eDirectResource();
if (resource != null && resource.getResourceSet() == ancestorResourceSet)
{
return true;
}
}
}
return false;
}
/**
* Returns whether any EObject, Resource, or ResourceSet in the collection is an ancestor of the EObject.
* @param ancestorEMFObjects the collection of ancestor objects in question.
* @param eObject the object to test.
* @return whether any object in the collection is an ancestor of the object.
*/
public static boolean isAncestor(Collection<?> ancestorEMFObjects, EObject eObject)
{
if (eObject != null)
{
if (ancestorEMFObjects.contains(eObject))
{
return true;
}
InternalEObject internalEObject = (InternalEObject)eObject;
Resource resource = internalEObject.eDirectResource();
if (resource != null && (ancestorEMFObjects.contains(resource) || ancestorEMFObjects.contains(resource.getResourceSet())))
{
return true;
}
int count = 0;
for (InternalEObject parent = internalEObject.eInternalContainer(); parent != null && parent != eObject; parent = parent.eInternalContainer())
{
if (++count > 100000)
{
return isAncestor(ancestorEMFObjects, parent);
}
if (ancestorEMFObjects.contains(parent))
{
return true;
}
resource = parent.eDirectResource();
if (resource != null && (ancestorEMFObjects.contains(resource) || ancestorEMFObjects.contains(resource.getResourceSet())))
{
return true;
}
}
}
return false;
}
/**
* Returns a subset of the objects such that no object in the result is an {@link #isAncestor(EObject, EObject) ancestor} of any other object in the result.
* @param eObjects the objects to be filtered.
* @return a subset of the objects such that no object in the result is an ancestor of any other object in the result.
* @since 2.5
*/
public static List<EObject> filterDescendants(Collection<? extends EObject> eObjects)
{
List<EObject> result = new ArrayList<EObject>(eObjects.size());
LOOP:
for (EObject eObject : eObjects)
{
for (int i = 0, size = result.size(); i < size; )
{
EObject rootEObject = result.get(i);
if (rootEObject == eObject || EcoreUtil.isAncestor(rootEObject, eObject))
{
continue LOOP;
}
if (EcoreUtil.isAncestor(eObject, rootEObject))
{
result.remove(i);
--size;
}
else
{
++i;
}
}
result.add(eObject);
}
return result;
}
/**
* Returns a tree iterator over the content trees
* recursively defined by
* {@link ResourceSet#getResources()},
* {@link Resource#getContents()},
* and {@link EObject#eContents()}.
* It uses a special iterator for ResourceSet.getResources
* that is tolerant of growth in the underlying collection
* which result from demand loaded resources;
* the iterator will walk these additional resources.
* @param emfObjects the collection of objects to iterate over.
* @return a tree iterator over the objects and their contents.
* @see ContentTreeIterator
*/
public static <T> TreeIterator<T> getAllContents(Collection<?> emfObjects)
{
return new ContentTreeIterator<T>(emfObjects);
}
/**
* Returns a tree iterator over the content trees
* recursively defined by
* {@link ResourceSet#getResources()},
* {@link Resource#getContents()},
* and {@link EObject#eContents()}.
* It uses a special iterator for ResourceSet.getResources
* that is tolerant of growth in the underlying collection
* which result from demand loaded resources;
* the iterator will walk these additional resources.
* Contained proxies are resolved or not as specified.
* @param emfObjects the collection of objects to iterate over.
* @param resolve whether proxies should be resolved.
* @return a tree iterator over the objects and their contents.
* @see ContentTreeIterator
*/
public static <T> TreeIterator<T> getAllContents(Collection<?> emfObjects, boolean resolve)
{
return new ContentTreeIterator<T>(emfObjects, resolve);
}
/**
* Returns a tree iterator that iterates over all the {@link EObject#eContents direct contents} and indirect contents of the object.
* @param eObject the object to iterate over.
* @param resolve whether proxies should be resolved.
* @return a tree iterator that iterates over all contents.
* @see EObject#eAllContents
* @see Resource#getAllContents
*/
public static <T> TreeIterator<T> getAllContents(EObject eObject, boolean resolve)
{
return
new ContentTreeIterator<T>(eObject, resolve)
{
private static final long serialVersionUID = 1L;
@SuppressWarnings("unchecked")
@Override
public Iterator<T> getChildren(Object object)
{
return (Iterator<T>)getEObjectChildren((EObject)object);
}
};
}
/**
* Returns a tree iterator that iterates over all the {@link Resource#getContents direct contents} and indirect contents of the resource.
* @param resource the resource to iterate over.
* @param resolve whether proxies should be resolved.
* @return a tree iterator that iterates over all contents.
* @see EObject#eAllContents
* @see ResourceSet#getAllContents
*/
public static <T> TreeIterator<T> getAllContents(Resource resource, boolean resolve)
{
return
new ContentTreeIterator<T>(resource.getContents(), resolve)
{
private static final long serialVersionUID = 1L;
@SuppressWarnings("unchecked")
@Override
public Iterator<T> getChildren(Object object)
{
return object == this.object ? ((List<T>)this.object).iterator() : (Iterator<T>)(getEObjectChildren((EObject)object));
}
};
}
/**
* Returns a tree iterator that iterates over all the {@link ResourceSet#getResources direct resources} in the resource set
* and over the content {@link Resource#getAllContents tree} of each.
* @param resourceSet the resource set to iterate over.
* @param resolve whether proxies should be resolved.
* @return a tree iterator that iterates over all contents.
* @see EObject#eAllContents
* @see Resource#getAllContents
* @see org.eclipse.emf.ecore.util.EcoreUtil#getAllProperContents(Resource, boolean)
*/
public static <T> TreeIterator<T> getAllContents(ResourceSet resourceSet, boolean resolve)
{
return new ContentTreeIterator<T>(resourceSet, resolve);
}
/**
* Returns a tree iterator over the content trees
* recursively defined by
* {@link ResourceSet#getResources()},
* {@link Resource#getContents()},
* and {@link EObject#eContents()},
* skipping over any child object that's in a different resource from its parent.
* It uses a special iterator for ResourceSet.getResources
* that is tolerant of growth in the underlying collection
* which result from demand loaded resources;
* the iterator will walk these additional resources.
* Contained proxies are resolved or not as specified.
* @param emfObjects the collection of objects to iterate over.
* @param resolve whether proxies should be resolved.
* @return a tree iterator over the objects and their contents.
* @see ContentTreeIterator
*/
public static <T> TreeIterator<T> getAllProperContents(Collection<?> emfObjects, boolean resolve)
{
return
new ContentTreeIterator<T>(emfObjects, resolve)
{
private static final long serialVersionUID = 1L;
@Override
public Iterator<EObject> getEObjectChildren(EObject eObject)
{
return new ProperContentIterator<EObject>(eObject, isResolveProxies());
}
};
}
/**
* Returns a tree iterator that iterates over all the {@link EObject#eContents direct contents} and indirect contents of the object,
* skipping over any child object that's in a different resource from its parent.
* @param eObject the object to iterate over.
* @param resolve whether proxies should be resolved.
* @return a tree iterator that iterates over all contents.
* @see EObject#eAllContents
* @see Resource#getAllContents
*/
public static <T> TreeIterator<T> getAllProperContents(EObject eObject, boolean resolve)
{
return
new ContentTreeIterator<T>(eObject, resolve)
{
private static final long serialVersionUID = 1L;
@Override
public Iterator<T> getChildren(Object object)
{
return new ProperContentIterator<T>(((EObject)object), isResolveProxies());
}
};
}
/**
* Returns a tree iterator that iterates over all the {@link Resource#getContents direct contents} and indirect contents of the resource,
* skipping over any child object that's in a different resource from its parent.
* @param resource the resource to iterate over.
* @param resolve whether proxies should be resolved.
* @return a tree iterator that iterates over all contents.
* @see EObject#eAllContents
* @see ResourceSet#getAllContents
*/
public static <T> TreeIterator<T> getAllProperContents(Resource resource, boolean resolve)
{
return
new ContentTreeIterator<T>(resource.getContents(), resolve)
{
private static final long serialVersionUID = 1L;
@Override
public Iterator<T> getChildren(Object object)
{
if (object == this.object)
{
@SuppressWarnings("unchecked") Iterator<T> result = ((Collection<T>)object).iterator();
return result;
}
else
{
return new ProperContentIterator<T>(((EObject)object), isResolveProxies());
}
}
};
}
/**
* Returns a tree iterator that iterates over all the {@link ResourceSet#getResources direct resources} in the resource set
* and over the content {@link Resource#getAllContents tree} of each,
* skipping over any child object that's in a different resource from its parent.
* @param resourceSet the resource set to iterate over.
* @param resolve whether proxies should be resolved.
* @return a tree iterator that iterates over all contents.
* @see EObject#eAllContents
* @see Resource#getAllContents
* @see org.eclipse.emf.ecore.util.EcoreUtil#getAllContents(ResourceSet, boolean)
*/
public static <T> TreeIterator<T> getAllProperContents(ResourceSet resourceSet, boolean resolve)
{
return
new ContentTreeIterator<T>(resourceSet, resolve)
{
private static final long serialVersionUID = 1L;
@Override
public Iterator<EObject> getEObjectChildren(EObject eObject)
{
return new ProperContentIterator<EObject>(eObject, isResolveProxies());
}
};
}
/**
* An iterator that can skip over items in a list.
*/
public static class ProperContentIterator<E> implements Iterator<E>
{
protected Iterator<? extends E> iterator;
protected E preparedResult;
public ProperContentIterator(List<? extends E> contents)
{
iterator = contents.iterator();
}
public ProperContentIterator(InternalEList<? extends E> basicContents)
{
iterator = basicContents.basicIterator();
}
public ProperContentIterator(EObject eObject)
{
this(eObject, false);
}
@SuppressWarnings("unchecked")
public ProperContentIterator(EObject eObject, boolean isResolveProxies)
{
EList<EObject> contents = eObject.eContents();
iterator =
(Iterator<E>)
(!isResolveProxies && contents instanceof InternalEList<?> ?
((InternalEList<EObject>)contents).basicIterator() :
contents.iterator());
}
public boolean hasNext()
{
if (preparedResult == null)
{
while (iterator.hasNext())
{
preparedResult = iterator.next();
if (((InternalEObject)preparedResult).eDirectResource() == null)
{
return true;
}
}
preparedResult = null;
return false;
}
else
{
return true;
}
}
public E next()
{
hasNext();
E result = preparedResult;
preparedResult = null;
return result;
}
public void remove()
{
iterator.remove();
}
}
/**
* An iterator over the tree contents of a collection of EObjects, Resources, and ResourceSets.
* It provides a special iterator for ResourceSet.getResources
* that is tolerant of growth in the underlying collection
* which result from demand loaded resources;
* the iterator will walk these additional resources.
* @see EcoreUtil#getAllContents(EObject, boolean)
* @see EcoreUtil#getAllContents(Resource, boolean)
* @see EcoreUtil#getAllContents(ResourceSet, boolean)
*/
public static class ContentTreeIterator<E> extends AbstractTreeIterator<E>
{
private static final long serialVersionUID = 1L;
/**
* Whether proxies should be resolved.
*/
protected boolean isResolveProxies;
/**
* The most recently created iterator over a resource set's resources.
* This iterator needs special handling because it returns <code>true</code> for <code>hasNext()</code>
* even when the list is exhausted.
* This ensures that any growth in the resources list will not be overlooked.
*/
protected ResourcesIterator resourceSetIterator;
/**
* Creates an instance for the given collection of objects.
* @param emfObjects the collection of objects to iterate over.
*/
protected ContentTreeIterator(Collection<?> emfObjects)
{
super(emfObjects, false);
}
/**
* Creates an instance for the given collection of objects.
* @param object the collection of objects to iterate over.
* @param isResolveProxies whether proxies should be resolved during the traversal.
*/
protected ContentTreeIterator(Object object, boolean isResolveProxies)
{
super(object, false);
this.isResolveProxies = isResolveProxies;
}
/**
* Returns an iterator over the children of the given parent object.
* @param object the parent object.
* @return the children iterator.
*/
@SuppressWarnings("unchecked")
@Override
public Iterator<E> getChildren(Object object)
{
if (object instanceof EObject)
{
return (Iterator<E>)getEObjectChildren((EObject)object);
}
else if (object instanceof Resource)
{
return (Iterator<E>)getResourceChildren((Resource)object);
}
else if (object instanceof ResourceSet)
{
return (Iterator<E>)getResourceSetChildren((ResourceSet)object);
}
else if (object == this.object)
{
return ((Collection<E>)object).iterator();
}
else
{
return getObjectChildren(object);
}
}
/**
* Returns an iterator over the {@link EObject#eContents() children} of the given parent EObject.
* @param eObject the parent object.
* @return the children iterator.
*/
protected Iterator<? extends EObject> getEObjectChildren(EObject eObject)
{
return isResolveProxies() ? eObject.eContents().iterator() : ((InternalEList<EObject>)eObject.eContents()).basicIterator();
}
/**
* Returns whether proxies should resolve.
* @return whether proxies should resolve.
*/
protected boolean isResolveProxies()
{
return isResolveProxies;
}
/**
* Returns an iterator over the {@link Resource#getContents() children} of the given parent resource.
* @param resource the parent resource.
* @return the children iterator.
*/
protected Iterator<EObject> getResourceChildren(Resource resource)
{
return resource.getContents().iterator();
}
/**
* Returns the next object and advances the iterator.
* This override handles the {@link #resourceSetIterator} in a special way,
* i.e., it skips the null object that iterator yields as the last fake item of the list.
* @return the next object.
*/
@Override
public boolean hasNext()
{
Iterator<?> iterator;
if (!includeRoot && data == null)
{
nextPruneIterator = getChildren(object);
add(nextPruneIterator);
iterator = nextPruneIterator;
}
else
{
// We don't create an iterator stack until the root mapping itself has been returned by next once.
// After that the stack should be non-empty and the top iterator should yield true for hasNext.
//
if (data == null)
{
return true;
}
else if (isEmpty())
{
return false;
}
else
{
iterator = (Iterator<?>)data[size - 1];
}
}
// If we are on the special resource set iterator, and there isn't really a next object at this point...
//
if (iterator == resourceSetIterator && !resourceSetIterator.reallyHasNext())
{
// Skip the dummy null object and test again.
//
next();
return hasNext();
}
else
{
return iterator.hasNext();
}
}
/**
* A special iterator that's tolerant of growth in the list of resources
* which can result from demand loading when traversing the tree of contents.
*/
protected static class ResourcesIterator implements Iterator<Resource>
{
/**
* The resources to iterator over.
*/
protected List<? extends Resource> resources;
/**
* The current index of the iterator.
*/
protected int index = 0;
/**
* Constructs an instance.
* @param resources the list of resources.
*/
public ResourcesIterator(List<? extends Resource> resources)
{
this.resources = resources;
}
/**
* Returns whether there really are any resources left.
* @return whether there really are any resources left.
*/
public boolean reallyHasNext()
{
return index < resources.size();
}
/**
* Returns whether there might be resources left by the time we next check.
* This returns <code>true</code> when the index is equal to the size,
* because the tree iterator will still be set to yield the last of the contents of the resource,
* and accessing that may cause another resource to be loaded.
* @return whether there might be resources left by the time we next check.
*/
public boolean hasNext()
{
return index <= resources.size();
}
/**
* Returns the next item, or <code>null</code> if there isn't one.
* @return the next item, or <code>null</code> if there isn't one.
*/
public Resource next()
{
if (index >= resources.size())
{
++index;
return null;
}
else
{
return resources.get(index++);
}
}
/**
* @throws UnsupportedOperationException always.
*/
public void remove()
{
throw new UnsupportedOperationException();
}
}
/**
* Returns an iterator over the {@link ResourceSet#getResources() children} of the given parent resource set.
* It also records the result in {@link #resourceSetIterator} for special handling in {@link #hasNext()}.
* @param resourceSet the parent resource set.
* @return the children iterator.
*/
protected Iterator<Resource> getResourceSetChildren(ResourceSet resourceSet)
{
return resourceSetIterator = new ResourcesIterator(resourceSet.getResources());
}
/**
* Returns an empty iterator; subclasses may override this method.
* @param object the parent object.
* @return the children iterator.
*/
protected Iterator<E> getObjectChildren(Object object)
{
return ECollections.<E>emptyEList().iterator();
}
}
/**
* A mapping building traverser of a collection of {@link ContentTreeIterator content trees};
* the map is from target {@link EObject object} to a collection of {@link org.eclipse.emf.ecore.EStructuralFeature.Setting}.
* Since this implementation extends a Map implementation, it can yield itself as the result for most operations.
* The traverser considers each EObject in the {@link EObject#eCrossReferences} of each EObject in the content tree,
* and creates a setting for each positive match.
* This default implementation {@link #find creates} a map of all cross references.
*/
public static class CrossReferencer extends HashMap<EObject, Collection<EStructuralFeature.Setting>>
{
private static final long serialVersionUID = 1L;
/**
* The collection of objects being cross referenced.
*/
protected Collection<?> emfObjects;
/**
* Creates an instance for the given object.
* @param eObject the object to cross reference.
*/
protected CrossReferencer(EObject eObject)
{
this.emfObjects = Collections.singleton(eObject);
}
/**
* Creates an instance for the given resource.
* @param resource the resource to cross reference.
*/
protected CrossReferencer(Resource resource)
{
this.emfObjects = Collections.singleton(resource);
}
/**
* Creates an instance for the given resource set.
* @param resourceSet the resource set to cross reference.
*/
protected CrossReferencer(ResourceSet resourceSet)
{
this.emfObjects = Collections.singleton(resourceSet);
}
/**
* Creates an instance for the given collection of objects.
* @param emfObjects the collection of objects to cross reference.
*/
protected CrossReferencer(Collection<?> emfObjects)
{
this.emfObjects = emfObjects;
}
/**
* Return true if the cross referencer should include references from children of the specified object.
* @param eObject an object in the cross referencer's content tree.
* @return if the cross referencer should include references from children of the object.
*/
protected boolean containment(EObject eObject)
{
return true;
}
/**
* Return true if the specified eReference from eObject to crossReferencedEObject should be
* considered a cross reference by this cross referencer.
* @param eObject an object in the cross referencer's content tree.
* @param eReference a reference from the object.
* @param crossReferencedEObject the target of the specified reference.
* @return if the cross referencer should consider the specified reference a cross reference.
*/
protected boolean crossReference(EObject eObject, EReference eReference, EObject crossReferencedEObject)
{
return true;
}
/**
* Return true if cross references that are proxies should be resolved.
* @return if the cross referencer should resolve proxies.
*/
protected boolean resolve()
{
return true;
}
/**
* Return a collection to use for storing {@link org.eclipse.emf.ecore.EStructuralFeature.Setting settings}.
* @return a collection for settings.
*/
protected Collection<EStructuralFeature.Setting> newCollection()
{
return new ArrayList<EStructuralFeature.Setting>();
}
/**
* Return the collection of cross reference {@link org.eclipse.emf.ecore.EStructuralFeature.Setting settings}
* for the specified key (target object).
* @param key the key for the cross referencer's map.
* @return the collection of settings.
*/
protected Collection<EStructuralFeature.Setting> getCollection(Object key)
{
Collection<EStructuralFeature.Setting> result = get(key);
if (result == null)
{
put((EObject)key, result = newCollection());
}
return result;
}
/**
* Return a tree iterator over the content trees of this cross referencer's objects.
* @return a tree iterator over content trees.
*/
protected TreeIterator<Notifier> newContentsIterator()
{
return new ContentTreeIterator<Notifier>(emfObjects);
}
/**
* Compute the map of cross references.
*/
protected void crossReference()
{
for (TreeIterator<Notifier> contents = newContentsIterator(); contents.hasNext();)
{
Object content = contents.next();
if (content instanceof EObject)
{
EObject eObject = (EObject)content;
if (containment(eObject))
{
handleCrossReference(eObject);
}
else
{
contents.prune();
}
}
}
}
protected EContentsEList.FeatureIterator<EObject> getCrossReferences(EObject eObject)
{
return
(EContentsEList.FeatureIterator<EObject>)
(resolve() ?
eObject.eCrossReferences().iterator() :
((InternalEList<EObject>)eObject.eCrossReferences()).basicIterator());
}
protected void handleCrossReference(EObject eObject)
{
InternalEObject internalEObject = (InternalEObject)eObject;
for (EContentsEList.FeatureIterator<EObject> crossReferences = getCrossReferences(internalEObject); crossReferences.hasNext();)
{
EObject crossReferencedEObject = crossReferences.next();
if (crossReferencedEObject != null)
{
EReference eReference = (EReference)crossReferences.feature();
if (crossReference(internalEObject, eReference, crossReferencedEObject))
{
add(internalEObject, eReference, crossReferencedEObject);
}
}
}
}
protected void add(InternalEObject eObject, EReference eReference, EObject crossReferencedEObject)
{
getCollection(crossReferencedEObject).add(eObject.eSetting(eReference));
}
/**
* Reset this cross referencer's object set.
*/
protected void done()
{
emfObjects = null;
}
/**
* Returns a map of all cross references in the content tree.
* @param emfObjects a collection of objects whose combined content trees should be considered.
* @return a map of cross references.
*/
public static Map<EObject, Collection<EStructuralFeature.Setting>> find(Collection<?> emfObjects)
{
CrossReferencer result = new CrossReferencer(emfObjects);
result.crossReference();
result.done();
return result;
}
/**
* Returns a string representation of this cross referencer.
* @return the string representation.
*/
@Override
public String toString()
{
StringBuffer result = new StringBuffer("{"); // }
for (Map.Entry<EObject, Collection<EStructuralFeature.Setting>> entry : entrySet())
{
EObject eObject = entry.getKey();
result.append(getIdentification(eObject));
result.append("=[");
Collection<EStructuralFeature.Setting> collection = entry.getValue();
for (Iterator<EStructuralFeature.Setting> j = collection.iterator(); j.hasNext();)
{
EStructuralFeature.Setting setting = j.next();
EStructuralFeature eStructuralFeature = setting.getEStructuralFeature();
result.append(eStructuralFeature.getName());
result.append("<-");
result.append(getIdentification(setting.getEObject()));
if (j.hasNext())
{
result.append(", ");
}
}
result.append(']');
}
// {
result.append('}');
return result.toString();
}
/**
* Print the specified cross reference map to the specified stream.
* @param out the stream to print to.
* @param crossReferenceMap a map (cross referencer) to print.
*/
public static void print(PrintStream out, Map<EObject, Collection<EStructuralFeature.Setting>> crossReferenceMap)
{
out.println('{'); // }
for (Map.Entry<EObject, Collection<EStructuralFeature.Setting>> entry : crossReferenceMap.entrySet())
{
EObject eObject = entry.getKey();
out.print(" ");
out.print(getIdentification(eObject));
Collection<EStructuralFeature.Setting> collection = entry.getValue();
if (collection.isEmpty())
{
out.println(" =[]");
}
else
{
out.println(" =[");
for (Iterator<EStructuralFeature.Setting> j = collection.iterator(); j.hasNext();)
{
EStructuralFeature.Setting setting = j.next();
EStructuralFeature eStructuralFeature = setting.getEStructuralFeature();
out.print(" ");
out.print(eStructuralFeature.getName());
out.print("<-");
out.print(getIdentification(setting.getEObject()));
if (j.hasNext())
{
out.println(",");
}
}
out.println(']');
}
}
// {
out.println('}');
}
/**
* Print the specified collection of {@link org.eclipse.emf.ecore.EStructuralFeature.Setting settings}
* to the specified stream.
* @param out the stream to print to.
* @param settings a collection of settings.
*/
public static void print(PrintStream out, Collection<EStructuralFeature.Setting> settings)
{
if (settings.isEmpty())
{
out.println("[]");
}
else
{
out.println("[");
for (Iterator<EStructuralFeature.Setting> j = settings.iterator(); j.hasNext();)
{
EStructuralFeature.Setting setting = j.next();
EStructuralFeature eStructuralFeature = setting.getEStructuralFeature();
out.print(" ");
out.print(eStructuralFeature.getName());
out.print("<-");
out.print(getIdentification(setting.getEObject()));
if (j.hasNext())
{
out.println(",");
}
}
out.println(']');
}
}
}
/**
* A cross referencer that finds all references that are not contained within the content trees.
*/
public static class ExternalCrossReferencer extends CrossReferencer
{
private static final long serialVersionUID = 1L;
/**
* Creates an instance for the given collection of objects.
* @param emfObjects the collection of objects to cross reference.
*/
protected ExternalCrossReferencer(Collection<?> emfObjects)
{
super(emfObjects);
}
/**
* Creates an instance for the given object.
* @param eObject the object to cross reference.
*/
protected ExternalCrossReferencer(EObject eObject)
{
super(eObject);
}
/**
* Creates an instance for the given resource.
* @param resource the resource to cross reference.
*/
protected ExternalCrossReferencer(Resource resource)
{
super(Collections.singleton(resource));
}
/**
* Creates an instance for the given resource set.
* @param resourceSet the resource set to cross reference.
*/
protected ExternalCrossReferencer(ResourceSet resourceSet)
{
super(Collections.singleton(resourceSet));
}
/**
* Return true if the specified eReference from eObject to crossReferencedEObject should be
* considered a cross reference by this cross referencer.
* @param eObject an object in the cross referencer's content tree.
* @param eReference a reference from the object.
* @param crossReferencedEObject the target of the specified reference.
* @return if the cross referencer should consider the specified reference a cross reference.
*/
@Override
protected boolean crossReference(EObject eObject, EReference eReference, EObject crossReferencedEObject)
{
return !isAncestor(emfObjects, crossReferencedEObject);
}
/**
* Returns the map of external cross references for this cross referencer.
* @return a map of cross references.
*/
protected Map<EObject, Collection<EStructuralFeature.Setting>> findExternalCrossReferences()
{
crossReference();
done();
return this;
}
/**
* Returns a map of all external cross references from the specified content tree.
* @param eObject an object whose content trees should be considered.
* @return a map of cross references.
*/
public static Map<EObject, Collection<EStructuralFeature.Setting>> find(EObject eObject)
{
return new ExternalCrossReferencer(eObject).findExternalCrossReferences();
}
/**
* Returns a map of all external cross references from the specified content tree.
* @param resource a resource whose content tree should be considered.
* @return a map of cross references.
*/
public static Map<EObject, Collection<EStructuralFeature.Setting>> find(Resource resource)
{
return new ExternalCrossReferencer(resource).findExternalCrossReferences();
}
/**
* Returns a map of all external cross references from the specified content tree.
* @param resourceSet a resourceSet whose content tree should be considered.
* @return a map of cross references.
*/
public static Map<EObject, Collection<EStructuralFeature.Setting>> find(ResourceSet resourceSet)
{
return new ExternalCrossReferencer(resourceSet).findExternalCrossReferences();
}
/**
* Returns a map of all external cross references from the combined content trees of the specified collection of objects.
* @param emfObjectsToSearch a collection of objects whose combined content trees should be considered.
* @return a map of cross references.
*/
public static Map<EObject, Collection<EStructuralFeature.Setting>> find(Collection<?> emfObjectsToSearch)
{
return new ExternalCrossReferencer(emfObjectsToSearch).findExternalCrossReferences();
}
}
/**
* An iterator over {@link EStructuralFeature.Setting settings} that filters out the ones that aren't of interest.
* If an {@link EReference} is specified,
* the iterator will only yield settings with that as their {@link EStructuralFeature.Setting#getEStructuralFeature() feature}.
* If an {@link EClass} is specified,
* the iterator will only yield settings with an {@link EStructuralFeature.Setting#getEObject() object} of that type.
* Use {@link EcoreUtil.FilteredSettingsIterator} to yield just the settings themselves,
* or to affect the yielded values, extend this class and implement {@link #yield}.
* @since 2.5
*/
public static abstract class AbstractFilteredSettingsIterator<E> implements Iterator<E>
{
protected List<EStructuralFeature.Setting> list;
protected int size;
protected int index;
protected Iterator<EStructuralFeature.Setting> iterator;
protected EStructuralFeature.Setting preparedResult;
protected EReference eReference;
protected EClass eClass;
public AbstractFilteredSettingsIterator(List<EStructuralFeature.Setting> list, EReference eReference, EClass eClass)
{
if (list instanceof RandomAccess)
{
this.list = list;
size = list.size();
}
else
{
iterator = list.iterator();
}
this.eReference = eReference;
this.eClass = eClass;
}
public AbstractFilteredSettingsIterator(Collection<EStructuralFeature.Setting> collection, EReference eReference, EClass eClass)
{
if (collection instanceof RandomAccess)
{
list = (List<EStructuralFeature.Setting>)collection;
size = list.size();
}
else
{
iterator = collection.iterator();
}
this.eReference = eReference;
this.eClass = eClass;
}
public AbstractFilteredSettingsIterator(Iterator<EStructuralFeature.Setting> iterator, EReference eReference, EClass eClass)
{
this.iterator = iterator;
this.eReference = eReference;
this.eClass = eClass;
}
protected boolean isIncluded(EStructuralFeature.Setting setting)
{
return
(eReference == null || setting.getEStructuralFeature() == eReference) &&
(eClass == null || eClass.isInstance(setting.getEObject()));
}
public boolean hasNext()
{
if (preparedResult == null)
{
if (iterator == null)
{
while (index < size)
{
EStructuralFeature.Setting setting = list.get(index++);
if (isIncluded(setting))
{
preparedResult = setting;
return true;
}
}
}
else
{
while (iterator.hasNext())
{
EStructuralFeature.Setting setting = iterator.next();
if (isIncluded(setting))
{
preparedResult = setting;
return true;
}
}
}
return false;
}
else
{
return true;
}
}
public E next()
{
if (hasNext())
{
E result = yield(preparedResult);
preparedResult = null;
return result;
}
else
{
throw new NoSuchElementException();
}
}
protected abstract E yield(EStructuralFeature.Setting setting);
public void remove()
{
if (iterator == null)
{
list.remove(index - 1);
}
else
{
iterator.remove();
}
}
}
/**
* An iterator over {@link EStructuralFeature.Setting settings} that filters out the ones that aren't of interest.
* If an {@link EReference} is specified,
* the iterator will only yield settings with that as their {@link EStructuralFeature.Setting#getEStructuralFeature() feature}.
* If an {@link EClass} is specified,
* the iterator will only yield settings with an {@link EStructuralFeature.Setting#getEObject() object} of that type.
*/
public static class FilteredSettingsIterator extends AbstractFilteredSettingsIterator<EStructuralFeature.Setting>
{
public FilteredSettingsIterator(List<EStructuralFeature.Setting> list, EReference eReference, EClass eClass)
{
super(list, eReference, eClass);
}
public FilteredSettingsIterator(Collection<EStructuralFeature.Setting> collection, EReference eReference, EClass eClass)
{
super(collection, eReference, eClass);
}
public FilteredSettingsIterator(Iterator<EStructuralFeature.Setting> iterator, EReference eReference, EClass eClass)
{
super(iterator, eReference, eClass);
}
@Override
protected EStructuralFeature.Setting yield(EStructuralFeature.Setting setting)
{
return setting;
}
}
/**
* Returns <code>true</code> if <code>eObject1</code> and <code>eObject2</code> are {@link EqualityHelper equal},
* <code>false</code> otherwise.
* @return whether <code>eObject1</code> and <code>eObject2</code> are equal.
* @see EqualityHelper
* @since 2.1.0
*/
public static boolean equals(EObject eObject1, EObject eObject2)
{
EqualityHelper equalityHelper = new EqualityHelper();
return equalityHelper.equals(eObject1, eObject2);
}
/**
* Returns <code>true</code> if <code>eObjectList1</code> and <code>eObjectList2</code> contain {@link #equals(EObject, EObject) equal} objects.
* <code>false</code> otherwise.
* @return whether <code>eObjectList1</code> and <code>eObjectList2</code> contains equal objects
* @see EqualityHelper
* @see #equals(EObject, EObject)
* @since 2.8.0
*/
@SuppressWarnings("unchecked")
public static boolean equals(List<? extends EObject> eObjectList1, List<? extends EObject> eObjectList2)
{
EqualityHelper equalityHelper = new EqualityHelper();
return equalityHelper.equals((List<EObject>)eObjectList1, (List<EObject>)eObjectList2);
}
/**
* <p>
* A helper for determining whether two {@link EObject}s are <em>structurally equal</em>.
* Two EObjects, <code>eObject1</code> and <code>eObject2</code>, are structurally equal
* if their {@link EObject#eClass() classes} are the same,
* and if, for each {@link EStructuralFeature#isDerived non-derived} {@link EStructuralFeature feature} of the class,
* the {@link EObject#eIsSet(EStructuralFeature) isSet} states are the same
* and the corresponding {@link EObject#eGet(EStructuralFeature) values} are structurally equal
* as appropriate for the type of feature.
* For {@link FeatureMapUtil#isFeatureMap(EStructuralFeature) feature map} features,
* the {@link FeatureMap.Entry entries} at corresponding positions
* must have the same {@link FeatureMap.Entry#getEStructuralFeature() entry feature}s
* and must have structurally equal {@link FeatureMap.Entry#getValue() value}s
* as appropriate for the type of entry's feature.
* For {@link EReference reference} features,
* the corresponding values must recursively be structurally equal according to this definition.
* For {@link EAttribute attribute} features,
* the corresponding values must be equal according to Java equality.
* Note that container references are derived and hence are ignored.
* </p>
* <p>
* During the recursive process of determining {@link EcoreUtil#equals(EObject,EObject) equality},
* the helper instance is populated as a two way map
* such that a given <code>eObject1</code> is considered to be equal to at most one other <code>eObject2</code>,
* i.e., <code>get(eObject1) == eObject2 && get(eObject2) == eObject1</code>.
* While their features are being compared, the two objects are assumed to be equal:
*<pre>
* put(eObject1, eObject2);
* put(eObject2, eObject1);
*</pre>
* Once that correspondence is established, an <code>eObject1</code> considered equal to a different <code>eObject2</code>
* will not even be considered equal to itself.
* This ensures that two objects are structurally equal only if the graphs formed by all their referenced objects
* have the same topology.
* </p>
* @see EcoreUtil#equals(EObject, EObject)
* @see EqualityHelper#equals(EObject, EObject)
*/
public static class EqualityHelper extends HashMap<EObject, EObject>
{
private static final long serialVersionUID = 1L;
/**
* Returns whether <code>eObject1</code> and <code>eObject2</code> are {@link EqualityHelper equal}
* in the context of this helper instance.
* @return whether <code>eObject1</code> and <code>eObject2</code> are equal.
* @since 2.1.0
*/
public boolean equals(EObject eObject1, EObject eObject2)
{
// If the first object is null, the second object must be null.
//
if (eObject1 == null)
{
return eObject2 == null;
}
// We know the first object isn't null, so if the second one is, it can't be equal.
//
if (eObject2 == null)
{
return false;
}
// Both eObject1 and eObject2 are not null.
// If eObject1 has been compared already...
//
Object eObject1MappedValue = get(eObject1);
if (eObject1MappedValue != null)
{
// Then eObject2 must be that previous match.
//
return eObject1MappedValue == eObject2;
}
// If eObject2 has been compared already...
//
Object eObject2MappedValue = get(eObject2);
if (eObject2MappedValue != null)
{
// Then eObject1 must be that match.
//
return eObject2MappedValue == eObject1;
}
// Neither eObject1 nor eObject2 have been compared yet.
// If eObject1 and eObject2 are the same instance...
//
if (eObject1 == eObject2)
{
// Match them and return true.
//
put(eObject1, eObject2);
put(eObject2, eObject1);
return true;
}
// If eObject1 is a proxy...
//
if (eObject1.eIsProxy())
{
// Then the other object must be a proxy with the same URI.
//
if (((InternalEObject)eObject1).eProxyURI().equals(((InternalEObject)eObject2).eProxyURI()))
{
put(eObject1, eObject2);
put(eObject2, eObject1);
return true;
}
else
{
return false;
}
}
// If eObject1 isn't a proxy but eObject2 is, they can't be equal.
//
else if (eObject2.eIsProxy())
{
return false;
}
// If they don't have the same class, they can't be equal.
//
EClass eClass = eObject1.eClass();
if (eClass != eObject2.eClass())
{
return false;
}
// Assume from now on that they match.
//
put(eObject1, eObject2);
put(eObject2, eObject1);
// Check all the values.
//
for (int i = 0, size = eClass.getFeatureCount(); i < size; ++i)
{
// Ignore derived features.
//
EStructuralFeature feature = eClass.getEStructuralFeature(i);
if (!feature.isDerived())
{
if (!haveEqualFeature(eObject1, eObject2, feature))
{
remove(eObject1);
remove(eObject2);
return false;
}
}
}
// There's no reason they aren't equal, so they are.
//
return true;
}
/**
* Returns whether <code>list1</code> and <code>list2</code> contain
* {@link #equals(EObject, EObject) equal} {@link EObject}s at the same index.
* It is assumed that list1 and list2 only contain EObjects.
* @return whether <code>list1</code> and <code>list2</code> contain equal objects.
* @since 2.1.0
*/
public boolean equals(List<EObject> list1, List<EObject> list2)
{
int size = list1.size();
if (size != list2.size())
{
return false;
}
for (int i = 0; i < size; i++)
{
EObject eObject1 = list1.get(i);
EObject eObject2 = list2.get(i);
if (!equals(eObject1, eObject2))
{
return false;
}
}
return true;
}
/**
* Returns whether the two objects have {@link EqualityHelper equal}
* {@link EObject#eIsSet(EStructuralFeature) isSet} states and {@link EObject#eGet(EStructuralFeature) value}s for the feature.
* @return whether the two objects have equal isSet states and values for the feature.
* @since 2.2.0
* @see #equals(EObject, EObject)
* @see #equals(List, List)
*/
protected boolean haveEqualFeature(EObject eObject1, EObject eObject2, EStructuralFeature feature)
{
// If the set states are the same, and the values of the feature are the structurally equal, they are equal.
//
final boolean isSet1 = eObject1.eIsSet(feature);
final boolean isSet2 = eObject2.eIsSet(feature);
if (isSet1 && isSet2)
{
return
feature instanceof EReference ?
haveEqualReference(eObject1, eObject2, (EReference)feature) :
haveEqualAttribute(eObject1, eObject2, (EAttribute)feature);
}
else
{
return isSet1 == isSet2;
}
}
/**
* Returns whether the two objects have {@link EqualityHelper equal} {@link EObject#eGet(EStructuralFeature) value}s for the reference.
* @return whether the two objects have equal values for the reference.
* @since 2.1.0
* @see #equals(EObject, EObject)
* @see #equals(List, List)
*/
@SuppressWarnings("unchecked")
protected boolean haveEqualReference(EObject eObject1, EObject eObject2, EReference reference)
{
Object value1 = eObject1.eGet(reference);
Object value2 = eObject2.eGet(reference);
return
reference.isMany() ?
equals((List<EObject>)value1, (List<EObject>)value2) :
equals((EObject)value1, (EObject)value2);
}
/**
* Returns whether the two objects have {@link EqualityHelper equal} {@link EObject#eGet(EStructuralFeature) value}s for the attribute.
* @return whether the two objects have equal values for the attribute.
* @since 2.1.0
* @see #equalFeatureMaps(FeatureMap, FeatureMap)
*/
protected boolean haveEqualAttribute(EObject eObject1, EObject eObject2, EAttribute attribute)
{
Object value1 = eObject1.eGet(attribute);
Object value2 = eObject2.eGet(attribute);
// If the first value is null, the second value must be null.
//
if (value1 == null)
{
return value2 == null;
}
// Since the first value isn't null, if the second one is, they aren't equal.
//
if (value2 == null)
{
return false;
}
// If this is a feature map...
//
if (FeatureMapUtil.isFeatureMap(attribute))
{
// The feature maps must be equal.
//
FeatureMap featureMap1 = (FeatureMap)value1;
FeatureMap featureMap2 = (FeatureMap)value2;
return equalFeatureMaps(featureMap1, featureMap2);
}
else
{
// The values must be Java equal.
//
return equalValues(value1, value2);
}
}
/**
* Returns whether value1 and value2 are structurally equal.
* The default implementation only checks for Java equality.
* @param value1 the first non-null value.
* @param value2 the second potentially null value.
* @return whether value1 and value2 are structurally equal.
* @since 2.10
*/
protected boolean equalValues(Object value1, Object value2)
{
return value1.equals(value2);
}
/**
* Returns whether the two feature maps are {@link EqualityHelper equal}.
* @return whether the two feature maps are equal.
* @since 2.1.0
*/
protected boolean equalFeatureMaps(FeatureMap featureMap1, FeatureMap featureMap2)
{
// If they don't have the same size, the feature maps aren't equal.
//
int size = featureMap1.size();
if (size != featureMap2.size())
{
return false;
}
// Compare entries in order.
//
for (int i = 0; i < size; i++)
{
// If entries don't have the same feature, the feature maps aren't equal.
//
EStructuralFeature feature = featureMap1.getEStructuralFeature(i);
if (feature != featureMap2.getEStructuralFeature(i))
{
return false;
}
Object value1 = featureMap1.getValue(i);
Object value2 = featureMap2.getValue(i);
if (!equalFeatureMapValues(value1, value2, feature))
{
return false;
}
}
// There is no reason they aren't equals.
//
return true;
}
/**
* Returns whether the two values of a feature map are {@link EqualityHelper equal}.
* @return whether the two values of a feature map are equal.
* @since 2.2.0
*/
protected boolean equalFeatureMapValues(Object value1, Object value2, EStructuralFeature feature)
{
if (feature instanceof EReference)
{
// If the referenced EObjects aren't equal, the feature maps aren't equal.
//
return equals((EObject)value1, (EObject)value2);
}
else
{
// If the values aren't Java equal, the feature maps aren't equal.
//
return value1 == null ? value2 == null : equalValues(value1, value2);
}
}
} // EqualityHelper
/**
* A cross referencer that finds each usage of an EObject or collection of EObjects.
*/
public static class UsageCrossReferencer extends CrossReferencer
{
private static final long serialVersionUID = 1L;
/**
* The collection of usage target objects.
*/
protected Collection<?> eObjectsOfInterest;
/**
* Creates an instance for the given object.
* @param eObject the object to cross reference.
*/
protected UsageCrossReferencer(EObject eObject)
{
super(eObject);
}
/**
* Creates an instance for the given resource.
* @param resource the resource to cross reference.
*/
protected UsageCrossReferencer(Resource resource)
{
super(resource);
}
/**
* Creates an instance for the given resource set.
* @param resourceSet the resource set to cross reference.
*/
protected UsageCrossReferencer(ResourceSet resourceSet)
{
super(resourceSet);
}
/**
* Creates an instance for the given collection of objects.
* @param emfObjects the collection of objects to cross reference.
*/
protected UsageCrossReferencer(Collection<?> emfObjects)
{
super(emfObjects);
}
/**
* Return true if the specified eReference from eObject to crossReferencedEObject should be
* considered a cross reference by this cross referencer.
* @param eObject an object in the cross referencer's content tree.
* @param eReference a reference from the object.
* @param crossReferencedEObject the target of the specified reference.
* @return if the cross referencer should consider the specified reference a cross reference.
*/
@Override
protected boolean crossReference(EObject eObject, EReference eReference, EObject crossReferencedEObject)
{
return eObjectsOfInterest.contains(crossReferencedEObject);
}
/**
* Returns the collection of usage references to the specified object.
* @param eObject the usage target.
* @return a collection of cross references.
*/
protected Collection<EStructuralFeature.Setting> findUsage(EObject eObject)
{
eObjectsOfInterest = Collections.singleton(eObject);
crossReference();
this.eObjectsOfInterest = null;
done();
return getCollection(eObject);
}
/**
* Returns the map of usage references to objects in the specified collection.
* @param eObjectsOfInterest a collection of usage targets.
* @return a map of cross references.
*/
protected Map<EObject, Collection<EStructuralFeature.Setting>> findAllUsage(Collection<?> eObjectsOfInterest)
{
this.eObjectsOfInterest = eObjectsOfInterest;
crossReference();
this.eObjectsOfInterest = null;
done();
return this;
}
/**
* Returns a collection of usage references from the specified content tree.
* @param eObjectOfInterest the usage target.
* @param eObject an object whose content trees should be considered.
* @return a collection of cross references.
*/
public static Collection<EStructuralFeature.Setting> find(EObject eObjectOfInterest, EObject eObject)
{
return new UsageCrossReferencer(eObject).findUsage(eObjectOfInterest);
}
/**
* Returns a collection of usage references from the specified content tree.
* @param eObjectOfInterest the usage target.
* @param resource a resource whose content tree should be considered.
* @return a collection of cross references.
*/
public static Collection<EStructuralFeature.Setting> find(EObject eObjectOfInterest, Resource resource)
{
return new UsageCrossReferencer(resource).findUsage(eObjectOfInterest);
}
/**
* Returns a collection of usage references from the specified content tree.
* @param eObjectOfInterest the usage target.
* @param resourceSet a resource set whose content tree should be considered.
* @return a collection of cross references.
*/
public static Collection<EStructuralFeature.Setting> find(EObject eObjectOfInterest, ResourceSet resourceSet)
{
return new UsageCrossReferencer(resourceSet).findUsage(eObjectOfInterest);
}
/**
* Returns a collection of usage references from the combined content trees of the specified collection of objects.
* @param eObjectOfInterest the usage target.
* @param emfObjectsToSearch a collection of objects whose combined content trees should be considered.
* @return a collection of cross references.
*/
public static Collection<EStructuralFeature.Setting> find(EObject eObjectOfInterest, Collection<?> emfObjectsToSearch)
{
return new UsageCrossReferencer(emfObjectsToSearch).findUsage(eObjectOfInterest);
}
/**
* Returns a map of usage references from the specified content tree.
* @param eObjectsOfInterest a collection of usage targets.
* @param eObject an object whose content trees should be considered.
* @return a map of cross references.
*/
public static Map<EObject, Collection<EStructuralFeature.Setting>> findAll
(Collection<?> eObjectsOfInterest, EObject eObject)
{
return new UsageCrossReferencer(eObject).findAllUsage(eObjectsOfInterest);
}
/**
* Returns a map of usage references from the specified content tree.
* @param eObjectsOfInterest a collection of usage targets.
* @param resource a resource whose content tree should be considered.
* @return a map of cross references.
*/
public static Map<EObject, Collection<EStructuralFeature.Setting>> findAll
(Collection<?> eObjectsOfInterest, Resource resource)
{
return new UsageCrossReferencer(resource).findAllUsage(eObjectsOfInterest);
}
/**
* Returns a map of usage references from the specified content tree.
* @param eObjectsOfInterest a collection of usage targets.
* @param resourceSet a resource set whose content tree should be considered.
* @return a map of cross references.
*/
public static Map<EObject, Collection<EStructuralFeature.Setting>> findAll
(Collection<?> eObjectsOfInterest, ResourceSet resourceSet)
{
return new UsageCrossReferencer(resourceSet).findAllUsage(eObjectsOfInterest);
}
/**
* Returns a map of usage references from the combined content trees of the specified collection of objects.
* @param eObjectsOfInterest a collection of usage targets.
* @param emfObjectsToSearch a collection of objects whose combined content trees should be considered.
* @return a map of cross references.
*/
public static Map<EObject, Collection<EStructuralFeature.Setting>> findAll
(Collection<?> eObjectsOfInterest, Collection<?> emfObjectsToSearch)
{
return new UsageCrossReferencer(emfObjectsToSearch).findAllUsage(eObjectsOfInterest);
}
}
/**
* A cross referencer that finds proxies; the cross referencer will not cause proxies to be resolved.
*/
public static class ProxyCrossReferencer extends CrossReferencer
{
private static final long serialVersionUID = 1L;
/**
* Creates an instance for the given object.
* @param eObject the object to cross reference.
*/
protected ProxyCrossReferencer(EObject eObject)
{
super(eObject);
}
/**
* Creates an instance for the given resource.
* @param resource the resource to cross reference.
*/
protected ProxyCrossReferencer(Resource resource)
{
super(Collections.singleton(resource));
}
/**
* Creates an instance for the given resource set.
* @param resourceSet the resource set to cross reference.
*/
protected ProxyCrossReferencer(ResourceSet resourceSet)
{
super(Collections.singleton(resourceSet));
}
/**
* Creates an instance for the given collection of objects.
* @param emfObjects the collection of objects to cross reference.
*/
protected ProxyCrossReferencer(Collection<?> emfObjects)
{
super(emfObjects);
}
/**
* Return true if potential cross references that are proxies should be resolved.
* @return if the cross referencer should resolve proxies.
*/
@Override
protected boolean resolve()
{
return false;
}
/**
* Return true if the specified eReference from eObject to crossReferencedEObject should be
* considered a cross reference by this cross referencer.
* @param eObject an object in the cross referencer's content tree.
* @param eReference a reference from the object.
* @param crossReferencedEObject the target of the specified reference.
* @return if the cross referencer should consider the specified reference a cross reference.
*/
@Override
protected boolean crossReference(EObject eObject, EReference eReference, EObject crossReferencedEObject)
{
return crossReferencedEObject.eIsProxy();
}
/**
* Returns the map of proxy references for this cross referencer.
* @return a map of cross references.
*/
protected Map<EObject, Collection<EStructuralFeature.Setting>> findProxyCrossReferences()
{
crossReference();
done();
return this;
}
/**
* Returns a map of all proxy references from the specified content tree.
* @param eObject an object whose content trees should be considered.
* @return a map of cross references.
*/
public static Map<EObject, Collection<EStructuralFeature.Setting>> find(EObject eObject)
{
return new ProxyCrossReferencer(eObject).findProxyCrossReferences();
}
/**
* Returns a map of all proxy references from the specified content tree.
* @param resource a resource whose content tree should be considered.
* @return a map of cross references.
*/
public static Map<EObject, Collection<EStructuralFeature.Setting>> find(Resource resource)
{
return new ProxyCrossReferencer(resource).findProxyCrossReferences();
}
/**
* Returns a map of all proxy references from the specified content tree.
* @param resourceSet a resourceSet whose content tree should be considered.
* @return a map of cross references.
*/
public static Map<EObject, Collection<EStructuralFeature.Setting>> find(ResourceSet resourceSet)
{
return new ProxyCrossReferencer(resourceSet).findProxyCrossReferences();
}
/**
* Returns a map of all proxy references from the specified content tree.
* @param emfObjects a collection of objects whose combined content trees should be considered.
* @return a map of cross references.
*/
public static Map<EObject, Collection<EStructuralFeature.Setting>> find(Collection<?> emfObjects)
{
return new ProxyCrossReferencer(emfObjects).findProxyCrossReferences();
}
}
/**
* A cross referencer that finds proxies that cannot be resolved.
*/
public static class UnresolvedProxyCrossReferencer extends CrossReferencer
{
private static final long serialVersionUID = 1L;
/**
* Creates an instance for the given object.
* @param eObject the object to cross reference.
*/
protected UnresolvedProxyCrossReferencer(EObject eObject)
{
super(eObject);
}
/**
* Creates an instance for the given resource.
* @param resource the resource to cross reference.
*/
protected UnresolvedProxyCrossReferencer(Resource resource)
{
super(Collections.singleton(resource));
}
/**
* Creates an instance for the given resource set.
* @param resourceSet the resource set to cross reference.
*/
protected UnresolvedProxyCrossReferencer(ResourceSet resourceSet)
{
super(Collections.singleton(resourceSet));
}
/**
* Creates an instance for the given collection of objects.
* @param emfObjects the collection of objects to cross reference.
*/
protected UnresolvedProxyCrossReferencer(Collection<?> emfObjects)
{
super(emfObjects);
}
/**
* Return true if the specified eReference from eObject to crossReferencedEObject should be
* considiered a cross reference by this cross referencer.
* @param eObject an object in the cross referencer's content tree.
* @param eReference a reference from the object.
* @param crossReferencedEObject the target of the specified reference.
* @return if the cross referencer should consider the specified reference a cross reference.
*/
@Override
protected boolean crossReference(EObject eObject, EReference eReference, EObject crossReferencedEObject)
{
return crossReferencedEObject.eIsProxy();
}
/**
* Returns the map of unresolvable proxies for this cross referencer.
* @return a map of cross references.
*/
protected Map<EObject, Collection<EStructuralFeature.Setting>> findUnresolvedProxyCrossReferences()
{
crossReference();
done();
return this;
}
/**
* Returns a map of all unresolvable proxies from the specified content tree.
* @param eObject an object whose content trees should be considered.
* @return a map of cross references.
*/
public static Map<EObject, Collection<EStructuralFeature.Setting>> find(EObject eObject)
{
return new UnresolvedProxyCrossReferencer(eObject).findUnresolvedProxyCrossReferences();
}
/**
* Returns a map of all unresolvable proxies from the specified content tree.
* @param resource a resource whose content tree should be considered.
* @return a map of cross references.
*/
public static Map<EObject, Collection<EStructuralFeature.Setting>> find(Resource resource)
{
return new UnresolvedProxyCrossReferencer(resource).findUnresolvedProxyCrossReferences();
}
/**
* Returns a map of all unresolvable proxies from the specified content tree.
* @param resourceSet a resourceSet whose content tree should be considered.
* @return a map of cross references.
*/
public static Map<EObject, Collection<EStructuralFeature.Setting>> find(ResourceSet resourceSet)
{
return new UnresolvedProxyCrossReferencer(resourceSet).findUnresolvedProxyCrossReferences();
}
/**
* Returns a map of all unresolvable proxies from the specified content tree.
* @param emfObjects a collection of objects whose combined content trees should be considered.
* @return a map of cross references.
*/
public static Map<EObject, Collection<EStructuralFeature.Setting>> find(Collection<?> emfObjects)
{
return new UnresolvedProxyCrossReferencer(emfObjects).findUnresolvedProxyCrossReferences();
}
}
/**
* Returns a unique string identification of the eObject;
* it is structured as follows:
*<pre>
* &lt;java-class-name>[/&lt;dynamic-eClass-name>]@&lt;java-hex-hash-code>{&lt;uri-of-eObject>}
*</pre>
* @param eObject the object for which to get an identification.
* @return the identification string for the object.
*/
public static String getIdentification(EObject eObject)
{
StringBuffer result = new StringBuffer(eObject.getClass().getName());
EClass eClass = eObject.eClass();
if (eClass.getInstanceClassName() == null)
{
result.append('/');
result.append(eClass.getEPackage().getNsURI());
result.append('#');
result.append(eClass.getName());
}
result.append('@');
result.append(Integer.toHexString(eObject.hashCode()));
result.append('{');
result.append(getURI(eObject));
result.append('}');
return result.toString();
}
/**
* Returns a URI for the eObject,
* i.e., either
* the {@link InternalEObject#eProxyURI() proxy URI},
* the URI of the {@link EObject#eResource() resource} with the {@link Resource#getURIFragment(EObject) fragment} produced by the resource,
* or the URI consisting of just the {@link #getRelativeURIFragmentPath(EObject, EObject) fragment path} that would be produced by a default Resource
* with the eObject as its only contents.
* @param eObject the object for which to get the URI.
* @return the URI for the object.
*/
public static URI getURI(EObject eObject)
{
// If it's a proxy, use that.
//
URI proxyURI = ((InternalEObject)eObject).eProxyURI();
if (proxyURI != null)
{
return proxyURI;
}
else
{
// If it is in a resource, form the URI relative to that resource.
//
Resource resource = eObject.eResource();
if (resource != null)
{
URI uri = resource.getURI();
String uriFragment = resource.getURIFragment(eObject);
return uri == null ? URI.createURI("#" + uriFragment) : uri.appendFragment(uriFragment);
}
else
{
String id = EcoreUtil.getID(eObject);
if (id != null)
{
return URI.createURI("#" + id);
}
else
{
return URI.createURI("#//" + getRelativeURIFragmentPath(null, eObject, false));
}
}
}
}
/**
* Returns the fragment path of the descendant object relative to its {@link #isAncestor(EObject, EObject) ancestor}.
* The ancestor may be <code>null</code>, it which case the path is relative to the {@link #getRootContainer(EObject) root}.
* Otherwise, the resulting fragment path can be passed to {@link #getEObject(EObject, String)} along with the ancestor to the yield the descendant.
* @param ancestorEObject the ancestor of the descendant object (can be null)
* @param descendantEObject descendant of the ancestor object
* @return the relativefragment path.
* @see InternalEObject#eURIFragmentSegment(EStructuralFeature, EObject)
* @see #getEObject(EObject, String)
* @throws IllegalArgumentException if the ancestor is non-null and is not an ancestor of the descendant.
* @since 2.10
*/
public static String getRelativeURIFragmentPath(EObject ancestorEObject, EObject descendantEObject)
{
return getRelativeURIFragmentPath(ancestorEObject, descendantEObject, true);
}
private static String getRelativeURIFragmentPath(EObject ancestorEObject, EObject descendantEObject, boolean resolve)
{
if (ancestorEObject == descendantEObject)
{
return "";
}
List<String> uriFragmentPath = new ArrayList<String>();
HashSet<InternalEObject> visited = new HashSet<InternalEObject>();
InternalEObject internalEObject = (InternalEObject)descendantEObject;
for (InternalEObject container = resolve ? (InternalEObject)internalEObject.eContainer() : internalEObject.eInternalContainer();
container != null && visited.add(container);
container = resolve ? (InternalEObject)internalEObject.eContainer() : internalEObject.eInternalContainer())
{
uriFragmentPath.add(container.eURIFragmentSegment(internalEObject.eContainingFeature(), internalEObject));
internalEObject = container;
if (container == ancestorEObject)
{
break;
}
}
if (internalEObject != ancestorEObject && ancestorEObject != null)
{
throw new IllegalArgumentException("The ancestor '" + ancestorEObject + "' is not an ancestor of '" + descendantEObject + "'");
}
StringBuilder result = new StringBuilder();
int size = uriFragmentPath.size();
if (size > 0)
{
for (int i = uriFragmentPath.size() - 1; i > 0; --i)
{
result.append(uriFragmentPath.get(i));
result.append('/');
}
result.append(uriFragmentPath.get(0));
}
return result.toString();
}
/**
* Returns the object reached via by navigating the relative URI fragment path.
* @param rootEObject
* @param relativeFragmentPath
* @return the object at the path.
* @see #getRelativeURIFragmentPath(EObject, EObject)
* @see InternalEObject#eObjectForURIFragmentSegment(String)
* @since 2.10
*/
public static EObject getEObject(EObject rootEObject, String relativeFragmentPath)
{
String[] segments = SegmentSequence.create("/", relativeFragmentPath).segments();
int size = segments.length;
EObject eObject = rootEObject;
for (int i = 0; i < size && eObject != null; ++i)
{
eObject = ((InternalEObject)eObject).eObjectForURIFragmentSegment(segments[i]);
}
return eObject;
}
/**
* Searches for the first occurrence of the given argument in list starting from
* a specified index. The equality is tested using the operator <tt>==<tt> and
* the <tt>equals</tt> method.
* @param list
* @param o an object (can be null)
* @param fromIndex
* @return the index of the first occurrence of the argument in this
* list (where index>=fromIndex); returns <tt>-1</tt> if the
* object is not found.
* @deprecated replaced by {@link ECollections#indexOf(List, Object, int)} in 2.1.0
*/
@Deprecated
public static int indexOf(List<?> list, Object o, int fromIndex)
{
return ECollections.indexOf(list, o, fromIndex);
}
/**
* Sets the <code>eList</code>'s contents and order to be exactly that of the <code>prototype</code> collection.
* This implementation minimizes the number of notifications the operation will produce.
* Objects already in the list will be moved, missing objects will be added, and extra objects will be removed.
* If <code>eList</code>'s contents and order are already exactly that of the <code>prototype</code> collection,
* no change will be made.
* @param eList the list to set.
* @param prototypeCollection the collection representing the desired content and order.
* @deprecated replaced by {@link ECollections#setEList(EList, List)} in 2.1.0
*/
@Deprecated
public static <T> void setEList(EList<T> eList, Collection<? extends T> prototypeCollection)
{
ECollections.setEList(eList, new ArrayList<T>(prototypeCollection));
}
/**
* Sets the <code>eList</code>'s contents and order to be exactly that of the <code>prototype</code> list.
* This implementation minimizes the number of notifications the operation will produce.
* Objects already in the list will be moved, missing objects will be added, and extra objects will be removed.
* If <code>eList</code>'s contents and order are already exactly that of the <code>prototype</code> list,
* no change will be made.
* @param eList the list to set.
* @param prototypeList the list representing the desired content and order.
* @deprecated replaced by {@link ECollections#setEList(EList, List)} in 2.1.0
*/
@Deprecated
public static <T> void setEList(EList<T> eList, List<? extends T> prototypeList)
{
ECollections.setEList(eList, prototypeList);
}
/**
* Removes the value from the setting.
* @param setting the setting holding the value.
* @param value the value to remove.
*/
public static void remove(EStructuralFeature.Setting setting, Object value)
{
if (FeatureMapUtil.isMany(setting.getEObject(), setting.getEStructuralFeature()))
{
((List<?>)setting.get(false)).remove(value);
}
else
{
setting.unset();
}
}
/**
* Replaces the old value in the setting with the new value.
* @param setting the setting holding the values.
* @param oldValue the value to replace.
* @param newValue the replacement value.
*/
public static void replace(EStructuralFeature.Setting setting, Object oldValue, Object newValue)
{
if (FeatureMapUtil.isMany(setting.getEObject(), setting.getEStructuralFeature()))
{
@SuppressWarnings("unchecked") List<Object> list = (List<Object>)setting.get(false);
list.set(list.indexOf(oldValue), newValue);
}
else
{
setting.set(newValue);
}
}
/**
* Removes the value from the feature of the object.
* @param eObject the object holding the value.
* @param eStructuralFeature the feature of the object holding the value.
* @param value the value to remove.
*/
public static void remove(EObject eObject, EStructuralFeature eStructuralFeature, Object value)
{
if (FeatureMapUtil.isMany(eObject, eStructuralFeature))
{
((List<?>)eObject.eGet(eStructuralFeature)).remove(value);
}
else
{
eObject.eUnset(eStructuralFeature);
}
}
/**
* Replaces the old value in the object's feature with the new value.
* @param eObject the object holding the values.
* @param eStructuralFeature the feature of the object holding the values.
* @param oldValue the value to replace.
* @param newValue the replacement value.
*/
public static void replace(EObject eObject, EStructuralFeature eStructuralFeature, Object oldValue, Object newValue)
{
if (FeatureMapUtil.isMany(eObject, eStructuralFeature))
{
@SuppressWarnings("unchecked") List<Object> list = (List<Object>)eObject.eGet(eStructuralFeature);
list.set(list.indexOf(oldValue), newValue);
}
else
{
eObject.eSet(eStructuralFeature, newValue);
}
}
/**
* Removes the object from its {@link EObject#eResource containing} resource
* and/or its {@link EObject#eContainer containing} object.
* @param eObject the object to remove.
*/
public static void remove(EObject eObject)
{
InternalEObject internalEObject = (InternalEObject)eObject;
EObject container = internalEObject.eInternalContainer();
if (container != null)
{
EReference feature = eObject.eContainmentFeature();
if (FeatureMapUtil.isMany(container, feature))
{
((EList<?>)container.eGet(feature)).remove(eObject);
}
else
{
container.eUnset(feature);
}
}
Resource resource = internalEObject.eDirectResource();
if (resource != null)
{
resource.getContents().remove(eObject);
}
}
/**
* Replace the object in its {@link EObject#eResource containing} resource
* and/or its {@link EObject#eContainer containing} object,
* with the replacement object.
* @param eObject the object to replace.
* @param replacementEObject the replacement object.
*/
public static void replace(EObject eObject, EObject replacementEObject)
{
EObject container = eObject.eContainer();
if (container != null)
{
EReference feature = eObject.eContainmentFeature();
if (FeatureMapUtil.isMany(container, feature))
{
@SuppressWarnings("unchecked") List<Object> list = (List<Object>)container.eGet(feature);
list.set(list.indexOf(eObject), replacementEObject);
}
else
{
container.eSet(feature, replacementEObject);
}
}
Resource resource = ((InternalEObject)eObject).eDirectResource();
if (resource != null)
{
List<EObject> list = resource.getContents();
list.set(list.indexOf(eObject), replacementEObject);
}
}
/**
* Deletes the object from its {@link EObject#eResource containing} resource
* and/or its {@link EObject#eContainer containing} object
* as well as from any other feature that references it
* within the enclosing resource set, resource, or root object.
* @param eObject the object to delete.
* @since 2.3
*/
public static void delete(EObject eObject)
{
EObject rootEObject = getRootContainer(eObject);
Resource resource = rootEObject.eResource();
Collection<EStructuralFeature.Setting> usages;
if (resource == null)
{
usages = UsageCrossReferencer.find(eObject, rootEObject);
}
else
{
ResourceSet resourceSet = resource.getResourceSet();
if (resourceSet == null)
{
usages = UsageCrossReferencer.find(eObject, resource);
}
else
{
usages = UsageCrossReferencer.find(eObject, resourceSet);
}
}
for (EStructuralFeature.Setting setting : usages)
{
if (setting.getEStructuralFeature().isChangeable())
{
remove(setting, eObject);
}
}
remove(eObject);
}
/**
* Deletes the object from its {@link EObject#eResource containing} resource
* and/or its {@link EObject#eContainer containing} object
* as well as from any other feature that references it
* within the enclosing resource set, resource, or root object.
* If recursive true, contained children of the object that are in the same resource
* are similarly removed from any features that references them.
* @param eObject the object to delete.
* @param recursive whether references to contained children should also be removed.
* @since 2.4
*/
public static void delete(EObject eObject, boolean recursive)
{
if (recursive)
{
EObject rootEObject = getRootContainer(eObject);
Resource resource = rootEObject.eResource();
Set<EObject> eObjects = new HashSet<EObject>();
Set<EObject> crossResourceEObjects = new HashSet<EObject>();
eObjects.add(eObject);
for (@SuppressWarnings("unchecked") TreeIterator<InternalEObject> j = (TreeIterator<InternalEObject>)(TreeIterator<?>)eObject.eAllContents(); j.hasNext(); )
{
InternalEObject childEObject = j.next();
if (childEObject.eDirectResource() != null)
{
crossResourceEObjects.add(childEObject);
}
else
{
eObjects.add(childEObject);
}
}
Map<EObject, Collection<EStructuralFeature.Setting>> usages;
if (resource == null)
{
usages = UsageCrossReferencer.findAll(eObjects, rootEObject);
}
else
{
ResourceSet resourceSet = resource.getResourceSet();
if (resourceSet == null)
{
usages = UsageCrossReferencer.findAll(eObjects, resource);
}
else
{
usages = UsageCrossReferencer.findAll(eObjects, resourceSet);
}
}
for (Map.Entry<EObject, Collection<EStructuralFeature.Setting>> entry : usages.entrySet())
{
EObject deletedEObject = entry.getKey();
Collection<EStructuralFeature.Setting> settings = entry.getValue();
for (EStructuralFeature.Setting setting : settings)
{
if (!eObjects.contains(setting.getEObject()) && setting.getEStructuralFeature().isChangeable())
{
remove(setting, deletedEObject);
}
}
}
remove(eObject);
for (EObject crossResourceEObject : crossResourceEObjects)
{
remove(crossResourceEObject.eContainer(), crossResourceEObject.eContainmentFeature(), crossResourceEObject);
}
}
else
{
delete(eObject);
}
}
/**
* Creates an instance of the class.
* @param eClass the class to instantiate.
* @return an instance of the class.
*/
public static EObject create(EClass eClass)
{
return eClass.getEPackage().getEFactoryInstance().create(eClass);
}
/**
* Creates an instance of the datatype.
* @param eDataType the datatype to instantiate.
* @param literal the string value of the datatype.
* @return an instance of the datatype.
* @see #convertToString(EDataType, Object)
*/
public static Object createFromString(EDataType eDataType, String literal)
{
return eDataType.getEPackage().getEFactoryInstance().createFromString(eDataType, literal);
}
/**
* Converts an instance of the data type to a string literal representation.
* @param eDataType the data type to instantiate.
* @param value a value of the data type.
* @return the string literal representation of the value.
* @see #createFromString(EDataType, String)
*/
public static String convertToString(EDataType eDataType, Object value)
{
return eDataType.getEPackage().getEFactoryInstance().convertToString(eDataType, value);
}
/**
* Returns the value of the object's ID attribute as a String.
* If the object has no ID attribute or the ID attribute is not set, it returns <code>null</code>.
* @param eObject the object in question.
* @return the value of the object's ID attribute as a String.
* @see org.eclipse.emf.ecore.EAttribute#isID
* @see org.eclipse.emf.ecore.EClass#getEIDAttribute
* @see #setID(EObject, String)
*/
public static String getID(EObject eObject)
{
EClass eClass = eObject.eClass();
EAttribute eIDAttribute = eClass.getEIDAttribute();
return eIDAttribute == null || !eObject.eIsSet(eIDAttribute) ? null : convertToString(
eIDAttribute.getEAttributeType(),
eObject.eGet(eIDAttribute));
}
/**
* Sets the value of the object's ID attribute according to the value represented by the String.
* A <code>null</code> ID will unset the attribute rather than setting it to <code>null</code>.
* @param eObject the object in question.
* @param id the String value of the new ID.
* @throws IllegalArgumentException if the object has no ID attribute.
* @see #getID(EObject)
* @see org.eclipse.emf.ecore.EAttribute#isID
* @see org.eclipse.emf.ecore.EClass#getEIDAttribute
*/
public static void setID(EObject eObject, String id)
{
EClass eClass = eObject.eClass();
EAttribute eIDAttribute = eClass.getEIDAttribute();
if (eIDAttribute == null)
{
throw new IllegalArgumentException("The object doesn't have an ID feature.");
}
else if (id == null)
{
eObject.eUnset(eIDAttribute);
}
else
{
eObject.eSet(eIDAttribute, createFromString(eIDAttribute.getEAttributeType(), id));
}
}
/**
* Returns the wrapper class for the primitive class, or the original class, if it's not a primitive class.
* @param javaClass
*/
public static Class<?> wrapperClassFor(Class<?> javaClass)
{
if (javaClass == null)
{
return null;
}
else if (javaClass.isPrimitive())
{
if (javaClass == Boolean.TYPE)
{
return Boolean.class;
}
else if (javaClass == Integer.TYPE)
{
return Integer.class;
}
else if (javaClass == Float.TYPE)
{
return Float.class;
}
else if (javaClass == Double.TYPE)
{
return Double.class;
}
else if (javaClass == Long.TYPE)
{
return Long.class;
}
else if (javaClass == Short.TYPE)
{
return Short.class;
}
else if (javaClass == Byte.TYPE)
{
return Byte.class;
}
else
// if (javaClass == Character.TYPE)
{
return Character.class;
}
}
else
{
return javaClass;
}
}
protected static final String GEN_MODEL_PACKAGE_NS_URI = "http://www.eclipse.org/emf/2002/GenModel";
public static String getDocumentation(EModelElement eModelElement)
{
EAnnotation eAnnotation = eModelElement.getEAnnotation(GEN_MODEL_PACKAGE_NS_URI);
return eAnnotation == null ? null : (String)eAnnotation.getDetails().get("documentation");
}
public static void setDocumentation(EModelElement eModelElement, String documentation)
{
EAnnotation eAnnotation = eModelElement.getEAnnotation(GEN_MODEL_PACKAGE_NS_URI);
if (documentation == null)
{
if (eAnnotation != null)
{
eAnnotation.getDetails().removeKey("documentation");
}
}
else
{
if (eAnnotation == null)
{
eAnnotation = EcoreFactory.eINSTANCE.createEAnnotation();
eAnnotation.setSource(GEN_MODEL_PACKAGE_NS_URI);
eModelElement.getEAnnotations().add(eAnnotation);
}
eAnnotation.getDetails().put("documentation", documentation);
}
}
public static List<String> getConstraints(EModelElement eModelElement)
{
EAnnotation eAnnotation = eModelElement.getEAnnotation(EcorePackage.eNS_URI);
if (eAnnotation != null)
{
String constraints = eAnnotation.getDetails().get("constraints");
if (constraints != null)
{
List<String> result = new ArrayList<String>();
for (StringTokenizer stringTokenizer = new StringTokenizer(constraints); stringTokenizer.hasMoreTokens();)
{
String constraint = stringTokenizer.nextToken();
result.add(constraint);
}
return result;
}
}
return Collections.emptyList();
}
public static void setConstraints(EModelElement eModelElement, List<String> constraints)
{
EAnnotation eAnnotation = eModelElement.getEAnnotation(EcorePackage.eNS_URI);
if (constraints == null || constraints.isEmpty())
{
if (eAnnotation != null)
{
eAnnotation.getDetails().removeKey("constraints");
}
}
else
{
if (eAnnotation == null)
{
eAnnotation = EcoreFactory.eINSTANCE.createEAnnotation();
eAnnotation.setSource(EcorePackage.eNS_URI);
eModelElement.getEAnnotations().add(eAnnotation);
}
StringBuffer value = new StringBuffer();
for (Iterator<String> i = constraints.iterator(); i.hasNext();)
{
value.append(i.next());
if (i.hasNext())
{
value.append(' ');
}
}
eAnnotation.getDetails().put("constraints", value.toString());
}
}
public static String getAnnotation(EModelElement eModelElement, String sourceURI, String key)
{
EAnnotation eAnnotation = eModelElement.getEAnnotation(sourceURI);
return eAnnotation == null ? null : (String)eAnnotation.getDetails().get(key);
}
public static void setAnnotation(EModelElement eModelElement, String sourceURI, String key, String value)
{
EAnnotation eAnnotation = eModelElement.getEAnnotation(sourceURI);
if (value == null)
{
if (eAnnotation != null)
{
eAnnotation.getDetails().removeKey(key);
}
}
else
{
if (eAnnotation == null)
{
eAnnotation = EcoreFactory.eINSTANCE.createEAnnotation();
eAnnotation.setSource(sourceURI);
eModelElement.getEAnnotations().add(eAnnotation);
}
eAnnotation.getDetails().put(key, value);
}
}
/**
* Identifier for the get accessor.
* @see #isSuppressedVisibility(EStructuralFeature, int)
* @see #setSuppressedVisibility(EStructuralFeature, int, boolean)
* @since 2.1
*/
public static final int GET = 0;
/**
* Identifier for the set accessor.
* @see #isSuppressedVisibility(EStructuralFeature, int)
* @see #setSuppressedVisibility(EStructuralFeature, int, boolean)
* @since 2.1
*/
public static final int SET = 1;
/**
* Identifier for the isSet accessor.
* @see #isSuppressedVisibility(EStructuralFeature, int)
* @see #setSuppressedVisibility(EStructuralFeature, int, boolean)
* @since 2.1
*/
public static final int IS_SET = 2;
/**
* Identifier for the unset accessor.
* @see #isSuppressedVisibility(EStructuralFeature, int)
* @see #setSuppressedVisibility(EStructuralFeature, int, boolean)
* @since 2.1
*/
public static final int UNSET = 3;
// Keys that will be used to record visibility for the accessors.
//
static final String[] ACCESSOR_KEYS =
{
"suppressedGetVisibility",
"suppressedSetVisibility",
"suppressedIsSetVisibility",
"suppressedUnsetVisibility"
};
// Value used to suppress visibility.
//
static final String TRUE = "true";
/**
* Tests whether the given structural feature has been annotated to prevent generation of accessor methods in its
* interface.
* @param eStructuralFeature the structural feature
* @param accessor the type of accessor method, one of {@link #GET}, {@link #SET}, {@link #IS_SET}, or {@link #UNSET}
* @return whether the specified accessor's visibility is suppressed
* @since 2.1
*/
public static boolean isSuppressedVisibility(EStructuralFeature eStructuralFeature, int accessor)
{
if (accessor < GET || accessor > UNSET) throw new IllegalArgumentException("Invalid accessor identifier: " + accessor);
EAnnotation eAnnotation = eStructuralFeature.getEAnnotation(GEN_MODEL_PACKAGE_NS_URI);
return eAnnotation == null ? false : TRUE.equalsIgnoreCase(eAnnotation.getDetails().get(ACCESSOR_KEYS[accessor]));
}
/**
* Sets or removes annotations on the given structural feature to prevent generation of accessor methods in its interface.
* @param eStructuralFeature the structural feature
* @param accessor the type of accessor method, one of {@link #GET}, {@link #SET}, {@link #IS_SET}, or {@link #UNSET}
* @param suppress whether the specified accessor's visibility should be suppressed
* @since 2.1
*/
public static void setSuppressedVisibility(EStructuralFeature eStructuralFeature, int accessor, boolean suppress)
{
if (accessor < GET || accessor > UNSET) throw new IllegalArgumentException("Invalid accessor identifier: " + accessor);
EAnnotation eAnnotation = eStructuralFeature.getEAnnotation(GEN_MODEL_PACKAGE_NS_URI);
if (!suppress)
{
if (eAnnotation != null)
{
eAnnotation.getDetails().removeKey(ACCESSOR_KEYS[accessor]);
}
}
else
{
if (eAnnotation == null)
{
eAnnotation = EcoreFactory.eINSTANCE.createEAnnotation();
eAnnotation.setSource(GEN_MODEL_PACKAGE_NS_URI);
eStructuralFeature.getEAnnotations().add(eAnnotation);
}
eAnnotation.getDetails().put(ACCESSOR_KEYS[accessor], TRUE);
}
}
static final String OPERATION_VISIBILITY_KEY = "suppressedVisibility";
/**
* Tests whether the given operation has been annotated to prevent generation of a method declaration in its interface.
* @param eOperation the operation.
* @return whether the visibility is suppressed
* @since 2.4
*/
public static boolean isSuppressedVisibility(EOperation eOperation)
{
EAnnotation eAnnotation = eOperation.getEAnnotation(GEN_MODEL_PACKAGE_NS_URI);
return eAnnotation == null ? false : TRUE.equalsIgnoreCase(eAnnotation.getDetails().get(OPERATION_VISIBILITY_KEY));
}
/**
* Sets or removes the annotation on the given operation to prevent generation of a method declaration in its interface.
* @param eOperation the operation.
* @param suppress whether the visibility should be suppressed
* @since 2.4
*/
public static void setSuppressedVisibility(EOperation eOperation, boolean suppress)
{
EAnnotation eAnnotation = eOperation.getEAnnotation(GEN_MODEL_PACKAGE_NS_URI);
if (!suppress)
{
if (eAnnotation != null)
{
eAnnotation.getDetails().removeKey(OPERATION_VISIBILITY_KEY);
}
}
else
{
if (eAnnotation == null)
{
eAnnotation = EcoreFactory.eINSTANCE.createEAnnotation();
eAnnotation.setSource(GEN_MODEL_PACKAGE_NS_URI);
eOperation.getEAnnotations().add(eAnnotation);
}
eAnnotation.getDetails().put(OPERATION_VISIBILITY_KEY, TRUE);
}
}
/**
* Generates a universally unique identifier,
* i.e., a <a href="http://www.ietf.org/rfc/rfc4122.txt">UUID</a>.
* It encodes the 128 bit UUID in <a href="http://www.ietf.org/rfc/rfc2045.txt">base 64</a>,
* but rather than padding the encoding with two "=" characters,
* it prefixes the encoding with a single "_" character,
* to ensure that the result is a valid <a href="http://www.w3.org/TR/xmlschema-2/#ID">ID</a>,
* i.e., an <a href="http://www.w3.org/TR/1999/REC-xml-names-19990114/#NT-NCName">NCName</a>
* @return a universally unique identifier.
*/
public static String generateUUID()
{
return UUID.generate();
}
/**
* Generates a universally unique identifier,
* i.e., a <a href="http://tools.ietf.org/id/draft-mealling-uuid-urn-02.txt">UUID</a>.
* The argument is filled in with the 128 bit UUID and hence must be at least 16 bytes in length.
* @param uuid the value to receive the result.
*/
public static void generateUUID(byte [] uuid)
{
UUID.generate(uuid);
}
private static final class UUID
{
public synchronized static String generate()
{
updateCurrentTime();
// Do a base 64 conversion by turning every 3 bytes into 4 base 64 characters
//
for (int i = 0; i < 5; ++i)
{
buffer[4 * i + 1] = BASE64_DIGITS[(uuid[i * 3] >> 2) & 0x3F];
buffer[4 * i + 2] = BASE64_DIGITS[((uuid[i * 3] << 4) & 0x30) | ((uuid[i * 3 + 1] >> 4) & 0xF)];
buffer[4 * i + 3] = BASE64_DIGITS[((uuid[i * 3 + 1] << 2) & 0x3C) | ((uuid[i * 3 + 2] >> 6) & 0x3)];
buffer[4 * i + 4] = BASE64_DIGITS[uuid[i * 3 + 2] & 0x3F];
}
// Handle the last byte at the end.
//
buffer[21] = BASE64_DIGITS[(uuid[15] >> 2) & 0x3F];
buffer[22] = BASE64_DIGITS[(uuid[15] << 4) & 0x30];
return new String(buffer);
}
public synchronized static void generate(byte [] uuid)
{
updateCurrentTime();
for (int i = 0; i < 16; i++)
{
uuid[i] = UUID.uuid[i];
}
}
private UUID()
{
super();
}
private static final char[] BASE64_DIGITS = {
'A',
'B',
'C',
'D',
'E',
'F',
'G',
'H',
'I',
'J',
'K',
'L',
'M',
'N',
'O',
'P',
'Q',
'R',
'S',
'T',
'U',
'V',
'W',
'X',
'Y',
'Z',
'a',
'b',
'c',
'd',
'e',
'f',
'g',
'h',
'i',
'j',
'k',
'l',
'm',
'n',
'o',
'p',
'q',
'r',
's',
't',
'u',
'v',
'w',
'x',
'y',
'z',
'0',
'1',
'2',
'3',
'4',
'5',
'6',
'7',
'8',
'9',
'-',
'_' };
/**
* An adjustment to convert the Java epoch of Jan 1, 1970 00:00:00 to
* the epoch required by the IETF specification, Oct 15, 1582 00:00:00.
*/
private static final long EPOCH_ADJUSTMENT = new GregorianCalendar(1970, 0, 1, 0, 0, 0).getTime().getTime()
- new GregorianCalendar(1582, 9, 15, 0, 0, 0).getTime().getTime();
private static long lastTime = System.currentTimeMillis() + EPOCH_ADJUSTMENT;
private static short clockSequence;
private static short timeAdjustment;
private static int sleepTime = 1;
/**
* A cached array of bytes representing the UUID. The second 8 bytes
* will be kept the same unless the clock sequence has changed.
*/
private static final byte[] uuid = new byte [16];
private static final char[] buffer = new char [23];
static
{
Random random = new SecureRandom();
clockSequence = (short)random.nextInt(16384);
updateClockSequence();
// Generate a 48 bit node identifier;
// This is an alternative to the IEEE 802 host address, which is not available in Java.
//
byte[] nodeAddress = new byte [6];
random.nextBytes(nodeAddress);
// Set the most significant bit of the first octet to 1 so as to distinguish it from IEEE node addresses
//
nodeAddress[0] |= (byte)0x80;
// The node identifier is already in network byte order,
// so there is no need to do any byte order reversing.
//
for (int i = 0; i < 6; ++i)
{
uuid[i + 10] = nodeAddress[i];
}
buffer[0] = '_';
}
/**
* Updates the clock sequence portion of the UUID. The clock sequence
* portion may seem odd, but in the specification, the high order byte
* comes before the low order byte. The variant is multiplexed into the
* high order octet of clockseq_hi.
*/
private static void updateClockSequence()
{
// clockseq_hi
uuid[8] = (byte)(((clockSequence >> 8) & 0x3F) | 0x80);
// clockseq_low
uuid[9] = (byte)(clockSequence & 0xFF);
}
/**
* Updates the UUID with the current time, compensating for the fact
* that the clock resolution may be less than 100 ns. The byte array
* will have its first eight bytes populated with the time in the
* correct sequence of bytes, as per the specification.
*/
private static void updateCurrentTime()
{
// Get the current time in milliseconds since the epoch
// and adjust it to match the epoch required by the specification.
//
long currentTime = System.currentTimeMillis() + EPOCH_ADJUSTMENT;
if (lastTime > currentTime)
{
// The system clock has been rewound so the clock sequence must be incremented
// to ensure that a duplicate UUID is not generated.
//
++clockSequence;
if (16384 == clockSequence)
{
clockSequence = 0;
}
updateClockSequence();
}
else if (lastTime == currentTime)
{
// The system time hasn't changed so add some increment of 100s of nanoseconds to guarantee uniqueness.
//
++timeAdjustment;
if (timeAdjustment > 9999)
{
// Wait so that the clock can catch up and the time adjustment won't overflow.
try
{
Thread.sleep(sleepTime);
}
catch (InterruptedException exception)
{
// We just woke up.
}
timeAdjustment = 0;
currentTime = System.currentTimeMillis() + EPOCH_ADJUSTMENT;
while (lastTime == currentTime)
{
try
{
++sleepTime;
Thread.sleep(1);
}
catch (InterruptedException exception)
{
// We just woke up.
}
currentTime = System.currentTimeMillis() + EPOCH_ADJUSTMENT;
}
}
}
else
{
timeAdjustment = 0;
}
lastTime = currentTime;
// Since the granularity of time in Java is only milliseconds,
// add an adjustment so that the time is represented in 100s of nanoseconds.
// The version number (1) is multiplexed into the most significant hex digit.
//
currentTime *= 10000;
currentTime += timeAdjustment;
currentTime |= 0x1000000000000000L;
// Place the time into the byte array in network byte order.
//
for (int i = 0; i < 4; ++i)
{
// time_low
//
uuid[i] = (byte)((currentTime >> 8 * (3 - i)) & 0xFFL);
}
for (int i = 0; i < 2; ++i)
{
// time_mid
//
uuid[i + 4] = (byte)((currentTime >> 8 * (1 - i) + 32) & 0xFFL);
}
for (int i = 0; i < 2; ++i)
{
// time_hi
//
uuid[i + 6] = (byte)((currentTime >> 8 * (1 - i) + 48) & 0xFFL);
}
}
}
/**
* Marks the package to indicate that it and everything it contains or that its contents depend on can no longer be changed.
* This helps to improve the performance of the model but has no other effect.
*/
public static void freeze(EPackage ePackage)
{
try
{
((EPackageImpl)ePackage).freeze();
}
catch (ClassCastException exception)
{
// Ignore if we can't freeze.
}
}
/**
* Computes a {@link Diagnostic} from the errors and warnings stored in the specified resource.
* @param resource
* @param includeWarnings
* @return {@link Diagnostic}
*/
public static Diagnostic computeDiagnostic(Resource resource, boolean includeWarnings)
{
if (resource.getErrors().isEmpty() && (!includeWarnings || resource.getWarnings().isEmpty()))
{
return Diagnostic.OK_INSTANCE;
}
else
{
BasicDiagnostic basicDiagnostic = new BasicDiagnostic();
for (Resource.Diagnostic resourceDiagnostic : resource.getErrors())
{
Diagnostic diagnostic = null;
if (resourceDiagnostic instanceof Throwable)
{
diagnostic = BasicDiagnostic.toDiagnostic((Throwable)resourceDiagnostic);
}
else
{
diagnostic = new BasicDiagnostic(
Diagnostic.ERROR,
"org.eclipse.emf.ecore.resource",
0,
resourceDiagnostic.getMessage(),
new Object[]{resourceDiagnostic});
}
basicDiagnostic.add(diagnostic);
}
if (includeWarnings)
{
for (Resource.Diagnostic resourceDiagnostic : resource.getWarnings())
{
Diagnostic diagnostic = null;
if (resourceDiagnostic instanceof Throwable)
{
diagnostic = BasicDiagnostic.toDiagnostic((Throwable)resourceDiagnostic);
}
else
{
diagnostic = new BasicDiagnostic(
Diagnostic.WARNING,
"org.eclipse.emf.ecore.resource",
0,
resourceDiagnostic.getMessage(),
new Object[]{resourceDiagnostic});
}
basicDiagnostic.add(diagnostic);
}
}
return basicDiagnostic;
}
}
/**
* Converts a generic type to its Java representation.
* @param eGenericType the generic type to convert.
* @return the Java representation of the generic type.
*/
public static String toJavaInstanceTypeName(EGenericType eGenericType)
{
return EGenericTypeConverter.INSTANCE.toJavaInstanceTypeName(eGenericType);
}
/**
* A utility class that traverses a generic type to convert it to a string representation.
*/
public static class EGenericTypeConverter
{
/**
* A default instance of the converter.
*/
public static EGenericTypeConverter INSTANCE = new EGenericTypeConverter();
/**
* Converts a generic type to its Java representation.
* @param eGenericType the generic type to convert.
* @return the Java representation of the generic type.
*/
public String toJavaInstanceTypeName(EGenericType eGenericType)
{
StringBuilder result = new StringBuilder();
convertJavaInstanceTypeName(result, eGenericType);
return result.toString();
}
/**
* Converts a generic type to its Java representation in the result.
* @param result the target in which to accumulate the result
* @param eGenericType the generic type to convert.
*/
public void convertJavaInstanceTypeName(StringBuilder result, EGenericType eGenericType)
{
EClassifier eClassifier = eGenericType.getEClassifier();
if (eClassifier != null)
{
String instanceTypeName = getInstanceTypeName(eClassifier);
EList<EGenericType> eTypeArguments = eGenericType.getETypeArguments();
if (eTypeArguments.isEmpty())
{
result.append(instanceTypeName);
}
else
{
int index = instanceTypeName.indexOf('[');
result.append(index == -1 ? instanceTypeName : instanceTypeName.substring(0, index));
result.append('<');
for (int i = 0, size = eTypeArguments.size(); i < size; ++i)
{
if (i != 0)
{
result.append(", ");
}
convertJavaInstanceTypeName(result, eTypeArguments.get(i));
}
result.append('>');
if (index != -1)
{
result.append(instanceTypeName.substring(index));
}
}
}
else
{
ETypeParameter eTypeParameter = eGenericType.getETypeParameter();
if (eTypeParameter != null)
{
result.append(eTypeParameter.getName());
}
else
{
result.append('?');
EGenericType eUpperBound = eGenericType.getEUpperBound();
if (eUpperBound != null)
{
result.append(" extends ");
convertJavaInstanceTypeName(result, eUpperBound);
}
else
{
EGenericType eLowerBound = eGenericType.getELowerBound();
if (eLowerBound != null)
{
result.append(" super ");
convertJavaInstanceTypeName(result, eLowerBound);
}
}
}
}
}
/**
* Returns the appropriate fully qualified java instance type name for the given classifier.
* @param eClassifier the classifier in question.
* @return the java instance type name for the given classifier.
*/
protected String getInstanceTypeName(EClassifier eClassifier)
{
return eClassifier.getInstanceTypeName();
}
}
/**
* @since 2.9
*/
public static EGenericType getReifiedType(EClass eClass, EGenericType eGenericType)
{
if (eGenericType == null)
{
return null;
}
else
{
Map<ETypeParameter, EGenericType> substitutions = new HashMap<ETypeParameter, EGenericType>();
for (EGenericType eGenericSuperType : eClass.getEAllGenericSuperTypes())
{
EClassifier eClassifier = eGenericSuperType.getEClassifier();
if (eClassifier != null)
{
EList<ETypeParameter> eTypeParameters = eClassifier.getETypeParameters();
int size = eTypeParameters.size();
if (size > 0)
{
EList<EGenericType> eTypeArguments = eGenericSuperType.getETypeArguments();
if (eTypeArguments.size() == size)
{
for (int i = 0; i < size; ++i)
{
substitutions.put(eTypeParameters.get(i), eTypeArguments.get(i));
}
}
}
}
}
if (substitutions.isEmpty() || !hasReifiedType(substitutions, eGenericType))
{
return eGenericType;
}
else
{
EGenericType reifiedType = getReifiedType(substitutions, eGenericType);
// Ensure that erasure produces the correct type of classifier by creating a container that forces it.
//
EObject eContainer = eGenericType.eContainer();
if (eContainer instanceof EClass || eContainer instanceof EReference)
{
EcoreFactory.eINSTANCE.createEReference().setEGenericType(reifiedType);
}
else if (eContainer instanceof EAttribute)
{
EcoreFactory.eINSTANCE.createEAttribute().setEGenericType(reifiedType);
}
return reifiedType;
}
}
}
private static boolean hasReifiedType(Map<ETypeParameter, EGenericType> substitutions, EGenericType eGenericType)
{
ETypeParameter eTypeParameter = eGenericType.getETypeParameter();
if (eTypeParameter != null)
{
return substitutions.containsKey(eTypeParameter);
}
else
{
EList<EGenericType> eTypeArguments = eGenericType.getETypeArguments();
if (!eTypeArguments.isEmpty())
{
for (EGenericType eTypeArgument : eTypeArguments)
{
if (hasReifiedType(substitutions, eTypeArgument))
{
return true;
}
}
return false;
}
else
{
EGenericType eLowerBound = eGenericType.getELowerBound();
if (eLowerBound != null)
{
return hasReifiedType(substitutions, eLowerBound);
}
else
{
EGenericType eUpperBound = eGenericType.getEUpperBound();
return eUpperBound != null && hasReifiedType(substitutions, eUpperBound);
}
}
}
}
private static EGenericType getReifiedType(Map<ETypeParameter, EGenericType> substitutions, EGenericType eGenericType)
{
ETypeParameter eTypeParameter = eGenericType.getETypeParameter();
if (eTypeParameter != null)
{
EGenericType substitution = substitutions.get(eTypeParameter);
if (substitution == null)
{
EGenericType result = EcoreFactory.eINSTANCE.createEGenericType();
result.setETypeParameter(eTypeParameter);
return result;
}
else
{
return getReifiedType(substitutions, substitution);
}
}
else
{
EGenericType result = EcoreFactory.eINSTANCE.createEGenericType();
EClassifier eClassifier = eGenericType.getEClassifier();
if (eClassifier != null)
{
result.setEClassifier(eClassifier);
EList<EGenericType> eTypeArguments = result.getETypeArguments();
for (EGenericType eTypeArgument : eGenericType.getETypeArguments())
{
eTypeArguments.add(getReifiedType(substitutions, eTypeArgument));
}
}
else
{
EGenericType eLowerBound = eGenericType.getELowerBound();
if (eLowerBound != null)
{
result.setELowerBound(getReifiedType(substitutions, eLowerBound));
}
else
{
EGenericType eUpperBound = eGenericType.getEUpperBound();
if (eUpperBound != null)
{
result.setEUpperBound(getReifiedType(substitutions, eUpperBound));
}
}
}
return result;
}
}
/**
* @since 2.6
*/
public static boolean isInvariant(EOperation eOperation)
{
// Base this on the instance class names so it returns true for models using the development time version of Ecore.
//
EClassifier eType = eOperation.getEType();
return eType != null && eType.getInstanceClassName() == "boolean" &&
eOperation.getEParameters().size() == 2 &&
eOperation.getEParameters().get(0).getEType().getInstanceClassName() == "org.eclipse.emf.common.util.DiagnosticChain" &&
eOperation.getEParameters().get(1).getEType().getInstanceClassName() == "java.util.Map";
}
/**
* @since 2.6
*/
public static List<String> getValidationDelegates(EPackage ePackage)
{
EAnnotation eAnnotation = ePackage.getEAnnotation(EcorePackage.eNS_URI);
if (eAnnotation != null)
{
String validationDelegates = eAnnotation.getDetails().get("validationDelegates");
if (validationDelegates != null)
{
List<String> result = new ArrayList<String>();
for (StringTokenizer stringTokenizer = new StringTokenizer(validationDelegates); stringTokenizer.hasMoreTokens();)
{
String validationDelegate = stringTokenizer.nextToken();
result.add(validationDelegate);
}
return result;
}
}
return Collections.emptyList();
}
/**
* @since 2.6
*/
public static void setValidationDelegates(EPackage ePackage, List<String> validationDelegates)
{
EAnnotation eAnnotation = ePackage.getEAnnotation(EcorePackage.eNS_URI);
if (validationDelegates == null || validationDelegates.isEmpty())
{
if (eAnnotation != null)
{
eAnnotation.getDetails().remove("validationDelegates");
}
}
else
{
if (eAnnotation == null)
{
eAnnotation = EcoreFactory.eINSTANCE.createEAnnotation();
eAnnotation.setSource(EcorePackage.eNS_URI);
ePackage.getEAnnotations().add(eAnnotation);
}
StringBuffer value = new StringBuffer();
for (Iterator<String> i = validationDelegates.iterator(); i.hasNext();)
{
value.append(i.next());
if (i.hasNext())
{
value.append(' ');
}
}
eAnnotation.getDetails().put("validationDelegates", value.toString());
}
}
/**
* @since 2.6
*/
public static List<String> getSettingDelegates(EPackage ePackage)
{
EAnnotation eAnnotation = ePackage.getEAnnotation(EcorePackage.eNS_URI);
if (eAnnotation != null)
{
String settingDelegates = eAnnotation.getDetails().get("settingDelegates");
if (settingDelegates != null)
{
List<String> result = new ArrayList<String>();
for (StringTokenizer stringTokenizer = new StringTokenizer(settingDelegates); stringTokenizer.hasMoreTokens();)
{
String settingDelegate = stringTokenizer.nextToken();
result.add(settingDelegate);
}
return result;
}
}
return Collections.emptyList();
}
/**
* @since 2.6
*/
public static void setSettingDelegates(EPackage ePackage, List<String> settingDelegates)
{
EAnnotation eAnnotation = ePackage.getEAnnotation(EcorePackage.eNS_URI);
if (settingDelegates == null || settingDelegates.isEmpty())
{
if (eAnnotation != null)
{
eAnnotation.getDetails().remove("settingDelegates");
}
}
else
{
if (eAnnotation == null)
{
eAnnotation = EcoreFactory.eINSTANCE.createEAnnotation();
eAnnotation.setSource(EcorePackage.eNS_URI);
ePackage.getEAnnotations().add(eAnnotation);
}
StringBuffer value = new StringBuffer();
for (Iterator<String> i = settingDelegates.iterator(); i.hasNext();)
{
value.append(i.next());
if (i.hasNext())
{
value.append(' ');
}
}
eAnnotation.getDetails().put("settingDelegates", value.toString());
}
}
/**
* @since 2.6
*/
public static EStructuralFeature.Internal.SettingDelegate.Factory getSettingDelegateFactory(EStructuralFeature eStructuralFeature)
{
for (String settingDelegate : getSettingDelegates(eStructuralFeature.getEContainingClass().getEPackage()))
{
if (eStructuralFeature.getEAnnotation(settingDelegate) != null)
return EStructuralFeature.Internal.SettingDelegate.Factory.Registry.INSTANCE.getFactory(settingDelegate);
}
return null;
}
/**
* @since 2.6
*/
public static List<String> getInvocationDelegates(EPackage ePackage)
{
EAnnotation eAnnotation = ePackage.getEAnnotation(EcorePackage.eNS_URI);
if (eAnnotation != null)
{
String invocationDelegates = eAnnotation.getDetails().get("invocationDelegates");
if (invocationDelegates != null)
{
List<String> result = new ArrayList<String>();
for (StringTokenizer stringTokenizer = new StringTokenizer(invocationDelegates); stringTokenizer.hasMoreTokens();)
{
String invocationDelegate = stringTokenizer.nextToken();
result.add(invocationDelegate);
}
return result;
}
}
return Collections.emptyList();
}
/**
* @since 2.6
*/
public static void setInvocationDelegates(EPackage ePackage, List<String> invocationDelegates)
{
EAnnotation eAnnotation = ePackage.getEAnnotation(EcorePackage.eNS_URI);
if (invocationDelegates == null || invocationDelegates.isEmpty())
{
if (eAnnotation != null)
{
eAnnotation.getDetails().remove("invocationDelegates");
}
}
else
{
if (eAnnotation == null)
{
eAnnotation = EcoreFactory.eINSTANCE.createEAnnotation();
eAnnotation.setSource(EcorePackage.eNS_URI);
ePackage.getEAnnotations().add(eAnnotation);
}
StringBuffer value = new StringBuffer();
for (Iterator<String> i = invocationDelegates.iterator(); i.hasNext();)
{
value.append(i.next());
if (i.hasNext())
{
value.append(' ');
}
}
eAnnotation.getDetails().put("invocationDelegates", value.toString());
}
}
/**
* @since 2.6
*/
public static EOperation.Internal.InvocationDelegate.Factory getInvocationDelegateFactory(EOperation eOperation)
{
for (String invocationDelegate : getInvocationDelegates(eOperation.getEContainingClass().getEPackage()))
{
if (eOperation.getEAnnotation(invocationDelegate) != null)
return EOperation.Internal.InvocationDelegate.Factory.Registry.INSTANCE.getFactory(invocationDelegate);
}
return null;
}
/**
* @since 2.8
*/
public static List<String> getConversionDelegates(EPackage ePackage)
{
EAnnotation eAnnotation = ePackage.getEAnnotation(EcorePackage.eNS_URI);
if (eAnnotation != null)
{
String eDataTypeDelegates = eAnnotation.getDetails().get("conversionDelegates");
if (eDataTypeDelegates != null)
{
List<String> result = new ArrayList<String>();
for (StringTokenizer stringTokenizer = new StringTokenizer(eDataTypeDelegates); stringTokenizer.hasMoreTokens();)
{
String eDataTypeDelegate = stringTokenizer.nextToken();
result.add(eDataTypeDelegate);
}
return result;
}
}
return Collections.emptyList();
}
public static void setConversionDelegates(EPackage ePackage, List<String> eDataTypeDelegates)
{
EAnnotation eAnnotation = ePackage.getEAnnotation(EcorePackage.eNS_URI);
if (eDataTypeDelegates == null || eDataTypeDelegates.isEmpty())
{
if (eAnnotation != null)
{
eAnnotation.getDetails().remove("conversionDelegates");
}
}
else
{
if (eAnnotation == null)
{
eAnnotation = EcoreFactory.eINSTANCE.createEAnnotation();
eAnnotation.setSource(EcorePackage.eNS_URI);
ePackage.getEAnnotations().add(eAnnotation);
}
StringBuffer value = new StringBuffer();
for (Iterator<String> i = eDataTypeDelegates.iterator(); i.hasNext();)
{
value.append(i.next());
if (i.hasNext())
{
value.append(' ');
}
}
eAnnotation.getDetails().put("conversionDelegates", value.toString());
}
}
/**
* @since 2.8
*/
public static EDataType.Internal.ConversionDelegate.Factory getConversionDelegateFactory(EDataType eDataType)
{
for (String eDataTypeDelegate : getConversionDelegates(eDataType.getEPackage()))
{
if (eDataType.getEAnnotation(eDataTypeDelegate) != null)
{
return EDataType.Internal.ConversionDelegate.Factory.Registry.INSTANCE.getFactory(eDataTypeDelegate);
}
}
return null;
}
/*
static
{
System.err.println("UUID");
for (int loop = 0; loop < 5; ++loop)
{
long before = System.currentTimeMillis();
long count = 500000;
for (int i = 0; i < count; ++i)
{
generateUUID();
}
long after = System.currentTimeMillis();
System.err.println("Elapsed " + (after - before));
System.err.println("Time " + 1000 * ((float)(after - before))/((float)count));
}
final EPackage ecorePackage = EPackage.Registry.INSTANCE.getEPackage("ecore.xmi");
final Resource ecorePackageResource = ecorePackage.eResource();
final EPackage genModelPackage = EPackage.Registry.INSTANCE.getEPackage("genmodel.xmi");
final Resource genModelPackageResource = genModelPackage.eResource();
// Proxy finder.
//
{
// Create a proxy and stuff it into the eSuperTypes.
// This is a really very nasty thing to do.
//
EClass eClass = org.eclipse.emf.ecore.EcoreFactory.eINSTANCE.createEClass();
((InternalEObject)eClass).eSetProxyURI(URI.createURI("Yes!"));
((EClass)genModelPackage.getEClassifier("GenClass")).getESuperTypes().add(eClass);
System.err.println("=========================================");
System.err.println("All proxy references in the GenModel EPackage");
Map proxyCrossReferences = ProxyCrossReferencer.find(genModelPackage);
CrossReferencer.print(System.err, proxyCrossReferences);
// Clean up the proxy.
//
((EClass)genModelPackage.getEClassifier("GenClass")).getESuperTypes().remove(eClass);
}
// External cross reference finder.
//
{
System.err.println("=========================================");
System.err.println("All cross document references in the GenModel EPackage");
Map externalCrossReferences = ExternalCrossReferencer.find(genModelPackage);
CrossReferencer.print(System.err, externalCrossReferences);
}
{
// Find uses for object of interest.
//
EObject objectOfInterest = ecorePackage.getEClassifier("EDataType");
System.err.println("=========================================");
System.err.println("Uses of: " + getIdentification(objectOfInterest));
// Put the models in a resource set temporarily.
//
ResourceSet resourceSet = new org.eclipse.emf.ecore.resource.impl.ResourceSetImpl();
resourceSet.getResources().add(ecorePackageResource);
resourceSet.getResources().add(genModelPackageResource);
// Search the whole resource set.
//
Collection result = new UsageCrossReferencer(resourceSet).findUsage(objectOfInterest);
for (Iterator i = result.iterator(); i.hasNext(); )
{
// Show the settings that reference the objectOfInterest.
//
EStructuralFeature.Setting setting = (EStructuralFeature.Setting)i.next();
EObject eObject = setting.getEObject();
EStructuralFeature eStructuralFeature = (EStructuralFeature)setting.getEStructuralFeature();
System.err.println
("> " + eStructuralFeature.getEContainingClass().getName() + "." + eStructuralFeature.getName() +
" <- " + getIdentification(eObject));
}
// Cleanup.
//
resourceSet.getResources().clear();
}
List list = org.eclipse.emf.ecore.EcorePackage.eINSTANCE.getEReference().getEAllStructuralFeatures();
{
Object object = org.eclipse.emf.ecore.EcorePackage.eINSTANCE.getEReference_EReferenceType();
for (int i = 0; i < 100; ++i)
{
list.indexOf(object);
}
long before = System.currentTimeMillis();
for (int i = 0; i < 500000; ++i)
{
list.indexOf(object);
}
long after = System.currentTimeMillis();
System.err.println("Elapsed " + (after - before));
}
{
Object object = org.eclipse.emf.ecore.EcorePackage.eINSTANCE.getENamedElement_Name();
for (int i = 0; i < 100; ++i)
{
list.indexOf(object);
}
long before = System.currentTimeMillis();
for (int i = 0; i < 500000; ++i)
{
list.indexOf(object);
}
long after = System.currentTimeMillis();
System.err.println("Elapsed " + (after - before));
}
}
*/
}