| /******************************************************************************* |
| * Copyright (c) 2015 Obeo. |
| * 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: |
| * Obeo - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.acceleo.query.runtime.impl; |
| |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.LinkedHashMap; |
| import java.util.LinkedHashSet; |
| import java.util.Map; |
| import java.util.Set; |
| |
| import org.eclipse.acceleo.query.runtime.IEPackageProvider; |
| import org.eclipse.emf.ecore.EAttribute; |
| import org.eclipse.emf.ecore.EClass; |
| import org.eclipse.emf.ecore.EClassifier; |
| import org.eclipse.emf.ecore.EEnum; |
| import org.eclipse.emf.ecore.EEnumLiteral; |
| import org.eclipse.emf.ecore.EPackage; |
| import org.eclipse.emf.ecore.EReference; |
| import org.eclipse.emf.ecore.EStructuralFeature; |
| import org.eclipse.emf.ecore.EcorePackage; |
| |
| /** |
| * {@link EPackageProvider} instances are used to access a set of ecore packages and getting classifiers, and |
| * enums literals. |
| * |
| * @author <a href="mailto:romain.guider@obeo.fr">Romain Guider</a> |
| */ |
| public class EPackageProvider implements IEPackageProvider { |
| |
| /** |
| * Map the name to their corresponding package. |
| */ |
| private Map<String, Set<EPackage>> ePackages = new LinkedHashMap<String, Set<EPackage>>(); |
| |
| /** |
| * {@link Class} to {@link EClassifier} mapping. |
| */ |
| private final Map<Class<?>, Set<EClassifier>> class2classifiers = new HashMap<Class<?>, Set<EClassifier>>(); |
| |
| /** |
| * {@link EClassifier} to {@link Class} mapping. |
| */ |
| private final Map<EClassifier, Class<?>> classifier2class = new HashMap<EClassifier, Class<?>>(); |
| |
| /** |
| * Mapping from an {@link EClass} to its containing {@link EStructuralFeature} for one {@link EClass} |
| * hierarchy. |
| */ |
| private final Map<EClass, Set<EStructuralFeature>> containingFeaturesForOneClassHierarchy = new HashMap<EClass, Set<EStructuralFeature>>(); |
| |
| /** |
| * Mapping from an {@link EClass} to its containing {@link EStructuralFeature}. |
| */ |
| private final Map<EClass, Set<EStructuralFeature>> containingFeatures = new HashMap<EClass, Set<EStructuralFeature>>(); |
| |
| /** |
| * Mapping from an {@link EClass} to all its containing {@link EStructuralFeature} (transitive). |
| */ |
| private final Map<EClass, Set<EStructuralFeature>> allContainingFeatures = new HashMap<EClass, Set<EStructuralFeature>>(); |
| |
| /** |
| * Mapping from an {@link EClass} to its inverse {@link EStructuralFeature}. |
| */ |
| private final Map<EClass, Set<EStructuralFeature>> inverseFeatures = new HashMap<EClass, Set<EStructuralFeature>>(); |
| |
| /** |
| * Mapping from an {@link EClass} to its sub {@link EClass}. |
| */ |
| private final Map<EClass, Set<EClass>> subTypes = new HashMap<EClass, Set<EClass>>(); |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.acceleo.query.runtime.IEPackageProvider#getEPackage(java.lang.String) |
| */ |
| @Override |
| public Collection<EPackage> getEPackage(String name) { |
| final Set<EPackage> res = new LinkedHashSet<EPackage>(); |
| |
| final Set<EPackage> set = ePackages.get(name); |
| if (set != null) { |
| res.addAll(set); |
| } |
| |
| return res; |
| } |
| |
| /** |
| * Removes the {@link EPackageProvider#registerPackage(EPackage) registered} {@link EPackage}s having the |
| * given {@link EPackage}. |
| * |
| * @param ePackage |
| * the {@link EPackage} to remove |
| * @return the list of removed {@link EPackage} |
| */ |
| public Collection<EPackage> removePackage(EPackage ePackage) { |
| final Collection<EPackage> result = new ArrayList<EPackage>(); |
| |
| final Set<EPackage> set = ePackages.get(ePackage.getName()); |
| if (set != null) { |
| if (set.remove(ePackage)) { |
| if (set.isEmpty()) { |
| ePackages.remove(ePackage.getName()); |
| } |
| result.add(ePackage); |
| for (EClassifier eCls : ePackage.getEClassifiers()) { |
| removeEClassifierClass(eCls); |
| if (eCls instanceof EClass) { |
| removeFeatures((EClass)eCls); |
| removeSubType((EClass)eCls); |
| } |
| } |
| for (EPackage childPkg : ePackage.getESubpackages()) { |
| removePackage(childPkg); |
| } |
| containingFeatures.clear(); |
| allContainingFeatures.clear(); |
| } |
| } |
| |
| return result; |
| } |
| |
| /** |
| * Removes the given {@link EClass} as been a sub type of its {@link EClass#getESuperTypes() super types}. |
| * |
| * @param eCls |
| * the {@link EClass} |
| */ |
| private void removeSubType(EClass eCls) { |
| for (EClass superECls : eCls.getESuperTypes()) { |
| Set<EClass> types = subTypes.get(superECls); |
| if (types != null && types.remove(eCls) && types.size() == 0) { |
| types = new LinkedHashSet<EClass>(); |
| subTypes.remove(superECls); |
| } |
| } |
| } |
| |
| /** |
| * Removes {@link EStructuralFeature} for the given {@link EClass}. |
| * |
| * @param eCls |
| * the {@link EClass} to remove |
| */ |
| private void removeFeatures(EClass eCls) { |
| for (EStructuralFeature feature : eCls.getEStructuralFeatures()) { |
| if (feature.getEType() instanceof EClass) { |
| Set<EStructuralFeature> possibleInverseFeatures = inverseFeatures.get(feature.getEType()); |
| if (possibleInverseFeatures != null && possibleInverseFeatures.remove(feature) |
| && possibleInverseFeatures.size() == 0) { |
| inverseFeatures.remove(feature.getEType()); |
| } |
| if (isContainingEStructuralFeature(feature)) { |
| Set<EStructuralFeature> possibleContainementFeatures = containingFeaturesForOneClassHierarchy |
| .get(feature.getEType()); |
| if (possibleContainementFeatures != null && possibleContainementFeatures.remove(feature) |
| && possibleContainementFeatures.size() == 0) { |
| containingFeaturesForOneClassHierarchy.remove(feature.getEType()); |
| } |
| } |
| } |
| } |
| } |
| |
| /** |
| * Tells if the given {@link EStructuralFeature} is a containing {@link EStructuralFeature}. |
| * |
| * @param feature |
| * the {@link EStructuralFeature} to test |
| * @return <code>true</code> if the given {@link EStructuralFeature} is a containing |
| * {@link EStructuralFeature},<code>false</code> otherwise |
| */ |
| private boolean isContainingEStructuralFeature(EStructuralFeature feature) { |
| return (feature instanceof EReference && ((EReference)feature).isContainment()) |
| || feature instanceof EAttribute; |
| } |
| |
| /** |
| * Removes the given {@link EClassifier} from {@link EPackageProvider#class2classifiers the class mapping} |
| * . |
| * |
| * @param eCls |
| * the {@link EClassifier} to remove |
| */ |
| private void removeEClassifierClass(EClassifier eCls) { |
| final Class<?> instanceClass = getClass(eCls); |
| final Set<EClassifier> classifiers = class2classifiers.get(instanceClass); |
| if (classifiers != null) { |
| if (classifiers.size() == 1) { |
| class2classifiers.remove(instanceClass); |
| } else { |
| classifiers.remove(eCls); |
| } |
| } |
| classifier2class.remove(eCls); |
| } |
| |
| /** |
| * Register a new {@link EPackage}. |
| * |
| * @param ePackage |
| * the package to be registered. |
| * @return the registered {@link EPackage} if any, <code>null</code> otherwise |
| */ |
| public EPackage registerPackage(EPackage ePackage) { |
| final EPackage result; |
| |
| if (!("ecore".equals(ePackage.getName()) && !EcorePackage.eNS_URI.equals(ePackage.getNsURI()))) { |
| if (ePackage.getName() != null) { |
| Set<EPackage> set = ePackages.get(ePackage.getName()); |
| if (set == null) { |
| set = new LinkedHashSet<EPackage>(); |
| ePackages.put(ePackage.getName(), set); |
| } |
| boolean increasedSize = set.add(ePackage); |
| if (!increasedSize) { |
| // duplicate package |
| return null; |
| } |
| result = ePackage; |
| for (EClassifier eCls : ePackage.getEClassifiers()) { |
| registerEClassifierClass(eCls); |
| if (eCls instanceof EClass) { |
| registerFeatures((EClass)eCls); |
| registerSubTypes((EClass)eCls); |
| } |
| } |
| for (EPackage childPkg : ePackage.getESubpackages()) { |
| registerPackage(childPkg); |
| } |
| containingFeatures.clear(); |
| allContainingFeatures.clear(); |
| } else { |
| throw new IllegalStateException("Couldn't register package " + ePackage.getName() |
| + " because its name is null."); |
| } |
| } else { |
| result = null; |
| } |
| |
| return result; |
| } |
| |
| /** |
| * Registers the given {@link EClass} as a sub type of its {@link EClass#getESuperTypes() super types}. |
| * |
| * @param eCls |
| * the {@link EClass} |
| */ |
| private void registerSubTypes(EClass eCls) { |
| for (EClass superECls : eCls.getESuperTypes()) { |
| Set<EClass> types = subTypes.get(superECls); |
| if (types == null) { |
| types = new LinkedHashSet<EClass>(); |
| subTypes.put(superECls, types); |
| } |
| types.add(eCls); |
| } |
| } |
| |
| /** |
| * Registers {@link EStructuralFeature} for the given {@link EClass}. |
| * |
| * @param eCls |
| * the {@link EClass} to register |
| */ |
| private void registerFeatures(EClass eCls) { |
| for (EStructuralFeature feature : eCls.getEStructuralFeatures()) { |
| if (feature.getEType() instanceof EClass) { |
| Set<EStructuralFeature> possibleInverseFeatures = inverseFeatures.get(feature.getEType()); |
| if (possibleInverseFeatures == null) { |
| possibleInverseFeatures = new LinkedHashSet<EStructuralFeature>(); |
| inverseFeatures.put((EClass)feature.getEType(), possibleInverseFeatures); |
| } |
| possibleInverseFeatures.add(feature); |
| if (isContainingEStructuralFeature(feature)) { |
| Set<EStructuralFeature> possibleContainementFeatures = containingFeaturesForOneClassHierarchy |
| .get(feature.getEType()); |
| if (possibleContainementFeatures == null) { |
| possibleContainementFeatures = new LinkedHashSet<EStructuralFeature>(); |
| containingFeaturesForOneClassHierarchy.put((EClass)feature.getEType(), |
| possibleContainementFeatures); |
| } |
| possibleContainementFeatures.add(feature); |
| } |
| } |
| } |
| } |
| |
| /** |
| * Registers the given {@link EClassifier} to {@link EPackageProvider#class2classifiers the class mapping} |
| * . |
| * |
| * @param eCls |
| * the {@link EClassifier} to register |
| */ |
| private void registerEClassifierClass(EClassifier eCls) { |
| final Class<?> customClass = classifier2class.get(eCls); |
| final Class<?> instanceClass; |
| if (customClass != null) { |
| instanceClass = customClass; |
| } else { |
| instanceClass = eCls.getInstanceClass(); |
| classifier2class.put(eCls, instanceClass); |
| } |
| Set<EClassifier> classifiers = class2classifiers.get(instanceClass); |
| if (classifiers == null) { |
| classifiers = new LinkedHashSet<EClassifier>(); |
| class2classifiers.put(instanceClass, classifiers); |
| } |
| classifiers.add(eCls); |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.acceleo.query.runtime.IEPackageProvider#getTypes(java.lang.String, java.lang.String) |
| */ |
| @Override |
| public Collection<EClassifier> getTypes(String name, String classifierName) { |
| final Set<EClassifier> classifiers = new LinkedHashSet<EClassifier>(); |
| |
| final Set<EPackage> set = ePackages.get(name); |
| if (set != null) { |
| for (EPackage ePackage : set) { |
| EClassifier clazz = ePackage.getEClassifier(classifierName); |
| if (clazz != null) { |
| classifiers.add(clazz); |
| } |
| } |
| } |
| |
| return classifiers; |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.acceleo.query.runtime.IEPackageProvider#getType(java.lang.String, java.lang.String) |
| */ |
| @Override |
| public EClassifier getType(String name, String classifierName) { |
| Collection<EClassifier> result = getTypes(name, classifierName); |
| if (result.size() == 0) { |
| return null; |
| } else { |
| return result.iterator().next(); |
| } |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.acceleo.query.runtime.IEPackageProvider#getEnumLiterals(java.lang.String, |
| * java.lang.String, java.lang.String) |
| */ |
| @Override |
| public Collection<EEnumLiteral> getEnumLiterals(String name, String enumName, String literalName) { |
| Collection<EEnumLiteral> result = new LinkedHashSet<EEnumLiteral>(); |
| |
| final Set<EPackage> set = ePackages.get(name); |
| if (set != null) { |
| for (EPackage ePackage : set) { |
| EClassifier eClassifier = ePackage.getEClassifier(enumName); |
| if (eClassifier != null) { |
| EEnumLiteral literal = getEnumLiteral(eClassifier, literalName); |
| if (literal != null) { |
| result.add(literal); |
| } |
| } |
| } |
| } |
| |
| return result; |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.acceleo.query.runtime.IEPackageProvider#getType(java.lang.String) |
| */ |
| @Override |
| public EClassifier getType(String classifierName) { |
| EClassifier result = null; |
| for (Set<EPackage> ePkgs : ePackages.values()) { |
| for (EPackage ePackage : ePkgs) { |
| EClassifier foundClassifier = ePackage.getEClassifier(classifierName); |
| if (foundClassifier != null) { |
| if (result == null) { |
| result = foundClassifier; |
| } else { |
| String firstFullyQualifiedName = result.getEPackage().getName() + "." + result |
| .getName(); |
| String secondFullyQualifiedName = foundClassifier.getEPackage().getName() + "." |
| + foundClassifier.getName(); |
| String message = "Ambiguous classifier request. At least two classifiers matches %s : %s and %s"; |
| throw new IllegalStateException(String.format(message, classifierName, |
| firstFullyQualifiedName, secondFullyQualifiedName)); |
| } |
| } |
| } |
| } |
| return result; |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.acceleo.query.runtime.IEPackageProvider#getTypes(java.lang.String) |
| */ |
| @Override |
| public Collection<EClassifier> getTypes(String classifierName) { |
| Set<EClassifier> result = new LinkedHashSet<EClassifier>(); |
| for (Set<EPackage> ePkgs : ePackages.values()) { |
| for (EPackage ePackage : ePkgs) { |
| EClassifier foundClassifier = ePackage.getEClassifier(classifierName); |
| if (foundClassifier != null) { |
| result.add(foundClassifier); |
| } |
| } |
| } |
| return result; |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.acceleo.query.runtime.IEPackageProvider#getEnumLiteral(java.lang.String, |
| * java.lang.String, java.lang.String) |
| */ |
| @Override |
| public EEnumLiteral getEnumLiteral(String packageName, String enumName, String literalName) { |
| Collection<EEnumLiteral> result = getEnumLiterals(packageName, enumName, literalName); |
| if (result.size() == 0) { |
| return null; |
| } else { |
| return result.iterator().next(); |
| } |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.acceleo.query.runtime.IEPackageProvider#getEnumLiteral(java.lang.String, |
| * java.lang.String) |
| */ |
| @Override |
| public EEnumLiteral getEnumLiteral(String enumName, String literalName) { |
| EClassifier eClassifier = getType(enumName); |
| if (eClassifier == null) { |
| return null; |
| } else { |
| return getEnumLiteral(eClassifier, literalName); |
| } |
| |
| } |
| |
| /** |
| * Returns the enum literal that corresponds to the specified literal name in the specified classifier. |
| * |
| * @param eClassifier |
| * the {@link EEnum} in which to look for the literal. |
| * @param literalName |
| * the name of the literal to look for. |
| * @return the enum literal with the specified name in the specified {@link EEnum}. |
| */ |
| private EEnumLiteral getEnumLiteral(EClassifier eClassifier, String literalName) { |
| EEnumLiteral result; |
| if (eClassifier instanceof EEnum) { |
| result = ((EEnum)eClassifier).getEEnumLiteral(literalName); |
| } else { |
| result = null; |
| } |
| return result; |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.acceleo.query.runtime.IEPackageProvider#getEClassifiers(java.lang.Class) |
| */ |
| @Override |
| public Set<EClassifier> getEClassifiers(Class<?> cls) { |
| return class2classifiers.get(cls); |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.acceleo.query.runtime.IEPackageProvider#getClass(org.eclipse.emf.ecore.EClassifier) |
| */ |
| @Override |
| public Class<?> getClass(EClassifier eCls) { |
| return classifier2class.get(eCls); |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.acceleo.query.runtime.IEPackageProvider#isRegistered(org.eclipse.emf.ecore.EClassifier) |
| */ |
| public boolean isRegistered(EClassifier eCls) { |
| return classifier2class.containsKey(eCls); |
| } |
| |
| /** |
| * Registers a custom mapping from an {@link EClassifier} to its {@link Class}. |
| * |
| * @param eClassifier |
| * the {@link EClassifier} |
| * @param cls |
| * the {@link Class} |
| */ |
| public void registerCustomClassMapping(EClassifier eClassifier, Class<?> cls) { |
| // remove old mappings |
| final Class<?> oldClass = classifier2class.remove(eClassifier); |
| if (oldClass != null) { |
| final Set<EClassifier> eClassifiers = class2classifiers.get(oldClass); |
| if (eClassifiers.remove(eClassifier) && eClassifiers.isEmpty()) { |
| class2classifiers.remove(oldClass); |
| } |
| } |
| // add new mappings |
| classifier2class.put(eClassifier, cls); |
| Set<EClassifier> eClassifiers = class2classifiers.get(cls); |
| if (eClassifiers == null) { |
| eClassifiers = new LinkedHashSet<EClassifier>(); |
| class2classifiers.put(cls, eClassifiers); |
| } |
| eClassifiers.add(eClassifier); |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.acceleo.query.runtime.IEPackageProvider#getEStructuralFeatures(java.util.Set) |
| */ |
| @Override |
| public Set<EStructuralFeature> getEStructuralFeatures(Set<EClass> receiverEClasses) { |
| Set<EStructuralFeature> result = new LinkedHashSet<EStructuralFeature>(); |
| |
| for (EClass eCls : receiverEClasses) { |
| if (isRegistered(eCls)) { |
| result.addAll(eCls.getEAllStructuralFeatures()); |
| } |
| } |
| |
| return result; |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.acceleo.query.runtime.IEPackageProvider#getEClassifiers() |
| */ |
| @Override |
| public Set<EClassifier> getEClassifiers() { |
| final Set<EClassifier> result = new LinkedHashSet<EClassifier>(); |
| |
| for (Set<EPackage> ePkgs : ePackages.values()) { |
| for (EPackage ePkg : ePkgs) { |
| result.addAll(ePkg.getEClassifiers()); |
| } |
| } |
| |
| return result; |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.acceleo.query.runtime.IEPackageProvider#getEEnumLiterals() |
| */ |
| @Override |
| public Set<EEnumLiteral> getEEnumLiterals() { |
| final Set<EEnumLiteral> result = new LinkedHashSet<EEnumLiteral>(); |
| |
| for (Set<EPackage> ePkgs : ePackages.values()) { |
| for (EPackage ePkg : ePkgs) { |
| for (EClassifier eClassifier : ePkg.getEClassifiers()) { |
| if (eClassifier instanceof EEnum) { |
| result.addAll(((EEnum)eClassifier).getELiterals()); |
| } |
| } |
| } |
| } |
| |
| return result; |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.acceleo.query.runtime.IEPackageProvider#getContainingEClasses(org.eclipse.emf.ecore.EClass) |
| */ |
| @Override |
| public Set<EClass> getContainingEClasses(EClass eCls) { |
| final Set<EClass> result = new LinkedHashSet<EClass>(); |
| |
| for (EStructuralFeature feature : getContainingEStructuralFeatures(eCls)) { |
| result.add(feature.getEContainingClass()); |
| } |
| |
| return result; |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.acceleo.query.runtime.IEPackageProvider#getAllContainingEClasses(org.eclipse.emf.ecore.EClass) |
| */ |
| @Override |
| public Set<EClass> getAllContainingEClasses(EClass eCls) { |
| final Set<EClass> result = new LinkedHashSet<EClass>(); |
| |
| for (EStructuralFeature feature : getAllContainingEStructuralFeatures(eCls)) { |
| result.add(feature.getEContainingClass()); |
| } |
| |
| return result; |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.acceleo.query.runtime.IEPackageProvider2#getAllContainingEStructuralFeatures(org.eclipse.emf.ecore.EClass) |
| */ |
| public Set<EStructuralFeature> getAllContainingEStructuralFeatures(EClass type) { |
| Set<EStructuralFeature> result = allContainingFeatures.get(type); |
| |
| if (result == null) { |
| result = new LinkedHashSet<EStructuralFeature>(); |
| allContainingFeatures.put(type, result); |
| |
| final Set<EClass> knownECls = new HashSet<EClass>(); |
| Set<EStructuralFeature> previousAdded = new LinkedHashSet<EStructuralFeature>( |
| getContainingEStructuralFeatures(type)); |
| result.addAll(previousAdded); |
| while (!previousAdded.isEmpty()) { |
| Set<EStructuralFeature> currentAdded = new LinkedHashSet<EStructuralFeature>(); |
| for (EStructuralFeature feature : previousAdded) { |
| final EClass eContainingClass = feature.getEContainingClass(); |
| if (!knownECls.contains(eContainingClass)) { |
| for (EStructuralFeature parentFeature : getContainingEStructuralFeatures( |
| eContainingClass)) { |
| if (result.add(parentFeature)) { |
| knownECls.add(eContainingClass); |
| currentAdded.add(parentFeature); |
| } |
| } |
| } |
| } |
| previousAdded = currentAdded; |
| } |
| } |
| |
| return result; |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.acceleo.query.runtime.IEPackageProvider2#getContainingEStructuralFeatures(org.eclipse.emf.ecore.EClass) |
| */ |
| public Set<EStructuralFeature> getContainingEStructuralFeatures(EClass eCls) { |
| Set<EStructuralFeature> result = containingFeatures.get(eCls); |
| |
| if (result == null) { |
| result = new LinkedHashSet<EStructuralFeature>(); |
| containingFeatures.put(eCls, result); |
| |
| result.addAll(getContainingEStructuralFeaturesForOneEClassHierarchyLevel(eCls)); |
| for (EClass superType : eCls.getEAllSuperTypes()) { |
| result.addAll(getContainingEStructuralFeaturesForOneEClassHierarchyLevel(superType)); |
| } |
| for (EClass subType : getAllSubTypes(eCls)) { |
| result.addAll(getContainingEStructuralFeaturesForOneEClassHierarchyLevel(subType)); |
| } |
| // always add EObject EClass containing EStructuralFeatures |
| result.addAll(getContainingEStructuralFeaturesForOneEClassHierarchyLevel(EcorePackage.eINSTANCE |
| .getEObject())); |
| } |
| |
| return result; |
| } |
| |
| /** |
| * Gets the containing {@link EClass} for the given {@link EClass} and only it, not its sub {@link EClass} |
| * nor super {@link EClass}. |
| * |
| * @param eCls |
| * the {@link EClass} |
| * @return the containing {@link EClass} for the given {@link EClass} and only it, not its sub |
| * {@link EClass} nor super {@link EClass} |
| */ |
| private Set<EStructuralFeature> getContainingEStructuralFeaturesForOneEClassHierarchyLevel(EClass eCls) { |
| final Set<EStructuralFeature> result = new LinkedHashSet<EStructuralFeature>(); |
| |
| Set<EStructuralFeature> features = containingFeaturesForOneClassHierarchy.get(eCls); |
| if (features != null) { |
| result.addAll(features); |
| } |
| |
| return result; |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.acceleo.query.runtime.IEPackageProvider#getAllSubTypes(org.eclipse.emf.ecore.EClass) |
| */ |
| @Override |
| public Set<EClass> getAllSubTypes(EClass eCls) { |
| final Set<EClass> result = new LinkedHashSet<EClass>(); |
| |
| final Set<EClass> types = subTypes.get(eCls); |
| if (types != null) { |
| for (EClass type : types) { |
| result.add(type); |
| result.addAll(getAllSubTypes(type)); |
| } |
| } |
| |
| return result; |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.acceleo.query.runtime.IEPackageProvider#getContainedEClasses(org.eclipse.emf.ecore.EClass) |
| */ |
| @Override |
| public Set<EClass> getContainedEClasses(EClass eCls) { |
| final Set<EClass> result = new LinkedHashSet<EClass>(); |
| |
| if (isRegistered(eCls)) { |
| final Set<EStructuralFeature> features = new LinkedHashSet<EStructuralFeature>(eCls |
| .getEAllStructuralFeatures()); |
| for (EClass subECls : getAllSubTypes(eCls)) { |
| features.addAll(subECls.getEStructuralFeatures()); |
| } |
| for (EStructuralFeature feature : features) { |
| if (isContainingEStructuralFeature(feature) && feature.getEType() instanceof EClass) { |
| result.add((EClass)feature.getEType()); |
| } |
| } |
| } |
| |
| return result; |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.acceleo.query.runtime.IEPackageProvider#getAllContainedEClasses(org.eclipse.emf.ecore.EClass) |
| */ |
| @Override |
| public Set<EClass> getAllContainedEClasses(EClass eCls) { |
| final Set<EClass> direcltyContainedEClasses = getContainedEClasses(eCls); |
| final Set<EClass> result = new LinkedHashSet<EClass>(direcltyContainedEClasses); |
| |
| Set<EClass> added = new LinkedHashSet<EClass>(direcltyContainedEClasses); |
| while (!added.isEmpty()) { |
| final Set<EClass> toDig = new LinkedHashSet<EClass>(); |
| for (EClass a : added) { |
| for (EClass contained : getContainedEClasses(a)) { |
| if (result.add(contained)) { |
| toDig.add(contained); |
| } |
| } |
| } |
| added = toDig; |
| } |
| |
| return result; |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.acceleo.query.runtime.IEPackageProvider#getInverseEClasses(org.eclipse.emf.ecore.EClass) |
| */ |
| @Override |
| public Set<EClass> getInverseEClasses(EClass eCls) { |
| final Set<EClass> result = new LinkedHashSet<EClass>(); |
| |
| result.addAll(getInverseClassesForOneEClassHierarchyLevel(eCls)); |
| for (EClass superType : eCls.getEAllSuperTypes()) { |
| result.addAll(getInverseClassesForOneEClassHierarchyLevel(superType)); |
| } |
| for (EClass subType : getAllSubTypes(eCls)) { |
| result.addAll(getInverseClassesForOneEClassHierarchyLevel(subType)); |
| } |
| // always add EObject EClass containing EClasses |
| for (EClass eObjectType : getInverseClassesForOneEClassHierarchyLevel(EcorePackage.eINSTANCE |
| .getEObject())) { |
| result.add(eObjectType); |
| } |
| |
| return result; |
| } |
| |
| /** |
| * Gets inverse {@link EClass} for the given {@link EClass} and only it, not its sub {@link EClass} nor |
| * super {@link EClass}. |
| * |
| * @param eCls |
| * the {@link EClass} |
| * @return the containing {@link EClass} for the given {@link EClass} and only it, not its sub |
| * {@link EClass} nor super {@link EClass} |
| */ |
| private Set<EClass> getInverseClassesForOneEClassHierarchyLevel(EClass eCls) { |
| final Set<EClass> result = new LinkedHashSet<EClass>(); |
| |
| Set<EStructuralFeature> features = inverseFeatures.get(eCls); |
| if (features != null) { |
| for (EStructuralFeature feature : features) { |
| result.add(feature.getEContainingClass()); |
| } |
| } |
| |
| return result; |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.acceleo.query.runtime.IEPackageProvider#getFollowingSiblingsEClasses(org.eclipse.emf.ecore.EClass) |
| */ |
| @Override |
| public Set<EClass> getFollowingSiblingsEClasses(EClass eCls) { |
| final Set<EClass> result = new LinkedHashSet<EClass>(); |
| |
| final Set<EStructuralFeature> containingEStructuralFeatures = getContainingEStructuralFeatures(eCls); |
| final Set<EStructuralFeature> followingEStructuralFeatures = new LinkedHashSet<EStructuralFeature>(); |
| for (EStructuralFeature feature : containingEStructuralFeatures) { |
| followingEStructuralFeatures.addAll(getFollowingSiblingEStructuralFeatures(feature)); |
| } |
| |
| for (EStructuralFeature feature : followingEStructuralFeatures) { |
| if (isContainingEStructuralFeature(feature) && feature.getEType() instanceof EClass) { |
| result.add((EClass)feature.getEType()); |
| } |
| } |
| |
| return result; |
| } |
| |
| /** |
| * Gets the {@link Set} of following {@link EStructuralFeature} of the given {@link EStructuralFeature}, |
| * if the given {@link EStructuralFeature} is {@link EStructuralFeature#isMany() many} it's included in |
| * the result. |
| * |
| * @param feature |
| * the {@link EStructuralFeature} |
| * @return the {@link Set} of following {@link EStructuralFeature} of the given {@link EStructuralFeature} |
| * , if the given {@link EStructuralFeature} is {@link EStructuralFeature#isMany() many} it's |
| * included in the result |
| */ |
| private Set<EStructuralFeature> getFollowingSiblingEStructuralFeatures(EStructuralFeature feature) { |
| final Set<EStructuralFeature> result = new LinkedHashSet<EStructuralFeature>(); |
| |
| if (feature.isMany()) { |
| result.add(feature); |
| } |
| |
| boolean add = false; |
| for (EStructuralFeature childFeature : feature.getEContainingClass().getEStructuralFeatures()) { |
| if (add && isContainingEStructuralFeature(childFeature)) { |
| result.add(childFeature); |
| } |
| add = add || childFeature == feature; |
| } |
| |
| for (EClass eCls : getAllSubTypes(feature.getEContainingClass())) { |
| for (EStructuralFeature childFeature : eCls.getEStructuralFeatures()) { |
| if (isContainingEStructuralFeature(childFeature)) { |
| result.add(childFeature); |
| } |
| } |
| } |
| |
| return result; |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.acceleo.query.runtime.IEPackageProvider#getPrecedingSiblingsEClasses(org.eclipse.emf.ecore.EClass) |
| */ |
| @Override |
| public Set<EClass> getPrecedingSiblingsEClasses(EClass eCls) { |
| final Set<EClass> result = new LinkedHashSet<EClass>(); |
| |
| final Set<EStructuralFeature> containingEStructuralFeatures = getContainingEStructuralFeatures(eCls); |
| final Set<EStructuralFeature> precedingEStructuralFeatures = new LinkedHashSet<EStructuralFeature>(); |
| for (EStructuralFeature feature : containingEStructuralFeatures) { |
| precedingEStructuralFeatures.addAll(getPrecedingSiblingEStructuralFeatures(feature)); |
| } |
| |
| for (EStructuralFeature feature : precedingEStructuralFeatures) { |
| if (feature.getEType() instanceof EClass) { |
| result.add((EClass)feature.getEType()); |
| } |
| } |
| |
| return result; |
| } |
| |
| /** |
| * Gets the {@link Set} of preceding {@link EStructuralFeature} of the given {@link EStructuralFeature}, |
| * if the given {@link EStructuralFeature} is {@link EStructuralFeature#isMany() many} it's included in |
| * the result. |
| * |
| * @param feature |
| * the {@link EStructuralFeature} |
| * @return the {@link Set} of preceding {@link EStructuralFeature} of the given {@link EStructuralFeature} |
| * , if the given {@link EStructuralFeature} is {@link EStructuralFeature#isMany() many} it's |
| * included in the result |
| */ |
| private Set<EStructuralFeature> getPrecedingSiblingEStructuralFeatures(EStructuralFeature feature) { |
| final Set<EStructuralFeature> result = new LinkedHashSet<EStructuralFeature>(); |
| |
| for (EStructuralFeature childFeature : feature.getEContainingClass().getEAllStructuralFeatures()) { |
| if (childFeature == feature) { |
| break; |
| } |
| if (isContainingEStructuralFeature(childFeature)) { |
| result.add(childFeature); |
| } |
| } |
| |
| if (feature.isMany()) { |
| result.add(feature); |
| } |
| |
| return result; |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.acceleo.query.runtime.IEPackageProvider#getSiblingsEClasses(org.eclipse.emf.ecore.EClass) |
| */ |
| @Override |
| public Set<EClass> getSiblingsEClasses(EClass eCls) { |
| final Set<EClass> result = new LinkedHashSet<EClass>(); |
| |
| final Set<EStructuralFeature> containingEStructuralFeatures = getContainingEStructuralFeatures(eCls); |
| final Set<EStructuralFeature> siblingEStructuralFeatures = new LinkedHashSet<EStructuralFeature>(); |
| for (EStructuralFeature feature : containingEStructuralFeatures) { |
| siblingEStructuralFeatures.addAll(getSiblingEStructuralFeatures(feature)); |
| } |
| |
| for (EStructuralFeature feature : siblingEStructuralFeatures) { |
| if (isContainingEStructuralFeature(feature) && feature.getEType() instanceof EClass) { |
| result.add((EClass)feature.getEType()); |
| } |
| } |
| |
| return result; |
| } |
| |
| /** |
| * Gets the {@link Set} of sibling {@link EStructuralFeature} of the given {@link EStructuralFeature}, if |
| * the given {@link EStructuralFeature} is {@link EStructuralFeature#isMany() many} it's included in the |
| * result. |
| * |
| * @param feature |
| * the {@link EStructuralFeature} |
| * @return the {@link Set} of sibling {@link EStructuralFeature} of the given {@link EStructuralFeature}, |
| * if the given {@link EStructuralFeature} is {@link EStructuralFeature#isMany() many} it's |
| * included in the result |
| */ |
| private Set<EStructuralFeature> getSiblingEStructuralFeatures(EStructuralFeature feature) { |
| final Set<EStructuralFeature> preceding = getPrecedingSiblingEStructuralFeatures(feature); |
| final Set<EStructuralFeature> following = getFollowingSiblingEStructuralFeatures(feature); |
| final Set<EStructuralFeature> result = new LinkedHashSet<EStructuralFeature>(preceding.size() |
| + following.size()); |
| |
| result.addAll(preceding); |
| result.addAll(following); |
| |
| return result; |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.acceleo.query.runtime.IEPackageProvider#getRegisteredEPackages() |
| */ |
| @Override |
| public Set<EPackage> getRegisteredEPackages() { |
| final LinkedHashSet<EPackage> res = new LinkedHashSet<EPackage>(); |
| |
| for (Set<EPackage> ePkgs : ePackages.values()) { |
| res.addAll(ePkgs); |
| } |
| |
| return res; |
| } |
| } |