| /** |
| * Copyright (c) 2009-2010 Thales Corporate Services S.A.S. |
| * This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v2.0 |
| * which accompanies this distribution, and is available at |
| * https://www.eclipse.org/legal/epl-v2.0 |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| * Contributors: |
| * Thales Corporate Services S.A.S - initial API and implementation |
| */ |
| package org.eclipse.egf.common.helper; |
| |
| import java.lang.reflect.InvocationTargetException; |
| import java.lang.reflect.Method; |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.Collections; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| |
| import org.eclipse.core.resources.IProject; |
| import org.eclipse.core.resources.IResource; |
| import org.eclipse.core.resources.ResourcesPlugin; |
| import org.eclipse.egf.common.EGFCommonPlugin; |
| import org.eclipse.egf.common.loader.IClassLoader; |
| import org.eclipse.emf.codegen.ecore.genmodel.GenModel; |
| import org.eclipse.emf.codegen.ecore.genmodel.GenPackage; |
| import org.eclipse.emf.common.notify.AdapterFactory; |
| import org.eclipse.emf.common.util.TreeIterator; |
| import org.eclipse.emf.common.util.URI; |
| import org.eclipse.emf.common.util.UniqueEList; |
| import org.eclipse.emf.ecore.EAnnotation; |
| import org.eclipse.emf.ecore.EClassifier; |
| import org.eclipse.emf.ecore.EObject; |
| import org.eclipse.emf.ecore.EOperation; |
| import org.eclipse.emf.ecore.EPackage; |
| import org.eclipse.emf.ecore.EParameter; |
| import org.eclipse.emf.ecore.EReference; |
| import org.eclipse.emf.ecore.EStructuralFeature; |
| import org.eclipse.emf.ecore.resource.Resource; |
| import org.eclipse.emf.ecore.resource.ResourceSet; |
| import org.eclipse.emf.ecore.resource.URIConverter; |
| import org.eclipse.emf.ecore.util.EcoreUtil; |
| import org.eclipse.emf.ecore.util.EcoreUtil.CrossReferencer; |
| import org.eclipse.emf.edit.provider.ComposedAdapterFactory; |
| import org.eclipse.emf.edit.provider.IItemLabelProvider; |
| import org.eclipse.emf.edit.provider.ReflectiveItemProviderAdapterFactory; |
| import org.eclipse.jdt.core.IJavaProject; |
| import org.eclipse.jdt.core.JavaCore; |
| import org.eclipse.osgi.util.NLS; |
| |
| /** |
| * @author Xavier Maysonnave |
| * |
| */ |
| public class EMFHelper { |
| |
| // back-up for unregistered packages |
| private static AdapterFactory __defaultFactory = new ReflectiveItemProviderAdapterFactory(); |
| |
| private static AdapterFactory __factory = new ComposedAdapterFactory(ComposedAdapterFactory.Descriptor.Registry.INSTANCE); |
| |
| private EMFHelper() { |
| // Prevent instantiation |
| } |
| |
| public static String getInstanceClassName(EPackage ePackage, URI uri) { |
| if (ePackage == null || uri == null) { |
| return null; |
| } |
| if (uri.hasFragment()) { |
| EObject eObject = ePackage.eResource().getEObject(uri.fragment()); |
| if (eObject != null && eObject instanceof EClassifier) { |
| return ((EClassifier) eObject).getInstanceClassName(); |
| } |
| } |
| return null; |
| } |
| |
| public static String getInstanceClassName(IClassLoader loader, Object object, URI uri) throws IllegalArgumentException, IllegalAccessException, SecurityException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException { |
| if (object == null || uri == null) { |
| return null; |
| } |
| Object ePackage = getEPackage(loader, object); |
| if (ePackage == null) { |
| return null; |
| } |
| if (uri.hasFragment()) { |
| object = ePackage.getClass().getMethod("eResource", new Class[] {}).invoke(ePackage); //$NON-NLS-1$ |
| if (object != null) { |
| object = object.getClass().getMethod("getEObject", new Class[] { java.lang.String.class}).invoke(object, uri.fragment()); //$NON-NLS-1$ |
| if (object != null) { |
| // EClassifier |
| Class<?> eClassifier = loader.loadClass("org.eclipse.emf.ecore.EClassifier"); //$NON-NLS-1$ |
| if (eClassifier.isInstance(object)) { |
| return (String) object.getClass().getMethod("getInstanceClassName", new Class[] {}).invoke(object); //$NON-NLS-1$ |
| } |
| } |
| } |
| } |
| return null; |
| } |
| |
| public static URI getEPackageNsURI(EPackage ePackage, URI uri) { |
| if (ePackage == null || uri == null) { |
| return null; |
| } |
| if (uri.hasFragment()) { |
| EObject eObject = ePackage.eResource().getEObject(uri.fragment()); |
| if (eObject != null) { |
| ePackage = getEPackage(eObject); |
| if (ePackage != null) { |
| return URI.createURI(ePackage.getNsURI()); |
| } |
| } |
| } |
| return URI.createURI(ePackage.getNsURI()); |
| } |
| |
| public static URI getEPackageNsURI(IClassLoader loader, String generatedPackage, URI uri) throws NoSuchFieldException, IllegalArgumentException, IllegalAccessException, SecurityException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException { |
| if (loader == null || generatedPackage == null || generatedPackage.trim().length() == 0 || uri == null) { |
| return null; |
| } |
| // EPackage |
| Class<?> eGeneratedPackage = loader.loadClass(generatedPackage.trim()); |
| if (eGeneratedPackage != null && uri.hasFragment()) { |
| Object object = eGeneratedPackage.getField("eINSTANCE").get(null); //$NON-NLS-1$ |
| if (object != null) { |
| object = eGeneratedPackage.getMethod("eResource", new Class[] {}).invoke(object); //$NON-NLS-1$ |
| if (object != null) { |
| object = object.getClass().getMethod("getEObject", new Class[] { java.lang.String.class}).invoke(object, uri.fragment()); //$NON-NLS-1$ |
| if (object != null) { |
| object = EMFHelper.getEPackage(loader, object); |
| if (object != null && loader.loadClass("org.eclipse.emf.ecore.EPackage").isInstance(object)) { //$NON-NLS-1$ |
| return URI.createURI(object.getClass().getMethod("getNsURI", new Class[] {}).invoke(object).toString()); //$NON-NLS-1$ |
| } |
| } |
| } |
| } |
| } |
| return null; |
| } |
| |
| public static Object getEPackage(IClassLoader loader, Object object) throws IllegalAccessException, InvocationTargetException, ClassNotFoundException, NoSuchMethodException { |
| if (loader == null || object == null) { |
| return null; |
| } |
| // EObject |
| Class<?> eObject = loader.loadClass("org.eclipse.emf.ecore.EObject"); //$NON-NLS-1$ |
| if (eObject.isInstance(object) == false) { |
| return null; |
| } |
| // EPackage |
| Class<?> ePackage = loader.loadClass("org.eclipse.emf.ecore.EPackage"); //$NON-NLS-1$ |
| if (ePackage.isInstance(object)) { |
| return object; |
| } |
| // EClassifier |
| Class<?> eClassifier = loader.loadClass("org.eclipse.emf.ecore.EClassifier"); //$NON-NLS-1$ |
| if (eClassifier.isInstance(object)) { |
| return object.getClass().getMethod("getEPackage", new Class[] {}).invoke(object); //$NON-NLS-1$ |
| } |
| // EOperation |
| Class<?> eOperation = loader.loadClass("org.eclipse.emf.ecore.EOperation"); //$NON-NLS-1$ |
| if (eOperation.isInstance(object)) { |
| Method getEContainingClass = object.getClass().getMethod("getEContainingClass", new Class[] {}); //$NON-NLS-1$ |
| object = getEContainingClass.invoke(object); |
| return object.getClass().getMethod("getEPackage", new Class[] {}).invoke(object); //$NON-NLS-1$ |
| } |
| // EStructuralFeature |
| Class<?> eStructuralFeature = loader.loadClass("org.eclipse.emf.ecore.EStructuralFeature"); //$NON-NLS-1$ |
| if (eStructuralFeature.isInstance(object)) { |
| Method getEContainingClass = object.getClass().getMethod("getEContainingClass", new Class[] {}); //$NON-NLS-1$ |
| object = getEContainingClass.invoke(object); |
| return object.getClass().getMethod("getEPackage", new Class[] {}).invoke(object); //$NON-NLS-1$ |
| } |
| // EAnnotation |
| Class<?> eAnnotation = loader.loadClass("org.eclipse.emf.ecore.EAnnotation"); //$NON-NLS-1$ |
| if (eAnnotation.isInstance(object)) { |
| Method getEModelElement = object.getClass().getMethod("getEModelElement", new Class[] {}); //$NON-NLS-1$ |
| return getEPackage(loader, getEModelElement.invoke(object)); |
| } |
| // EParameter |
| Class<?> eParameter = loader.loadClass("org.eclipse.emf.ecore.EParameter"); //$NON-NLS-1$ |
| if (eParameter.isInstance(object)) { |
| Method getEOperation = object.getClass().getMethod("getEOperation", new Class[] {}); //$NON-NLS-1$ |
| return getEPackage(loader, getEOperation.invoke(object)); |
| } |
| // Meta-Class analysis |
| return getEPackage(loader, object.getClass().getMethod("eClass", new Class[] {}).invoke(object)); //$NON-NLS-1$ |
| } |
| |
| public static EPackage getEPackage(EObject eObject) { |
| if (eObject == null) { |
| return null; |
| } |
| if (eObject instanceof EPackage) { |
| return (EPackage) eObject; |
| } else if (eObject instanceof EClassifier) { |
| return ((EClassifier) eObject).getEPackage(); |
| } else if (eObject instanceof EOperation) { |
| return ((EOperation) eObject).getEContainingClass().getEPackage(); |
| } else if (eObject instanceof EStructuralFeature) { |
| return ((EStructuralFeature) eObject).getEContainingClass().getEPackage(); |
| } else if (eObject instanceof EAnnotation) { |
| return getEPackage(((EAnnotation) eObject).getEModelElement()); |
| } else if (eObject instanceof EParameter) { |
| return getEPackage(((EParameter) eObject).getEOperation()); |
| } |
| return getEPackage(eObject.eClass()); |
| } |
| |
| public static Collection<EPackage> getAllPackages(Resource resource) { |
| if (resource == null) { |
| return null; |
| } |
| List<EPackage> result = new UniqueEList<EPackage>(); |
| for (TreeIterator<?> j = new EcoreUtil.ContentTreeIterator<Object>(resource.getContents()) { |
| |
| private static final long serialVersionUID = 1L; |
| |
| @Override |
| protected Iterator<? extends EObject> getEObjectChildren(EObject eObject) { |
| return eObject instanceof EPackage ? ((EPackage) eObject).getESubpackages().iterator() : Collections.<EObject> emptyList().iterator(); |
| } |
| |
| }; j.hasNext();) { |
| Object content = j.next(); |
| if (content instanceof EPackage) { |
| result.add((EPackage) content); |
| } |
| } |
| return result; |
| } |
| |
| public static Collection<GenPackage> getAllGenPackages(Resource resource) { |
| if (resource == null) { |
| return null; |
| } |
| List<GenPackage> result = new UniqueEList<GenPackage>(); |
| for (TreeIterator<?> j = new EcoreUtil.ContentTreeIterator<Object>(resource.getContents()) { |
| |
| private static final long serialVersionUID = 1L; |
| |
| @Override |
| protected Iterator<? extends EObject> getEObjectChildren(EObject eObject) { |
| return eObject instanceof GenModel ? ((GenModel) eObject).getGenPackages().iterator() : eObject instanceof GenPackage ? ((GenPackage) eObject).getSubGenPackages().iterator() : Collections.<EObject> emptyList().iterator(); |
| } |
| |
| }; j.hasNext();) { |
| Object content = j.next(); |
| if (content instanceof GenPackage) { |
| result.add((GenPackage) content); |
| } |
| } |
| return result; |
| } |
| |
| public static Collection<EObject> getAllProperContents(EClassifier eClassifier, EObject owner) { |
| Collection<EObject> result = new ArrayList<EObject>(); |
| if (eClassifier == null || owner == null) { |
| return result; |
| } |
| if (eClassifier.isInstance(owner)) { |
| result.add(owner); |
| } |
| for (TreeIterator<EObject> j = EcoreUtil.getAllProperContents(owner, false); j.hasNext();) { |
| EObject eObject = j.next(); |
| if (eClassifier.isInstance(eObject)) { |
| result.add(eObject); |
| } |
| } |
| return result; |
| } |
| |
| public static IResource getWorkspaceResource(Resource resource) { |
| if (resource == null) { |
| return null; |
| } |
| URI uri = resource.getURI(); |
| if (uri != null && resource.getResourceSet() != null) { |
| URIConverter converter = resource.getResourceSet().getURIConverter(); |
| if (converter != null) { |
| uri = converter.normalize(uri); |
| } |
| } |
| if (uri != null && uri.isPlatformResource()) { |
| return ResourcesPlugin.getWorkspace().getRoot().findMember(uri.toPlatformString(true)); |
| } |
| return null; |
| } |
| |
| public static IProject getProject(Resource resource) { |
| IResource iResource = getWorkspaceResource(resource); |
| if (iResource != null) { |
| return iResource.getProject(); |
| } |
| return null; |
| } |
| |
| public static IJavaProject getJavaProject(Resource resource) { |
| IProject project = getProject(resource); |
| if (project != null && project.isAccessible()) { |
| IJavaProject javaProject = JavaCore.create(project); |
| if (javaProject.exists()) { |
| return javaProject; |
| } |
| } |
| return null; |
| } |
| |
| /** |
| * Get root package for given one.<br> |
| * Root package being the eldest parent package. |
| * |
| * @param ePackage |
| * @return EPackage |
| */ |
| public static EPackage getRootPackage(EPackage ePackage) { |
| if (ePackage == null) { |
| return null; |
| } |
| EPackage result = null; |
| EPackage rootPackage = ePackage; |
| while (rootPackage != null) { |
| result = rootPackage; |
| rootPackage = result.getESuperPackage(); |
| } |
| if (result == null) { |
| EGFCommonPlugin.getDefault().logWarning(NLS.bind("Unable to solve a Root EPackage for {0}", ePackage)); //$NON-NLS-1$ |
| } |
| return result; |
| } |
| |
| /** |
| * Get static ecore package from serialized one.<br> |
| * That implies that the corresponding ecore model has been generated once. |
| * |
| * @param ePackage |
| * @return null if no generated package could be found. |
| */ |
| public static EPackage getStaticPackage(EPackage ePackage) { |
| if (ePackage == null) { |
| return null; |
| } |
| EPackage ePackageStatic = null; |
| // Get the equivalent from the Global EPackage registry. |
| Object staticPackage = null; |
| if (ePackage.getNsURI() != null) { |
| staticPackage = EPackage.Registry.INSTANCE.get(ePackage.getNsURI()); |
| } |
| if (staticPackage != null) { |
| if (staticPackage instanceof EPackage) { |
| ePackageStatic = (EPackage) staticPackage; |
| } else if (staticPackage instanceof EPackage.Descriptor) { |
| ePackageStatic = ((EPackage.Descriptor) staticPackage).getEPackage(); |
| } |
| } else { |
| ePackageStatic = ePackage; |
| } |
| return ePackageStatic; |
| } |
| |
| public static EClassifier solveAgainstStaticPackage(EClassifier eClassifier) { |
| if (eClassifier == null) { |
| return null; |
| } |
| EPackage ePackage = getStaticPackage(getRootPackage(eClassifier.getEPackage())); |
| if (ePackage != null && ePackage.eResource() != null) { |
| URI uri = EcoreUtil.getURI(eClassifier); |
| if (uri == null) { |
| return eClassifier; |
| } |
| EObject eObject = ePackage.eResource().getEObject(uri.fragment()); |
| if (eObject == null) { |
| return eClassifier; |
| } |
| EClassifier solvedEClassifier = eObject instanceof EClassifier ? (EClassifier) eObject : eObject.eClass(); |
| if (solvedEClassifier != null) { |
| return solvedEClassifier; |
| } |
| } else { |
| EGFCommonPlugin.getDefault().logWarning(NLS.bind("Unable to solve EClassifier {0} against its static EPackage", eClassifier)); //$NON-NLS-1$ |
| } |
| return eClassifier; |
| } |
| |
| public static EObject solveAgainstStaticPackage(EPackage ePackage, EObject eObject) { |
| if (eObject == null) { |
| return null; |
| } |
| EPackage solvedEPackage = getStaticPackage(getRootPackage(ePackage)); |
| if (solvedEPackage != null && solvedEPackage.eResource() != null) { |
| URI uri = EcoreUtil.getURI(eObject); |
| if (uri == null) { |
| return eObject; |
| } |
| EObject solvedEObject = solvedEPackage.eResource().getEObject(uri.fragment()); |
| if (solvedEObject != null) { |
| return solvedEObject; |
| } |
| } else { |
| EGFCommonPlugin.getDefault().logWarning(NLS.bind("Unable to solve EObject {0} against its static EPackage", eObject)); //$NON-NLS-1$ |
| } |
| return eObject; |
| } |
| |
| /** |
| * Obtains a textual representation of the specified object, as for |
| * display in messages. If no suitable factory is registered for model element, |
| * then the EMF reflective item provider is used. |
| * |
| * @param object |
| * the model element for which to get text |
| * @return the corresponding text |
| */ |
| public static String getText(Object object) { |
| if (object == null || object instanceof EObject == false) { |
| if (object == null) { |
| return null; |
| } |
| return object.toString(); |
| } |
| EObject eObject = (EObject) object; |
| IItemLabelProvider provider = (IItemLabelProvider) __factory.adapt(eObject, IItemLabelProvider.class); |
| if (provider == null) { |
| // for backward compatibility, try looking in the resource set |
| provider = (IItemLabelProvider) getRegisteredAdapter(eObject, IItemLabelProvider.class); |
| } |
| if (provider == null) { |
| provider = (IItemLabelProvider) __defaultFactory.adapt(eObject, IItemLabelProvider.class); |
| } |
| String result = provider.getText(eObject); |
| if (result != null) { |
| // don't want leading or trailing blanks in messages |
| result = result.trim(); |
| } |
| return result; |
| } |
| |
| /** |
| * Obtains an IItemLabelProvider of the specified model element, as for |
| * display in messages. If no suitable factory is registered, then |
| * the EMF reflective item provider is used. |
| * |
| * @param eObject |
| * the model element for which to get text |
| * @return the corresponding text |
| */ |
| public static IItemLabelProvider getItemLabelProvider(EObject eObject) { |
| if (eObject == null) { |
| return null; |
| } |
| IItemLabelProvider provider = (IItemLabelProvider) __factory.adapt(eObject, IItemLabelProvider.class); |
| if (provider == null) { |
| // for backward compatibility, try looking in the resource set |
| provider = (IItemLabelProvider) getRegisteredAdapter(eObject, IItemLabelProvider.class); |
| } |
| if (provider == null) { |
| provider = (IItemLabelProvider) __defaultFactory.adapt(eObject, IItemLabelProvider.class); |
| } |
| return provider; |
| } |
| |
| /** |
| * Similar to the {@link EcoreUtil#getRegisteredAdapter(EObject, Object)} method, attempts to |
| * adapt the given <code>eObject</code> to the |
| * specified <code>type</code> using adapter factories registered on its |
| * resource set. The difference is, that this method anticipates that |
| * adapter factories from multiple disjoint metamodels may be registered, |
| * that adapt different kinds of objects to the same types. This method |
| * will try them all until it either gets a successful adaptation or runs |
| * out of factories. |
| * |
| * @param eObject |
| * the model element to adapt |
| * @param type |
| * indicates the type of adapter to obtain |
| * @return the available registered adapter, or <code>null</code> if no |
| * suitable adapter factory is found |
| */ |
| private static Object getRegisteredAdapter(EObject eObject, Object type) { |
| Object result = EcoreUtil.getExistingAdapter(eObject, type); |
| if (result == null) { |
| Resource resource = eObject.eResource(); |
| if (resource != null) { |
| ResourceSet resourceSet = resource.getResourceSet(); |
| if (resourceSet != null) { |
| List<AdapterFactory> factories = resourceSet.getAdapterFactories(); |
| // iterate only as long as we don't find an adapter factory |
| // that successfully adapted the eObject |
| for (Iterator<AdapterFactory> iter = factories.iterator(); iter.hasNext() && (result == null);) { |
| AdapterFactory next = iter.next(); |
| if (next.isFactoryForType(type)) { |
| result = next.adapt(eObject, type); |
| } |
| } |
| } |
| } |
| } |
| return result; |
| } |
| |
| /** |
| * A cross referencer that finds resolved proxies against a particular URI while |
| * ignoring non resolved proxies. |
| */ |
| public static class URIProxyCrossReferencer extends CrossReferencer { |
| |
| private static final long serialVersionUID = 1L; |
| |
| private URI _uri; |
| |
| /** |
| * Creates an instance for the given resource. |
| * |
| * @param resource |
| * the resource to cross reference. |
| */ |
| protected URIProxyCrossReferencer(Resource resource, URI uri) { |
| super(Collections.singleton(resource)); |
| _uri = uri; |
| } |
| |
| /** |
| * 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) { |
| if (crossReferencedEObject.eIsProxy() == false) { |
| return false; |
| } |
| URI uri = EcoreUtil.getURI(crossReferencedEObject); |
| if (uri == null) { |
| return false; |
| } |
| uri = uri.trimFragment(); |
| if (_uri.equals(uri)) { |
| return true; |
| } |
| return false; |
| } |
| |
| /** |
| * 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 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, URI uri) { |
| return new URIProxyCrossReferencer(resource, uri).findProxyCrossReferences(); |
| } |
| |
| } |
| |
| } |