blob: e9bac741eabdd489c8fe996e6dbca118137b8025 [file] [log] [blame]
/**
* 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();
}
}
}