blob: c4cdda07d8de1387b89e45499684b1b3b04bebc5 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2007, 2011 THALES GLOBAL SERVICES.
* 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.sirius.ecore.extender.business.internal.accessor.ecore;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedHashSet;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EAttribute;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EDataType;
import org.eclipse.emf.ecore.EEnum;
import org.eclipse.emf.ecore.EEnumLiteral;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EPackage;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.EStructuralFeature.Setting;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
import org.eclipse.emf.ecore.util.ECrossReferenceAdapter;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.sirius.ecore.extender.business.api.accessor.AbstractMetamodelExtender;
import org.eclipse.sirius.ecore.extender.business.api.accessor.EcoreMetamodelDescriptor;
import org.eclipse.sirius.ecore.extender.business.api.accessor.ExtensionFeatureDescription;
import org.eclipse.sirius.ecore.extender.business.api.accessor.MetamodelDescriptor;
import org.eclipse.sirius.ext.emf.EReferencePredicate;
import com.google.common.base.Predicates;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.Iterables;
import com.google.common.collect.Iterators;
import com.google.common.collect.Multimap;
/**
* This metamodel Extender accesses the intrinsic data of an EObject.
*
* @author cbrun
*
*/
public class EcoreIntrinsicExtender extends AbstractMetamodelExtender {
private static final String SEPARATOR = "."; //$NON-NLS-1$
private static PackageRegistryIndex platformIndex = new PackageRegistryIndex(EPackage.Registry.INSTANCE, Predicates.<EPackage> alwaysTrue());
private Multimap<String, EClass> viewpointIndex = HashMultimap.create();
private Collection<? extends MetamodelDescriptor> lastDescriptors;
@Override
public EObject createInstance(final String name) {
EObject result = null;
final Iterator<EClass> it = getEClassesFromName(name);
while (result == null && it.hasNext()) {
final EClass eClass = it.next();
if (!eClass.isAbstract()) {
result = EcoreUtil.create(eClass);
}
}
if (result == null && name != null && name.indexOf("#") > 0) { //$NON-NLS-1$
final URI eClassURI = URI.createURI(name);
final EObject eobj = new ResourceSetImpl().getEObject(eClassURI, true);
if (eobj instanceof EClass) {
result = EcoreUtil.create((EClass) eobj);
}
}
return result;
}
@Override
public boolean eIsKnownType(final String name) {
return findFirstEClassFromName(name) != null;
}
@Override
@SuppressWarnings("unchecked")
public Object eAdd(final EObject instance, final String name, final Object value) {
if (eValid(instance, name)) {
if (eIsMany(instance, name).booleanValue()) {
final Object object = instance.eGet(instance.eClass().getEStructuralFeature(name));
if (object instanceof Collection && value instanceof Collection) {
((Collection<Object>) object).addAll((Collection<Object>) value);
} else if (object instanceof Collection && value != null) {
((Collection<Object>) object).add(value);
}
} else {
eSet(instance, name, value);
}
return instance;
}
return null;
}
@Override
public Iterator<EObject> eContents(final EObject root) {
return root.eContents().iterator();
}
@Override
public Object eClear(final EObject instance, final String name) {
if (eValid(instance, name)) {
final EStructuralFeature feat = instance.eClass().getEStructuralFeature(name);
final Object value = instance.eGet(feat);
if (value != null) {
if (value instanceof Collection) {
((Collection<?>) value).clear();
} else {
instance.eSet(feat, null);
}
}
return instance;
}
return null;
}
@Override
public EObject eContainer(final EObject instance) {
return instance.eContainer();
}
@Override
public String eContainingFeatureName(final EObject objectToRemove) {
if (objectToRemove.eContainingFeature() != null) {
return objectToRemove.eContainingFeature().getName();
}
return null;
}
@Override
public EObject eDelete(final EObject objectToRemove, final ECrossReferenceAdapter xref) {
return eDelete(objectToRemove, xref, null);
}
@Override
public EObject eDelete(EObject objectToRemove, ECrossReferenceAdapter xref, EReferencePredicate isReferencesToIgnorePredicate) {
if (xref == null) {
// If no cross referencer can be found,
// we simply remove the element from its container
EcoreUtil.delete(objectToRemove);
} else {
// Step 1: remove all references to the element to delete
eRemoveInverseCrossReferences(objectToRemove, xref, isReferencesToIgnorePredicate);
// Step 2: remove the element from its container
EcoreUtil.remove(objectToRemove);
}
return objectToRemove;
}
@Override
public Collection<EObject> eRemoveInverseCrossReferences(EObject eObject, ECrossReferenceAdapter xref, EReferencePredicate isReferencesToIgnorePredicate) {
Collection<EObject> impactedEObjects = new LinkedHashSet<EObject>();
Collection<Setting> inverseReferences = xref.getInverseReferences(eObject, true);
Collection<Setting> containmentReferences = getContainmentReferences(inverseReferences);
Collection<Setting> otherReferences = getNonContainmentReferences(inverseReferences);
for (EStructuralFeature.Setting setting : otherReferences) {
// If reference is changeable and should not be ignored
boolean isChangeableFeature = setting.getEStructuralFeature().isChangeable();
boolean isFeatureToIgnore = isReferencesToIgnorePredicate != null && setting.getEStructuralFeature() instanceof EReference
&& isReferencesToIgnorePredicate.apply((EReference) setting.getEStructuralFeature());
if (isChangeableFeature && !isFeatureToIgnore) {
// we delete it
EcoreUtil.remove(setting, eObject);
impactedEObjects.add(setting.getEObject());
}
}
for (EStructuralFeature.Setting setting : containmentReferences) {
// If reference is changeable and should not be ignored
boolean isChangeableFeature = setting.getEStructuralFeature().isChangeable();
boolean isFeatureToIgnore = isReferencesToIgnorePredicate != null && setting.getEStructuralFeature() instanceof EReference
&& isReferencesToIgnorePredicate.apply((EReference) setting.getEStructuralFeature());
if (isChangeableFeature && !isFeatureToIgnore) {
// we delete it
EcoreUtil.remove(setting, eObject);
impactedEObjects.add(setting.getEObject());
}
}
return impactedEObjects;
}
private Collection<Setting> getContainmentReferences(Collection<Setting> inverseReferences) {
Collection<Setting> containmentReferences = new ArrayList<EStructuralFeature.Setting>();
for (EStructuralFeature.Setting setting : inverseReferences) {
EStructuralFeature eStructuralFeature = setting.getEStructuralFeature();
if (eStructuralFeature instanceof EReference) {
EReference eReference = (EReference) eStructuralFeature;
if (eReference.isContainment()) {
containmentReferences.add(setting);
}
}
}
return containmentReferences;
}
private Collection<Setting> getNonContainmentReferences(Collection<Setting> inverseReferences) {
Collection<Setting> containmentReferences = new ArrayList<EStructuralFeature.Setting>();
for (EStructuralFeature.Setting setting : inverseReferences) {
EStructuralFeature eStructuralFeature = setting.getEStructuralFeature();
if (eStructuralFeature instanceof EReference) {
EReference eReference = (EReference) eStructuralFeature;
if (!eReference.isContainment()) {
containmentReferences.add(setting);
}
}
}
return containmentReferences;
}
@Override
public Object eGet(final EObject instance, final String name) {
if (instance.eClass().getEStructuralFeature(name) != null) {
return instance.eGet(instance.eClass().getEStructuralFeature(name));
}
// do nothing on error if we don't find the value, then may be
// another extender will !
return null;
}
@Override
public boolean eInstanceOf(final EObject instance, final String name) {
if ("EObject".equals(name) && instance != null) { //$NON-NLS-1$
return true;
}
boolean result = eInstanceOf(instance.eClass(), name);
if (!result && name != null && name.indexOf("#") > 0) { //$NON-NLS-1$
try {
final URI eClassURI = URI.createURI(name);
final EObject eobj = new ResourceSetImpl().getEObject(eClassURI, true);
if (eobj instanceof EClass) {
result = ((EClass) eobj).isInstance(instance);
}
// CHECKSTYLE:OFF
} catch (Exception e) {
// then it's not a valid URI, nothing more to do ! We really
// can't know what exception will pops up :'(
}
// CHECKSTYLE:ONN
}
return result;
}
private boolean eInstanceOf(final EClass eClass, final String superClassName) {
boolean result = false;
if (eClass.getName().equals(superClassName)) {
return true;
}
Iterator<EClass> it = getEClassesFromName(superClassName);
while (!result && it.hasNext()) {
EClass possibleSuperType = it.next();
result = possibleSuperType.isSuperTypeOf(eClass);
}
return result;
}
@Override
public Boolean eIsContainment(final EObject instance, final String featureName) {
Boolean result = null;
if (instance.eClass().getEStructuralFeature(featureName) instanceof EReference) {
result = new Boolean(((EReference) instance.eClass().getEStructuralFeature(featureName)).isContainment());
}
if (result == null && instance.eClass().getEStructuralFeature(featureName) instanceof EAttribute) {
result = Boolean.TRUE;
}
return result;
}
@Override
public Boolean eIsMany(final EObject instance, final String featureName) {
if (instance.eClass().getEStructuralFeature(featureName) != null) {
return new Boolean(instance.eClass().getEStructuralFeature(featureName).isMany());
}
return null;
}
@Override
public Object eRemove(final EObject instance, final String name, final Object value) {
if (eValid(instance, name)) {
EcoreUtil.remove(instance, instance.eClass().getEStructuralFeature(name), value);
return value;
}
return null;
}
@Override
public Object eSet(final EObject instance, final String name, final Object value) {
if (eValid(instance, name)) {
final EStructuralFeature feature = instance.eClass().getEStructuralFeature(name);
if (feature.getEType() instanceof EEnum && (value instanceof String || value instanceof Integer)) {
// Try to retrieve the expected literal.
EEnumLiteral literal = getEnumLiteral((EEnum) feature.getEType(), value);
if (literal != null) {
instance.eSet(feature, literal.getInstance());
}
} else if (feature instanceof EAttribute && value instanceof String) {
final EDataType attributeType = ((EAttribute) feature).getEAttributeType();
final Object objectValue = EcoreUtil.createFromString(attributeType, (String) value);
instance.eSet(feature, objectValue);
} else {
instance.eSet(feature, value);
}
return instance;
}
return null;
}
private EEnumLiteral getEnumLiteral(final EEnum eenum, final Object value) {
EEnumLiteral literal = null;
if (value instanceof Integer) {
literal = eenum.getEEnumLiteral((Integer) value);
} else if (value instanceof String) {
literal = eenum.getEEnumLiteral((String) value);
if (literal == null) {
literal = eenum.getEEnumLiteralByLiteral((String) value);
}
}
return literal;
}
@Override
public boolean eValid(final EObject object, final String name) {
return object.eClass().getEStructuralFeature(name) != null;
}
@Override
public Iterator<String> getContributedAttributeNames(final EObject next) {
final Collection<String> attributeNames = new ArrayList<String>();
final Iterator<EAttribute> it = next.eClass().getEAllAttributes().iterator();
while (it.hasNext()) {
final EAttribute attr = it.next();
attributeNames.add(attr.getName());
}
return attributeNames.iterator();
}
@Override
public Iterator<String> getContributedReferenceNames(final EObject instance) {
final Collection<String> referencesNames = new ArrayList<String>();
final Iterator<EReference> it = instance.eClass().getEAllReferences().iterator();
while (it.hasNext()) {
final EReference ref = it.next();
referencesNames.add(ref.getName());
}
return referencesNames.iterator();
}
@Override
public boolean hasExtension(final EObject next) {
return false;
}
@Override
public void init(final ResourceSet set) {
// platformIndex.init();
}
private void addTypesToSiriusIndex(final EPackage value) {
for (EClass cur : Iterables.filter(value.getEClassifiers(), EClass.class)) {
viewpointIndex.put(cur.getName(), cur);
viewpointIndex.put(value.getName() + EcoreIntrinsicExtender.SEPARATOR + cur.getName(), cur);
}
}
@Override
public boolean isExtension(final EObject next) {
return false;
}
private Iterator<EClass> getEClassesFromName(final String name) {
return Iterators.concat(viewpointIndex.get(name).iterator(), platformIndex.getEClassesFromName(name).iterator());
}
private EClass findFirstEClassFromName(final String name) {
Iterator<EClass> it = getEClassesFromName(name);
if (it.hasNext()) {
return it.next();
}
return null;
}
/**
* Create a new instance.
*
* @param eClass
* any EClass.
* @return instance built from the EClass.
*/
public EObject createInstance(final EClass eClass) {
return EcoreUtil.create(eClass);
}
@Override
public void dispose() {
// platformIndex.clear();
}
@Override
public String getQualifiedName(final EObject element, final boolean b) {
return EMFUtil.getQualifiedName(element, b);
}
@Override
public boolean isExtension(final EObject next, final String name) {
return false;
}
@Override
public Collection<ExtensionFeatureDescription> getAllExtensionFeatureDescriptions(final EObject target) {
return Collections.emptyList();
}
@Override
public boolean preventFromBrowsing(final EObject root) {
return false;
}
@Override
public void updateMetamodels(final Collection<? extends MetamodelDescriptor> metamodelDescriptors) {
if (lastDescriptors != null) {
metamodelDescriptors.removeAll(lastDescriptors);
}
final Iterator<? extends MetamodelDescriptor> it = metamodelDescriptors.iterator();
while (it.hasNext()) {
final Object obj = it.next();
if (obj instanceof EcoreMetamodelDescriptor) {
final EPackage pak = ((EcoreMetamodelDescriptor) obj).resolve();
if (pak != null) {
addTypesToSiriusIndex(pak);
Iterator<EPackage> subPack = Iterators.filter(pak.eAllContents(), EPackage.class);
while (subPack.hasNext()) {
addTypesToSiriusIndex(subPack.next());
}
}
}
}
lastDescriptors = metamodelDescriptors;
}
}