/******************************************************************************* * Copyright (c) 2011, 2015 Willink Transformations and others. * 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: * E.D.Willink - initial API and implementation *******************************************************************************/ package org.eclipse.ocl.xtext.completeocl.as2cs; import java.util.ArrayList; import java.util.Collections; 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<Constraint> allConstraints = new ArrayList<Constraint>(); List<LanguageExpression> allExpressionInOCLs = new ArrayList<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()) { return null; } URI uri = asResource.getURI(); @SuppressWarnings("null")@NonNull 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<NamedElement, NamedElement> map = new HashMap<NamedElement, 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 = 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) 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) 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 = 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 if (separateParent != null) { separateSiblings = ((org.eclipse.ocl.pivot.Package)separateParent).getOwnedPackages(); } else { separateSiblings = Collections.emptyList(); } org.eclipse.ocl.pivot.Package separateObject = NameUtil.getNameable(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 = 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; } 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 <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.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; } } }