| /** |
| * 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.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); |
| 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); |
| 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(EClass) |
| * @see EcoreUtil#create(EClass) |
| */ |
| protected EObject createCopy(EObject eObject) |
| { |
| return create(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) |
| */ |
| protected EClass getTarget(EClass eClass) |
| { |
| return eClass; |
| } |
| |
| /** |
| * 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)) |
| { |
| if (eReference.isMany()) |
| { |
| @SuppressWarnings("unchecked") List<EObject> source = (List<EObject>)eObject.eGet(eReference); |
| @SuppressWarnings("unchecked") List<EObject> target = (List<EObject>)copyEObject.eGet(getTarget(eReference)); |
| if (source.isEmpty()) |
| { |
| target.clear(); |
| } |
| else |
| { |
| target.addAll(copyAll(source)); |
| } |
| } |
| else |
| { |
| EObject childEObject = (EObject)eObject.eGet(eReference); |
| copyEObject.eSet(getTarget(eReference), childEObject == null ? null : copy(childEObject)); |
| } |
| } |
| } |
| |
| /** |
| * 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); |
| 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) |
| { |
| copy((EObject)value); |
| } |
| } |
| } |
| } |
| else if (eAttribute.isMany()) |
| { |
| List<?> source = (List<?>)eObject.eGet(eAttribute); |
| @SuppressWarnings("unchecked") List<Object> target = (List<Object>)copyEObject.eGet(getTarget(eAttribute)); |
| if (source.isEmpty()) |
| { |
| target.clear(); |
| } |
| else |
| { |
| target.addAll(source); |
| } |
| } |
| else |
| { |
| copyEObject.eSet(getTarget(eAttribute), eObject.eGet(eAttribute)); |
| } |
| } |
| } |
| |
| /** |
| * 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 featureMap = (FeatureMap)eObject.eGet(eStructuralFeature); |
| FeatureMap copyFeatureMap = (FeatureMap)copyEObject.eGet(getTarget(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(featureMap.get(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)) |
| { |
| if (eReference.isMany()) |
| { |
| @SuppressWarnings("unchecked") InternalEList<EObject> source = (InternalEList<EObject>)eObject.eGet(eReference); |
| @SuppressWarnings("unchecked") InternalEList<EObject> target = (InternalEList<EObject>)copyEObject.eGet(getTarget(eReference)); |
| 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 |
| { |
| Object referencedEObject = eObject.eGet(eReference, resolveProxies); |
| if (referencedEObject == null) |
| { |
| copyEObject.eSet(getTarget(eReference), null); |
| } |
| else |
| { |
| Object copyReferencedEObject = get(referencedEObject); |
| if (copyReferencedEObject == null) |
| { |
| if (useOriginalReferences && eReference.getEOpposite() == null) |
| { |
| copyEObject.eSet(getTarget(eReference), referencedEObject); |
| } |
| } |
| else |
| { |
| copyEObject.eSet(getTarget(eReference), 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 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 : value1.equals(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> |
| * <java-class-name>[/<dynamic-eClass-name>]@<java-hex-hash-code>{<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 eProxyURI, |
| * the URI of the eResource with the fragment produced by the eResource, |
| * or the URI consisting of just the fragment 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 |
| { |
| InternalEObject internalEObject = (InternalEObject)eObject; |
| List<String> uriFragmentPath = new ArrayList<String>(); |
| HashSet<InternalEObject> visited = new HashSet<InternalEObject>(); |
| for (InternalEObject container = internalEObject.eInternalContainer(); container != null && visited.add(container); container = internalEObject.eInternalContainer()) |
| { |
| uriFragmentPath.add(container.eURIFragmentSegment(internalEObject.eContainingFeature(), internalEObject)); |
| internalEObject = container; |
| } |
| |
| StringBuffer result = new StringBuffer("#//"); |
| |
| for (int i = uriFragmentPath.size() - 1; i >= 0; --i) |
| { |
| result.append('/'); |
| result.append(uriFragmentPath.get(i)); |
| } |
| return URI.createURI(result.toString()); |
| } |
| } |
| } |
| } |
| |
| /** |
| * 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) |
| { |
| return eOperation.getEType() == EcorePackage.Literals.EBOOLEAN && |
| eOperation.getEParameters().size() == 2 && |
| eOperation.getEParameters().get(0).getEType() == EcorePackage.Literals.EDIAGNOSTIC_CHAIN && |
| eOperation.getEParameters().get(1).getEType() == EcorePackage.Literals.EMAP; |
| } |
| |
| /** |
| * @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)); |
| } |
| } |
| */ |
| } |