blob: 114f6c413636d231250756db400ccc4da7749c95 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2011, 2018 Willink Transformations and others.
* All rights reserved. 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
* http://www.eclipse.org/legal/epl-v20.html
*
* Contributors:
* E.D.Willink - initial API and implementation
*******************************************************************************/
package org.eclipse.ocl.xtext.completeocl.as2cs;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.emf.common.util.TreeIterator;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.ocl.pivot.Annotation;
import org.eclipse.ocl.pivot.Constraint;
import org.eclipse.ocl.pivot.ExpressionInOCL;
import org.eclipse.ocl.pivot.LanguageExpression;
import org.eclipse.ocl.pivot.Model;
import org.eclipse.ocl.pivot.NamedElement;
import org.eclipse.ocl.pivot.Namespace;
import org.eclipse.ocl.pivot.Operation;
import org.eclipse.ocl.pivot.PivotFactory;
import org.eclipse.ocl.pivot.PivotPackage;
import org.eclipse.ocl.pivot.Property;
import org.eclipse.ocl.pivot.internal.manager.PivotMetamodelManager;
import org.eclipse.ocl.pivot.internal.utilities.EnvironmentFactoryInternal;
import org.eclipse.ocl.pivot.internal.utilities.PivotUtilInternal;
import org.eclipse.ocl.pivot.resource.ASResource;
import org.eclipse.ocl.pivot.util.PivotSwitch;
import org.eclipse.ocl.pivot.utilities.ClassUtil;
import org.eclipse.ocl.pivot.utilities.NameUtil;
/**
*
*/
public class CompleteOCLSplitter
{
public static @Nullable ASResource separate(@NonNull EnvironmentFactoryInternal environmentFactory, @NonNull Resource asResource) {
List<@NonNull Constraint> allConstraints = new ArrayList<@NonNull Constraint>();
List<@NonNull LanguageExpression> allExpressionInOCLs = new ArrayList<@NonNull LanguageExpression>();
for (TreeIterator<EObject> tit = asResource.getAllContents(); tit.hasNext(); ) {
EObject eObject = tit.next();
if (eObject instanceof Constraint) {
allConstraints.add((Constraint) eObject);
}
else if (eObject instanceof Operation) {
LanguageExpression bodyExpression = ((Operation)eObject).getBodyExpression();
if (bodyExpression != null) {
allExpressionInOCLs.add(bodyExpression);
}
}
else if (eObject instanceof Property) {
LanguageExpression bodyExpression = ((Property)eObject).getOwnedExpression();
if (bodyExpression != null) {
allExpressionInOCLs.add(bodyExpression);
}
}
else if (eObject instanceof Annotation) {
tit.prune();
}
}
if (allConstraints.isEmpty() && allExpressionInOCLs.isEmpty()) {
return null;
}
URI uri = ClassUtil.nonNullState(asResource.getURI());
URI oclURI = PivotUtilInternal.getNonASURI(uri).appendFileExtension("ocl");
URI oclASuri = PivotUtilInternal.getASURI(oclURI); // xxx.ocl.ocl.oclas
ASResource oclResource = (ASResource) asResource.getResourceSet().createResource(oclASuri, ASResource.COMPLETE_OCL_CONTENT_TYPE);
if (oclResource != null) {
PivotMetamodelManager metamodelManager = environmentFactory.getMetamodelManager();
Separator separator = new Separator(metamodelManager, oclResource);
for (Constraint constraint : allConstraints) {
separator.doSwitch(constraint);
}
for (LanguageExpression opaqueExpression : allExpressionInOCLs) {
separator.doSwitch(opaqueExpression);
}
metamodelManager.installResource(oclResource);
}
return oclResource;
}
public static class Separator extends PivotSwitch<@Nullable EObject>
{
protected final @NonNull PivotMetamodelManager metamodelManager;
protected final @NonNull Resource separateResource;
private final @NonNull Map<@NonNull NamedElement, @NonNull NamedElement> map = new HashMap<@NonNull NamedElement, @NonNull NamedElement>();
public Separator(@NonNull PivotMetamodelManager metamodelManager, @NonNull Resource separateResource) {
this.metamodelManager = metamodelManager;
this.separateResource = separateResource;
}
@Override
public EObject caseClass(org.eclipse.ocl.pivot.Class object) {
org.eclipse.ocl.pivot.Package parent = ClassUtil.nonNullState(object.getOwningPackage());
org.eclipse.ocl.pivot.Package separateParent = getSeparate(parent);
List<org.eclipse.ocl.pivot.@NonNull Class> separateSiblings = ClassUtil.nullFree(separateParent.getOwnedClasses());
return cloneNamedElement(separateSiblings, object);
}
@Override
public EObject caseConstraint(Constraint object) {
NamedElement parent = (NamedElement) ClassUtil.nonNullState(object.eContainer());
NamedElement separateParent = getSeparate(parent);
EStructuralFeature eContainingFeature = object.eContainingFeature();
PivotUtilInternal.resetContainer(object); // Avoid a child-stealing detection
if (!eContainingFeature.isMany()) {
separateParent.eSet(eContainingFeature, object);
}
else {
@SuppressWarnings("unchecked") List<Constraint> eGet = (List<Constraint>)separateParent.eGet(eContainingFeature);
eGet.add(object);
}
return object;
}
@Override
public EObject caseExpressionInOCL(ExpressionInOCL object) {
NamedElement parent = (NamedElement) ClassUtil.nonNullState(object.eContainer());
NamedElement separateParent = getSeparate(parent);
if (separateParent instanceof Operation) {
PivotUtilInternal.resetContainer(object);
((Operation)separateParent).setBodyExpression(object);
}
if (separateParent instanceof Property) {
PivotUtilInternal.resetContainer(object);
((Property)separateParent).setOwnedExpression(object);
}
return object;
}
@Override
public EObject caseModel(Model object) {
String name = object.getName();
EObject container = object.eContainer();
assert container == null;
List<EObject> separateSiblings = separateResource.getContents();
Model separateObject = (Model) getElementByName(separateSiblings, name);
if (separateObject == null) {
separateObject = PivotFactory.eINSTANCE.createModel();
separateObject.setExternalURI(separateResource.getURI().toString());
separateSiblings.add(separateObject);
// metamodelManager.addRoot(separateObject);
}
return separateObject;
}
@Override
public EObject caseOperation(Operation object) {
org.eclipse.ocl.pivot.Class parent = ClassUtil.nonNullState(object.getOwningClass());
org.eclipse.ocl.pivot.Class separateParent = getSeparate(parent);
List<Operation> separateSiblings = separateParent.getOwnedOperations();
@SuppressWarnings("serial")
EcoreUtil.Copier copier = new EcoreUtil.Copier(false, true)
{
@Override
protected void copyContainment(EReference eReference, EObject eObject, EObject copyEObject) {
if (eReference == PivotPackage.Literals.OPERATION__OWNED_PARAMETERS) {
super.copyContainment(eReference, eObject, copyEObject);
}
}
};
Operation clone = (Operation) copier.copy(object);
copier.copyReferences();
separateSiblings.add(clone);
return clone;
}
@Override
public EObject casePackage(org.eclipse.ocl.pivot.Package object) {
String name = object.getName();
EObject container = object.eContainer();
assert container instanceof Namespace;
Namespace parent = (Namespace) container;
Namespace separateParent = (Namespace) map.get(parent);
if (separateParent == null) {
separateParent = (Namespace) doSwitch(parent);
map.put(parent, separateParent);
}
List<org.eclipse.ocl.pivot.Package> separateSiblings;
if (separateParent instanceof Model) {
separateSiblings = ((Model)separateParent).getOwnedPackages();
}
else {
separateSiblings = ((org.eclipse.ocl.pivot.Package)separateParent).getOwnedPackages();
}
org.eclipse.ocl.pivot.Package separateObject = NameUtil.getNameable(ClassUtil.<org.eclipse.ocl.pivot.Package>nullFree(separateSiblings), name);
if (separateObject == null) {
separateObject = (org.eclipse.ocl.pivot.Package) object.eClass().getEPackage().getEFactoryInstance().create(object.eClass());
separateObject.setName(name);
separateObject.setURI(object.getURI());
separateObject.setNsPrefix(object.getNsPrefix());
separateSiblings.add(separateObject);
}
return separateObject;
}
@Override
public EObject caseProperty(Property object) {
org.eclipse.ocl.pivot.Class parent = ClassUtil.nonNullState(object.getOwningClass());
org.eclipse.ocl.pivot.Class separateParent = getSeparate(parent);
List<Property> separateSiblings = separateParent.getOwnedProperties();
@SuppressWarnings("serial")
EcoreUtil.Copier copier = new EcoreUtil.Copier(false, true)
{
@Override
protected void copyContainment(EReference eReference, EObject eObject, EObject copyEObject) {
}
};
Property clone = (Property) copier.copy(object);
copier.copyReferences();
separateSiblings.add(clone);
return clone;
}
// @Override
// public EObject caseType(Type object) {
// org.eclipse.ocl.pivot.Package parent = object.getPackage();
// org.eclipse.ocl.pivot.Package separateParent = getSeparate(parent);
// List<org.eclipse.ocl.pivot.Class> separateSiblings = separateParent.getOwnedType();
// return cloneNamedElement(separateSiblings, object);
// }
protected <@NonNull T extends NamedElement> T cloneNamedElement(List<T> separateSiblings, T object) {
String name = object.getName();
@Nullable T separateObject = NameUtil.getNameable(separateSiblings, name);
if (separateObject == null) {
@SuppressWarnings("unchecked")@NonNull T castObject = (T) object.eClass().getEPackage().getEFactoryInstance().create(object.eClass());
separateObject = castObject;
separateObject.setName(name);
separateSiblings.add(separateObject);
}
return separateObject;
}
@Override
public @NonNull EObject doSwitch(EObject eObject)
{
return ClassUtil.nonNullState(super.doSwitch(eObject));
}
public NamedElement getElementByName(Iterable<? extends EObject> elements, String name) {
if (elements == null)
return null;
for (EObject element : elements)
if ((element instanceof NamedElement) && ClassUtil.safeEquals(name, ((NamedElement)element).getName()))
return (NamedElement)element;
return null;
}
protected <@NonNull T extends NamedElement> T getSeparate(T element) {
NamedElement separate = map.get(element);
if (separate == null) {
separate = (NamedElement) doSwitch(element);
map.put(element, separate);
}
@SuppressWarnings("unchecked")
T castSeparate = (T) separate;
return castSeparate;
}
protected org.eclipse.ocl.pivot.Package getSeparatePackage(org.eclipse.ocl.pivot.@NonNull Package element) {
org.eclipse.ocl.pivot.Package separate = (org.eclipse.ocl.pivot.Package) map.get(element);
if (separate == null) {
separate = (org.eclipse.ocl.pivot.Package) doSwitch(element);
map.put(element, separate);
}
return separate;
}
}
}