| /******************************************************************************* |
| * Copyright (c) 2016, 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.qvtd.umlx.qvtr2umlx; |
| |
| import java.util.ArrayList; |
| import java.util.Collections; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| |
| import org.eclipse.emf.common.util.URI; |
| import org.eclipse.emf.ecore.EClass; |
| import org.eclipse.emf.ecore.EClassifier; |
| import org.eclipse.emf.ecore.EObject; |
| import org.eclipse.emf.ecore.EStructuralFeature; |
| import org.eclipse.emf.ecore.EcorePackage; |
| import org.eclipse.emf.ecore.resource.Resource; |
| import org.eclipse.jdt.annotation.NonNull; |
| import org.eclipse.jdt.annotation.Nullable; |
| import org.eclipse.ocl.pivot.CollectionType; |
| import org.eclipse.ocl.pivot.Comment; |
| import org.eclipse.ocl.pivot.Element; |
| import org.eclipse.ocl.pivot.Import; |
| import org.eclipse.ocl.pivot.Model; |
| import org.eclipse.ocl.pivot.Namespace; |
| import org.eclipse.ocl.pivot.OCLExpression; |
| import org.eclipse.ocl.pivot.PrimitiveType; |
| import org.eclipse.ocl.pivot.Property; |
| import org.eclipse.ocl.pivot.StandardLibrary; |
| import org.eclipse.ocl.pivot.Type; |
| import org.eclipse.ocl.pivot.TypedElement; |
| import org.eclipse.ocl.pivot.Variable; |
| import org.eclipse.ocl.pivot.VariableDeclaration; |
| import org.eclipse.ocl.pivot.VariableExp; |
| import org.eclipse.ocl.pivot.internal.prettyprint.PrettyPrinter; |
| import org.eclipse.ocl.pivot.util.Visitable; |
| import org.eclipse.ocl.pivot.utilities.EnvironmentFactory; |
| import org.eclipse.ocl.pivot.utilities.NameUtil; |
| import org.eclipse.ocl.pivot.utilities.PivotConstants; |
| import org.eclipse.ocl.pivot.utilities.PivotUtil; |
| import org.eclipse.ocl.pivot.utilities.TracingOption; |
| import org.eclipse.ocl.pivot.utilities.TreeIterable; |
| import org.eclipse.qvtd.compiler.CompilerChainException; |
| import org.eclipse.qvtd.pivot.qvtbase.Function; |
| import org.eclipse.qvtd.pivot.qvtbase.FunctionParameter; |
| import org.eclipse.qvtd.pivot.qvtbase.Pattern; |
| import org.eclipse.qvtd.pivot.qvtbase.Predicate; |
| import org.eclipse.qvtd.pivot.qvtbase.TypedModel; |
| import org.eclipse.qvtd.pivot.qvtbase.utilities.QVTbaseUtil; |
| import org.eclipse.qvtd.pivot.qvtrelation.DomainPattern; |
| import org.eclipse.qvtd.pivot.qvtrelation.Key; |
| import org.eclipse.qvtd.pivot.qvtrelation.Relation; |
| import org.eclipse.qvtd.pivot.qvtrelation.RelationCallExp; |
| import org.eclipse.qvtd.pivot.qvtrelation.RelationDomain; |
| import org.eclipse.qvtd.pivot.qvtrelation.RelationModel; |
| import org.eclipse.qvtd.pivot.qvtrelation.RelationalTransformation; |
| import org.eclipse.qvtd.pivot.qvtrelation.SharedVariable; |
| import org.eclipse.qvtd.pivot.qvtrelation.util.AbstractExtendingQVTrelationVisitor; |
| import org.eclipse.qvtd.pivot.qvtrelation.utilities.QVTrelationUtil; |
| import org.eclipse.qvtd.pivot.qvttemplate.CollectionTemplateExp; |
| import org.eclipse.qvtd.pivot.qvttemplate.ObjectTemplateExp; |
| import org.eclipse.qvtd.pivot.qvttemplate.PropertyTemplateItem; |
| import org.eclipse.qvtd.pivot.qvttemplate.TemplateExp; |
| import org.eclipse.qvtd.umlx.RelDiagram; |
| import org.eclipse.qvtd.umlx.RelDomainNode; |
| import org.eclipse.qvtd.umlx.RelInvocationEdge; |
| import org.eclipse.qvtd.umlx.RelInvocationNode; |
| import org.eclipse.qvtd.umlx.RelPatternEdge; |
| import org.eclipse.qvtd.umlx.RelPatternNode; |
| import org.eclipse.qvtd.umlx.TxDiagram; |
| import org.eclipse.qvtd.umlx.TxKeyNode; |
| import org.eclipse.qvtd.umlx.TxPackageNode; |
| import org.eclipse.qvtd.umlx.TxParameterNode; |
| import org.eclipse.qvtd.umlx.TxPartNode; |
| import org.eclipse.qvtd.umlx.TxQueryNode; |
| import org.eclipse.qvtd.umlx.TxTypedModelNode; |
| import org.eclipse.qvtd.umlx.UMLXElement; |
| import org.eclipse.qvtd.umlx.UMLXFactory; |
| import org.eclipse.qvtd.umlx.UMLXModel; |
| import org.eclipse.qvtd.umlx.UMLXTypedElement; |
| import org.eclipse.qvtd.umlx.compiler.UMLXCompilerChain; |
| import org.eclipse.qvtd.umlx.utilities.UMLXUtil; |
| |
| import com.google.common.collect.Iterables; |
| |
| public class QVTr2UMLX |
| { |
| public static final @NonNull TracingOption DEAD_VARIABLE = new TracingOption(UMLXCompilerChain.PLUGIN_ID, "qvtr2umlx/dead-variable"); |
| |
| protected static abstract class AbstractVisitor extends AbstractExtendingQVTrelationVisitor<@Nullable UMLXElement, @NonNull QVTr2UMLX> |
| { |
| public AbstractVisitor(@NonNull QVTr2UMLX context) { |
| super(context); |
| } |
| |
| protected <T1 extends Element, T2 extends UMLXElement> @Nullable T2 create(@Nullable T1 source) { |
| if (source == null) { |
| return null; |
| } |
| @SuppressWarnings("unchecked") @Nullable T2 target = (T2) source.accept(this); |
| return target; |
| } |
| |
| protected <@NonNull T1 extends Element, T2 extends UMLXElement> void createAll(/*@NonNull*/ Iterable<T1> sources, /*@NonNull*/ List<? super T2> targets) { |
| for (T1 source : sources) { |
| @SuppressWarnings("unchecked") T2 target = (T2) source.accept(this); |
| if ((target != null) && (targets != null)) { |
| targets.add(target); |
| } |
| } |
| } |
| |
| protected void setReferredEType(@NonNull UMLXTypedElement umlxTypedElement, @NonNull TypedElement qvtrTypedElement) { |
| umlxTypedElement.setIsRequired(qvtrTypedElement.isIsRequired()); |
| Type qvtrType = PivotUtil.getType(qvtrTypedElement); |
| if (qvtrType instanceof CollectionType) { |
| CollectionType qvtrCollectionType = (CollectionType)qvtrType; |
| umlxTypedElement.setIsMany(true); |
| umlxTypedElement.setIsNullFree(qvtrCollectionType.isIsNullFree()); |
| umlxTypedElement.setIsOrdered(qvtrCollectionType.isOrdered()); |
| umlxTypedElement.setIsUnique(qvtrCollectionType.isUnique()); |
| qvtrType = PivotUtil.getElementalType(qvtrCollectionType); |
| } |
| umlxTypedElement.setReferredEClassifier(context.getEcoreOf(qvtrType)); |
| } |
| |
| protected <T extends UMLXElement> @NonNull T visit(@NonNull Class<T> umlxClass, @NonNull Element qvtrElement) { |
| UMLXElement umlxElement = qvtrElement.accept(this); |
| if (umlxElement == null) { |
| throw new IllegalArgumentException("Missing UMLX element for " + qvtrElement); |
| } |
| if (!umlxClass.isAssignableFrom(umlxElement.getClass())) { |
| throw new ClassCastException("UMLX element " + umlxElement + " cannot be cast to " + umlxClass); |
| } |
| @SuppressWarnings("unchecked")T castElement = (T)umlxElement; |
| return castElement; |
| } |
| |
| // @Override |
| // public @Nullable String visitOCLExpression(@NonNull OCLExpression qvtrExpression) { |
| // return PrettyPrinter.print(qvtrExpression); |
| // } |
| |
| @Override |
| public @Nullable UMLXElement visitOCLExpression(@NonNull OCLExpression qvtrExpression) { |
| RelDomainNode relDomainNode = context.getContainingRelDomainNode(qvtrExpression); |
| RelPatternNode relPatternExpressionNode = UMLXFactory.eINSTANCE.createRelPatternNode(); |
| context.install(qvtrExpression, relPatternExpressionNode); |
| for (String line : PrettyPrinter.print(qvtrExpression).split("\\n")) { |
| relPatternExpressionNode.getInitExpressionLines().add(line); |
| } |
| relDomainNode.getOwnedRelPatternNodes().add(relPatternExpressionNode); |
| return relPatternExpressionNode; |
| } |
| |
| @Override |
| public @Nullable RelPatternNode visitVariableExp(@NonNull VariableExp qvtrVariableExp) { |
| RelPatternNode relPatternNode = context.getUMLXElement(RelPatternNode.class, PivotUtil.getReferredVariable(qvtrVariableExp)); |
| return relPatternNode; |
| } |
| |
| @Override |
| public @Nullable UMLXElement visiting(@NonNull Visitable visitable) { |
| // System.out.println("Unsupported " + visitable.eClass().getName() + " for " + getClass().getSimpleName()); |
| // return null; |
| throw new IllegalArgumentException("Unsupported " + visitable.eClass().getName() + " for " + getClass().getSimpleName()); |
| } |
| } |
| |
| protected static class CreateRelationVisitor extends AbstractVisitor |
| { |
| protected final @NonNull Relation qvtrRelation; |
| private final @NonNull Map<@NonNull VariableDeclaration, @NonNull List<@NonNull RelationDomain>> variable2domains = new HashMap<>(); |
| private @Nullable List<@NonNull RelPatternNode> ownedPrimitiveNodes = null; |
| private final @NonNull RelDiagram relDiagram; |
| |
| public CreateRelationVisitor(@NonNull QVTr2UMLX context, @NonNull Relation qvtrRelation) { |
| super(context); |
| this.qvtrRelation = qvtrRelation; |
| for (@NonNull RelationDomain rDomain : QVTrelationUtil.getOwnedDomains(qvtrRelation)) { |
| analyzeTree(rDomain, rDomain); |
| } |
| Pattern rWhen = qvtrRelation.getWhen(); |
| if (rWhen != null) { |
| analyzeTree(rWhen, null); |
| } |
| Pattern rWhere = qvtrRelation.getWhere(); |
| if (rWhere != null) { |
| analyzeTree(rWhere, null); |
| } |
| for (@NonNull Variable rVariable : QVTrelationUtil.getOwnedVariables(qvtrRelation)) { |
| OCLExpression rExpression = rVariable.getOwnedInit(); |
| if (rExpression != null) { |
| List<@NonNull RelationDomain> referencedDomains = analyzeTree(rExpression, null); |
| for (@NonNull RelationDomain rDomain : referencedDomains) { |
| add(rVariable, rDomain); |
| } |
| } |
| } |
| this.relDiagram = UMLXFactory.eINSTANCE.createRelDiagram(); |
| } |
| |
| private @NonNull List<@NonNull RelationDomain> add(@NonNull VariableDeclaration variable, @Nullable RelationDomain rDomain) { |
| List<@NonNull RelationDomain> domains = variable2domains.get(variable); |
| if (domains == null) { |
| domains = new ArrayList<>(); |
| variable2domains.put(variable, domains); |
| } |
| if ((rDomain != null) && !domains.contains(rDomain)) { // FIXME null can be resolved from RelationCallExp arg |
| domains.add(rDomain); |
| } |
| return domains; |
| } |
| |
| private @NonNull List<@NonNull RelationDomain> analyzeTree(@NonNull Element rElement, @Nullable RelationDomain rDomain) { |
| List<@NonNull RelationDomain> referencedDomains = new ArrayList<>(); |
| for (EObject eObject : new TreeIterable(rElement, true)) { |
| VariableDeclaration variable =null; |
| if (eObject instanceof VariableExp) { |
| variable = PivotUtil.getReferredVariable((VariableExp)eObject); |
| } |
| else if (eObject instanceof TemplateExp) { |
| variable = QVTrelationUtil.getBindsTo((TemplateExp)eObject); |
| } |
| if (variable != null) { |
| for (@NonNull RelationDomain domain : add(variable, rDomain)) { |
| if (!referencedDomains.contains(domain)) { |
| referencedDomains.add(domain); |
| } |
| } |
| } |
| } |
| return referencedDomains; |
| } |
| |
| protected @NonNull RelPatternNode createRelPatternClassNode(@NonNull TypedElement qvtrTypedElement) { |
| RelPatternNode relPatternClassNode = UMLXFactory.eINSTANCE.createRelPatternNode(); |
| context.install(qvtrTypedElement, relPatternClassNode); |
| boolean isImplicit = (qvtrTypedElement instanceof Variable) && ((Variable)qvtrTypedElement).isIsImplicit(); |
| if (isImplicit) { |
| relPatternClassNode.setIsAnon(true); |
| relPatternClassNode.setName(""); |
| } |
| else { |
| relPatternClassNode.setIsAnon(false); |
| relPatternClassNode.setName(qvtrTypedElement.getName()); |
| } |
| setReferredEType(relPatternClassNode, qvtrTypedElement); |
| return relPatternClassNode; |
| } |
| |
| private @NonNull List<@NonNull RelPatternNode> getPrimitiveNodes() { |
| List<@NonNull RelPatternNode> ownedPrimitiveNodes2 = ownedPrimitiveNodes; |
| if (ownedPrimitiveNodes2 == null) { |
| RelDomainNode relDomainNode = context.getPrimitiveRelDomainNode(relDiagram); |
| ownedPrimitiveNodes = ownedPrimitiveNodes2 = UMLXUtil.Internal.getOwnedRelPatternNodesList(relDomainNode); |
| } |
| return ownedPrimitiveNodes2; |
| } |
| |
| @Override |
| public @NonNull String toString() { |
| StringBuilder s = new StringBuilder(); |
| s.append(qvtrRelation.getName()); |
| List<@NonNull VariableDeclaration> variables = new ArrayList<>(variable2domains.keySet()); |
| Collections.sort(variables, NameUtil.NAMEABLE_COMPARATOR); |
| for (@NonNull VariableDeclaration variable : variables) { |
| List<@NonNull RelationDomain> domains = variable2domains.get(variable); |
| assert domains != null; |
| s.append("\n\t'"); |
| s.append(variable.getName()); |
| s.append("' =>"); |
| for (@NonNull RelationDomain domain : domains) { |
| s.append(" '"); |
| s.append(domain.getName()); |
| s.append("'"); |
| } |
| } |
| return s.toString(); |
| } |
| |
| @Override |
| public @Nullable UMLXElement visitRelation(@NonNull Relation qvtrRelation) { |
| context.install(qvtrRelation, relDiagram); |
| relDiagram.setIsAbstract(qvtrRelation.isIsAbstract()); |
| relDiagram.setIsTop(qvtrRelation.isIsTopLevel()); |
| relDiagram.setName(qvtrRelation.getName()); |
| // |
| // Create the domains and their variables |
| // |
| createAll(QVTrelationUtil.getOwnedDomains(qvtrRelation), relDiagram.getOwnedRelDomainNodes()); |
| // |
| // Create the primitive domain and its variables |
| // |
| for (@NonNull Variable qvtrVariable : QVTrelationUtil.getOwnedVariables(qvtrRelation)) { |
| RelPatternNode relPatternClassNode = context.basicGetUMLXElement(RelPatternNode.class, qvtrVariable); |
| if (relPatternClassNode == null) { |
| relPatternClassNode = createRelPatternClassNode(qvtrVariable); |
| OCLExpression ownedInit = qvtrVariable.getOwnedInit(); |
| if (ownedInit != null) { |
| for (String line : PrettyPrinter.print(ownedInit).split("\\n")) { |
| relPatternClassNode.getInitExpressionLines().add(line); |
| } |
| } |
| List<@NonNull RelPatternNode> ownedNodes = null; |
| List<@NonNull RelationDomain> qvtrDomains = variable2domains.get(qvtrVariable); |
| if (qvtrDomains == null) { |
| DEAD_VARIABLE.println("Dead variable " + qvtrRelation.getName() + "." + qvtrVariable.getName()); |
| } |
| else if (qvtrDomains.size() == 1) { |
| RelationDomain qvtrDomain = qvtrDomains.get(0); |
| RelDomainNode relDomainNode = context.basicGetUMLXElement(RelDomainNode.class, qvtrDomain); |
| assert relDomainNode != null; |
| ownedNodes = UMLXUtil.Internal.getOwnedRelPatternNodesList(relDomainNode); |
| } |
| if (ownedNodes == null) { |
| ownedNodes = getPrimitiveNodes(); |
| } |
| ownedNodes.add(relPatternClassNode); |
| } |
| } |
| // |
| // Create the when predicate |
| // |
| Pattern qvtrWhen = qvtrRelation.getWhen(); |
| if (qvtrWhen != null) { |
| for (@NonNull Predicate qvtrPredicate : QVTrelationUtil.getOwnedPredicates(qvtrWhen)) { |
| QVTrelationUtil.getOwnedConditionExpression(qvtrPredicate).accept(this); |
| } |
| } |
| // |
| // Create the where predicate |
| // |
| Pattern qvtrWhere = qvtrRelation.getWhere(); |
| if (qvtrWhere != null) { |
| for (@NonNull Predicate qvtrPredicate : QVTrelationUtil.getOwnedPredicates(qvtrWhere)) { |
| QVTrelationUtil.getOwnedConditionExpression(qvtrPredicate).accept(this); |
| } |
| } |
| return relDiagram; |
| } |
| |
| @Override |
| public @Nullable UMLXElement visitRelationCallExp(@NonNull RelationCallExp qvtrRelationCallExp) { |
| Predicate qvtrPredicate = QVTrelationUtil.getContainingPredicate(qvtrRelationCallExp); |
| Relation qvtrRelation = QVTrelationUtil.getContainingRelation(qvtrRelationCallExp); |
| Boolean isWhen = null; |
| Pattern qvtrWhen = qvtrRelation.getWhen(); |
| Pattern qvtrWhere = qvtrRelation.getWhere(); |
| if ((qvtrWhen != null) && Iterables.contains(QVTrelationUtil.getOwnedPredicates(qvtrWhen), qvtrPredicate)) { |
| isWhen = true; |
| } |
| else if ((qvtrWhere != null) && Iterables.contains(QVTrelationUtil.getOwnedPredicates(qvtrWhere), qvtrPredicate)) { |
| isWhen = false; |
| } |
| RelDiagram relDiagram = context.getUMLXElement(RelDiagram.class, qvtrRelation); |
| RelInvocationNode relInvocationNode = UMLXFactory.eINSTANCE.createRelInvocationNode(); |
| context.install(qvtrRelationCallExp, relInvocationNode); |
| relInvocationNode.setIsThen(isWhen == Boolean.FALSE); |
| relDiagram.getOwnedRelInvocationNodes().add(relInvocationNode); |
| context.addReference(qvtrRelationCallExp); |
| return relInvocationNode; |
| } |
| |
| @Override |
| public @Nullable UMLXElement visitRelationDomain(@NonNull RelationDomain qvtrRelationDomain) { |
| RelDomainNode relDomainNode = UMLXFactory.eINSTANCE.createRelDomainNode(); |
| context.install(qvtrRelationDomain, relDomainNode); |
| TxTypedModelNode tyTypedModelNode = context.getUMLXElement(TxTypedModelNode.class, QVTrelationUtil.getTypedModel(qvtrRelationDomain)); |
| relDomainNode.setReferredTxTypedModelNode(tyTypedModelNode); |
| if (qvtrRelationDomain.isIsCheckable()) { |
| tyTypedModelNode.setCheck(true); |
| } |
| if (qvtrRelationDomain.isIsEnforceable()) { |
| tyTypedModelNode.setEnforce(true); |
| relDomainNode.setIsEnforced(true); |
| } |
| for (@NonNull EObject eObject : new TreeIterable(qvtrRelationDomain, false)) { |
| if (eObject instanceof TemplateExp) { |
| TemplateExp qvtrTemplateExp = (TemplateExp)eObject; |
| RelPatternNode relPatternClassNode = createRelPatternClassNode(QVTrelationUtil.getBindsTo(qvtrTemplateExp)); |
| context.install(qvtrTemplateExp, relPatternClassNode); |
| |
| |
| Variable qvtrVariable = qvtrTemplateExp.getBindsTo(); |
| List<@NonNull RelPatternNode> ownedNodes = null; |
| List<@NonNull RelationDomain> qvtrDomains = variable2domains.get(qvtrVariable); |
| if (qvtrDomains == null) { |
| DEAD_VARIABLE.println("Dead variable " + qvtrRelation.getName() + "." + qvtrVariable.getName()); |
| } |
| else if (qvtrDomains.size() == 1) { |
| ownedNodes = UMLXUtil.Internal.getOwnedRelPatternNodesList(relDomainNode); |
| } |
| if (ownedNodes == null) { |
| ownedNodes = getPrimitiveNodes(); |
| } |
| ownedNodes.add(relPatternClassNode); |
| if (eObject instanceof CollectionTemplateExp) { |
| CollectionTemplateExp qvtrCollectionTemplateExp = (CollectionTemplateExp)eObject; |
| Variable qvtrRestVariable = qvtrCollectionTemplateExp.getRest(); |
| if (qvtrRestVariable != null) { |
| RelPatternNode relPatternRestNode = createRelPatternClassNode(qvtrRestVariable); |
| ownedNodes.add(relPatternRestNode); |
| } |
| } |
| } |
| } |
| context.addReference(qvtrRelationDomain); |
| return relDomainNode; |
| } |
| } |
| |
| protected static class CreateTransformationVisitor extends AbstractVisitor |
| { |
| protected final @NonNull UMLXModel umlxModel; |
| private final @NonNull Map<org.eclipse.ocl.pivot.@NonNull Package, @NonNull TxPackageNode> asPackage2txPackageNode = new HashMap<>(); |
| |
| public CreateTransformationVisitor(@NonNull QVTr2UMLX context, @NonNull UMLXModel umlxModel) { |
| super(context); |
| this.umlxModel = umlxModel; |
| } |
| |
| @Override |
| public @Nullable UMLXElement visitFunction(@NonNull Function asFunction) { |
| TxQueryNode txQueryNode = UMLXFactory.eINSTANCE.createTxQueryNode(); |
| context.install(asFunction, txQueryNode); |
| txQueryNode.setName(asFunction.getName()); |
| setReferredEType(txQueryNode, asFunction); |
| OCLExpression bodyExpression = asFunction.getQueryExpression(); |
| if (bodyExpression != null) { |
| for (String line : PrettyPrinter.print(bodyExpression).split("\\n")) { |
| txQueryNode.getInitExpressionLines().add(line); |
| } |
| } |
| createAll(QVTrelationUtil.getOwnedParameters(asFunction), txQueryNode.getOwnedTxParameterNodes()); |
| return txQueryNode; |
| } |
| |
| @Override |
| public @Nullable UMLXElement visitFunctionParameter(@NonNull FunctionParameter asFunctionParameter) { |
| TxParameterNode txParameterNode = UMLXFactory.eINSTANCE.createTxParameterNode(); |
| context.install(asFunctionParameter, txParameterNode); |
| txParameterNode.setName(asFunctionParameter.getName()); |
| setReferredEType(txParameterNode, asFunctionParameter); |
| return txParameterNode; |
| } |
| |
| @Override |
| public @Nullable UMLXElement visitKey(@NonNull Key qvtrKey) { |
| TxKeyNode txKeyNode = UMLXFactory.eINSTANCE.createTxKeyNode(); |
| context.install(qvtrKey, txKeyNode); |
| txKeyNode.setReferredEClass((EClass) context.getEcoreOf(QVTrelationUtil.getIdentifies(qvtrKey))); |
| for (Property qvtrPart : QVTrelationUtil.getOwnedParts(qvtrKey)) { |
| TxPartNode txPartNode = UMLXFactory.eINSTANCE.createTxPartNode(); |
| // context.addTrace(usedPackage, txPartNode); |
| txPartNode.setReferredEStructuralFeature(context.getEcoreOf(qvtrPart)); |
| txKeyNode.getOwnedTxPartNodes().add(txPartNode); |
| } |
| for (@NonNull Property qvtrPart : QVTrelationUtil.getOwnedOppositeParts(qvtrKey)) { |
| TxPartNode txPartNode = UMLXFactory.eINSTANCE.createTxPartNode(); |
| // context.addTrace(usedPackage, txPartNode); |
| txPartNode.setReferredEStructuralFeature(context.getEcoreOf(qvtrPart)); |
| txPartNode.setIsOpposite(true); |
| txKeyNode.getOwnedTxPartNodes().add(txPartNode); |
| } |
| return txKeyNode; |
| } |
| |
| @Override |
| public @Nullable UMLXElement visitPackage(org.eclipse.ocl.pivot.@NonNull Package qvtrPackage) { |
| if (PivotConstants.ORPHANAGE_URI.equals(qvtrPackage.getURI())) { |
| return null; |
| } |
| // Package umlxPackage = context.createPackage(qvtrPackage); |
| createAll(PivotUtil.getOwnedClasses(qvtrPackage), null); //pOut.getOwnedClasses()); |
| createAll(PivotUtil.getOwnedPackages(qvtrPackage), null); //pOut.getOwnedPackages()); |
| // createAll(qvtrPackage.getOwnedComments(), pOut.getOwnedComments()); |
| return null; |
| } |
| |
| @Override |
| public @Nullable UMLXElement visitRelation(@NonNull Relation qvtrRelation) { |
| CreateRelationVisitor createRelationVisitor = new CreateRelationVisitor(context, qvtrRelation); |
| return qvtrRelation.accept(createRelationVisitor); |
| } |
| |
| @Override |
| public @Nullable UMLXElement visitRelationModel(@NonNull RelationModel qvtrModel) { |
| String externalURI = qvtrModel.getExternalURI(); |
| if (externalURI.endsWith(".qvtras")) { |
| externalURI = externalURI.replace(".qvtras", ".umlx"); |
| } |
| else if (externalURI.endsWith(".qvtr")) { |
| externalURI = externalURI.replace(".qvtr", ".umlx"); |
| } |
| // umlxModel.setExternalURI(externalURI); |
| context.install(qvtrModel, umlxModel); |
| // createAll(relationModel.getOwnedImports(), umlxModel.getOwnedImports()); |
| createAll(PivotUtil.getOwnedPackages(qvtrModel), null); //umlxModel.getOwnedPackages()); |
| // createAll(relationModel.getOwnedComments(), umlxModel.getOwnedComments()); |
| for (@NonNull Import qvtrImport : QVTrelationUtil.getOwnedImports(qvtrModel)) { |
| Namespace asNamespace = qvtrImport.getImportedNamespace(); |
| TxPackageNode txPackageNode = asPackage2txPackageNode.get(asNamespace); |
| if (txPackageNode != null) { |
| List<String> importAliases = txPackageNode.getImportAliases(); |
| String name = qvtrImport.getName(); |
| if (!importAliases.contains(name)) { |
| importAliases.add(name); |
| } |
| } |
| } |
| return null; |
| } |
| |
| @Override |
| public @Nullable UMLXElement visitRelationalTransformation(@NonNull RelationalTransformation qvtrTransformation) { |
| StringBuilder s = new StringBuilder(); |
| String packagePath = context.getPackagePath(s, QVTbaseUtil.getOwningPackage(qvtrTransformation)); |
| TxDiagram txDiagram = UMLXFactory.eINSTANCE.createTxDiagram(); |
| txDiagram.setName(qvtrTransformation.getName()); |
| txDiagram.setPackage(packagePath); |
| context.install(qvtrTransformation, txDiagram); |
| // |
| Iterable<@NonNull TypedModel> modelParameters = QVTrelationUtil.getModelParameters(qvtrTransformation); |
| for (@NonNull TypedModel qvtrTypedModel : modelParameters) { |
| if (!qvtrTypedModel.isIsTrace()) { |
| for (org.eclipse.ocl.pivot.@NonNull Package asPackage : QVTrelationUtil.getUsedPackages(qvtrTypedModel)) { |
| TxPackageNode txPackageNode = asPackage2txPackageNode.get(asPackage); |
| if (txPackageNode == null) { |
| txPackageNode = UMLXFactory.eINSTANCE.createTxPackageNode(); |
| // context.addTrace(usedPackage, txPackageNode); |
| txPackageNode.setReferredEPackage(asPackage.getEPackage()); |
| txDiagram.getOwnedTxPackageNodes().add(txPackageNode); |
| asPackage2txPackageNode.put(asPackage, txPackageNode); |
| } |
| } |
| } |
| } |
| // Collections.sort(txDiagram.getOwnedTxPackageNodes(), NameUtil.NAMEABLE_COMPARATOR); |
| // txTransformationNode.setOwnedContext(create(qvtrTransformation.getOwnedContext())); |
| // createAll(qvtrTransformation.getOwnedOperations(), txTransformationNode.getOwnedOperations()); |
| createAll(modelParameters, txDiagram.getOwnedTxTypedModelNodes()); |
| createAll(QVTrelationUtil.getOwnedKey(qvtrTransformation), txDiagram.getOwnedTxKeyNodes()); |
| createAll(QVTrelationUtil.getRule(qvtrTransformation), txDiagram.getOwnedRelDiagrams()); |
| createAll(QVTrelationUtil.getOwnedOperations(qvtrTransformation), txDiagram.getOwnedTxQueryNodes()); |
| // doRules(qvtrTransformation, txTransformationNode); |
| // createAll(qvtrTransformation.getOwnedComments(), txTransformationNode.getOwnedComments()); |
| umlxModel.getOwnedTxDiagrams().add(txDiagram); |
| return null; |
| } |
| |
| @Override |
| public @Nullable UMLXElement visitTypedModel(@NonNull TypedModel qvtrTypedModel) { |
| TxTypedModelNode txTypedModelNode = UMLXFactory.eINSTANCE.createTxTypedModelNode(); |
| context.install(qvtrTypedModel, txTypedModelNode); |
| String name = qvtrTypedModel.getName(); |
| txTypedModelNode.setName(name); |
| for (org.eclipse.ocl.pivot.@NonNull Package usedPackage : QVTrelationUtil.getUsedPackages(qvtrTypedModel)) { |
| TxPackageNode txPackageNode = asPackage2txPackageNode.get(usedPackage); |
| txTypedModelNode.getUsedTxPackageNodes().add(txPackageNode); |
| } |
| if (qvtrTypedModel.getDependsOn().size() > 0) { |
| context.addReference(qvtrTypedModel); |
| } |
| return txTypedModelNode; |
| } |
| } |
| |
| protected static class ReferenceVisitor extends AbstractVisitor |
| { |
| public ReferenceVisitor(@NonNull QVTr2UMLX context) { |
| super(context); |
| } |
| |
| @Override |
| public @Nullable UMLXElement visitCollectionTemplateExp(@NonNull CollectionTemplateExp qvtrCollectionTemplateExp) { |
| RelPatternNode relPatternNode = context.getUMLXElement(RelPatternNode.class, qvtrCollectionTemplateExp); |
| // CollectionType qvtrCollectionType = QVTrelationUtil.getReferredCollectionType(qvtrCollectionTemplateExp); |
| assert relPatternNode.isIsMany(); |
| // relPatternNode.setIsNullFree(qvtrCollectionType.isIsNullFree()); |
| // relPatternNode.setIsOrdered(qvtrCollectionType.isOrdered()); |
| // relPatternNode.setIsUnique(qvtrCollectionType.isUnique()); |
| int sourceIndex = 1; |
| for (@NonNull OCLExpression qvtrMember : QVTrelationUtil.getOwnedMembers(qvtrCollectionTemplateExp)) { |
| RelPatternNode relMemberPatternNode = visit(RelPatternNode.class, qvtrMember); |
| RelPatternEdge relPatternEdge = UMLXFactory.eINSTANCE.createRelPatternEdge(); |
| relPatternEdge.setSourceIndex(sourceIndex); |
| relPatternEdge.setSource(relPatternNode); |
| relPatternEdge.setTarget(relMemberPatternNode); |
| relMemberPatternNode.getOwningRelDomainNode().getOwnedRelPatternEdges().add(relPatternEdge); |
| sourceIndex++; |
| } |
| Variable qvtrRest = qvtrCollectionTemplateExp.getRest(); |
| if (qvtrRest != null) { |
| RelPatternNode relRestPatternNode = visit(RelPatternNode.class, qvtrRest); |
| RelPatternEdge relPatternEdge = UMLXFactory.eINSTANCE.createRelPatternEdge(); |
| relPatternEdge.setSourceIndex(-1); |
| relPatternEdge.setSource(relPatternNode); |
| relPatternEdge.setTarget(relRestPatternNode); |
| relRestPatternNode.getOwningRelDomainNode().getOwnedRelPatternEdges().add(relPatternEdge); |
| } |
| OCLExpression qvtrWhere = qvtrCollectionTemplateExp.getWhere(); |
| if (qvtrWhere != null) { |
| RelPatternNode relWherePatternNode = (RelPatternNode) qvtrWhere.accept(this); |
| relPatternNode.getOwningRelDomainNode().getOwnedRelPatternNodes().add(relWherePatternNode); |
| } |
| return relPatternNode; |
| } |
| |
| @Override |
| public @Nullable UMLXElement visitObjectTemplateExp(@NonNull ObjectTemplateExp qvtrObjectTemplateExp) { |
| RelPatternNode relPatternNode = context.getUMLXElement(RelPatternNode.class, qvtrObjectTemplateExp); |
| for (@NonNull PropertyTemplateItem qvtrPropertyTemplateItem : QVTrelationUtil.getOwnedParts(qvtrObjectTemplateExp)) { |
| Property partProperty = QVTrelationUtil.getReferredProperty(qvtrPropertyTemplateItem); |
| OCLExpression partValue = QVTrelationUtil.getOwnedValue(qvtrPropertyTemplateItem); |
| RelPatternNode relPartPatternNode = visit(RelPatternNode.class, partValue); |
| RelPatternEdge relPatternEdge = UMLXFactory.eINSTANCE.createRelPatternEdge(); |
| Property oppositeProperty = partProperty.getOpposite(); |
| if (partProperty.isIsComposite()) { // FIXME direction only needs to avoid a null/implicit EReference |
| // relPatternEdge.setIsOpposite(false); |
| relPatternEdge.setReferredEStructuralFeature(context.getEcoreOf(partProperty)); |
| relPatternEdge.setSource(relPatternNode); |
| relPatternEdge.setTarget(relPartPatternNode); |
| } |
| else if ((oppositeProperty != null) && !relPartPatternNode.isExpression() && oppositeProperty.isIsComposite()) { |
| // relPatternEdge.setIsOpposite(false); |
| relPatternEdge.setReferredEStructuralFeature(context.getEcoreOf(oppositeProperty)); |
| relPatternEdge.setSource(relPartPatternNode); |
| relPatternEdge.setTarget(relPatternNode); |
| } |
| else if ((oppositeProperty != null) && !relPartPatternNode.isExpression() && partProperty.isIsImplicit()) { |
| // relPatternEdge.setIsOpposite(true); |
| relPatternEdge.setReferredEStructuralFeature(context.getEcoreOf(oppositeProperty)); |
| relPatternEdge.setSource(relPartPatternNode); |
| relPatternEdge.setTarget(relPatternNode); |
| } |
| else { |
| // relPatternEdge.setIsOpposite(false); |
| relPatternEdge.setReferredEStructuralFeature(context.getEcoreOf(partProperty)); |
| relPatternEdge.setSource(relPatternNode); |
| relPatternEdge.setTarget(relPartPatternNode); |
| } |
| relPartPatternNode.getOwningRelDomainNode().getOwnedRelPatternEdges().add(relPatternEdge); |
| } |
| OCLExpression qvtrWhere = qvtrObjectTemplateExp.getWhere(); |
| if (qvtrWhere != null) { |
| RelPatternNode relWherePatternNode = (RelPatternNode) qvtrWhere.accept(this); |
| relPatternNode.getOwningRelDomainNode().getOwnedRelPatternNodes().add(relWherePatternNode); |
| } |
| return relPatternNode; |
| } |
| |
| @Override |
| public @Nullable UMLXElement visitRelationCallExp(@NonNull RelationCallExp qvtrRelationCallExp) { |
| RelInvocationNode relInvocationNode = context.getUMLXElement(RelInvocationNode.class, qvtrRelationCallExp); |
| Relation qvtrReferredRelation = QVTrelationUtil.getReferredRelation(qvtrRelationCallExp); |
| RelDiagram relReferredDiagram = context.getUMLXElement(RelDiagram.class, qvtrReferredRelation); |
| relInvocationNode.setReferredRelDiagram(relReferredDiagram); |
| Iterable<@NonNull Variable> qvtrRootVariables = QVTrelationUtil.getRootVariables(qvtrReferredRelation); |
| Iterable<@NonNull OCLExpression> qvtrArguments = QVTrelationUtil.getOwnedArguments(qvtrRelationCallExp); |
| Iterator<@NonNull Variable> itRootVariables = qvtrRootVariables.iterator(); |
| Iterator<@NonNull OCLExpression> itArguments = qvtrArguments.iterator(); |
| while (itRootVariables.hasNext() && itArguments.hasNext()) { |
| Variable qvtrRootVariable = itRootVariables.next(); |
| OCLExpression qvtrArgument = itArguments.next(); |
| RelPatternNode umlxRootVariable = context.getUMLXElement(RelPatternNode.class, qvtrRootVariable); |
| RelPatternNode relArgumentNode = create(qvtrArgument); |
| RelInvocationEdge relInvocationEdge = UMLXFactory.eINSTANCE.createRelInvocationEdge(); |
| relInvocationEdge.setOwningRelInvocationNode(relInvocationNode); |
| relInvocationEdge.setInvokingRelPatternNode(relArgumentNode); |
| relInvocationEdge.setReferredRelPatternNode(umlxRootVariable); |
| } |
| return null; |
| } |
| |
| @Override |
| public @Nullable UMLXElement visitRelationDomain(@NonNull RelationDomain qvtrRelationDomain) { |
| RelDomainNode relDomainNode = context.getUMLXElement(RelDomainNode.class, qvtrRelationDomain); |
| for (@NonNull DomainPattern qvtrPattern : QVTrelationUtil.getOwnedPatterns(qvtrRelationDomain)) { |
| TemplateExp qvtrTemplateExpression = QVTrelationUtil.getOwnedTemplateExpression(qvtrPattern); |
| RelPatternNode relPatternNode = context.getUMLXElement(RelPatternNode.class, qvtrTemplateExpression); |
| relPatternNode.setIsRoot(true); |
| qvtrTemplateExpression.accept(this); |
| } |
| return relDomainNode; |
| } |
| |
| @Override |
| public @Nullable UMLXElement visitSharedVariable(@NonNull SharedVariable qvtrSharedVariable) { |
| RelPatternNode relPatternNode = context.getUMLXElement(RelPatternNode.class, qvtrSharedVariable); |
| return relPatternNode; |
| } |
| |
| @Override |
| public @Nullable UMLXElement visitTypedModel(@NonNull TypedModel qvtrTypedModel) { |
| TxTypedModelNode txTypedModelNode = context.getUMLXElement(TxTypedModelNode.class, qvtrTypedModel); |
| for (@NonNull TypedModel qvtrDependsOn : QVTrelationUtil.getDependsOns(qvtrTypedModel)) { |
| TxTypedModelNode txDependsOn = context.getUMLXElement(TxTypedModelNode.class, qvtrDependsOn); |
| txTypedModelNode.getDependsOns().add(txDependsOn); |
| } |
| return txTypedModelNode; |
| } |
| } |
| |
| protected final @NonNull EnvironmentFactory environmentFactory; |
| private final @NonNull Resource qvtrResource; |
| private final @NonNull Resource umlxResource; |
| private final @NonNull Map<@NonNull Element, @NonNull UMLXElement> qvtr2umlx = new HashMap<>(); |
| private final @NonNull Set<@NonNull Element> references = new HashSet<>(); |
| |
| public QVTr2UMLX(@NonNull EnvironmentFactory environmentFactory, @NonNull Resource qvtrResource, @NonNull Resource umlxResource) { |
| this.environmentFactory = environmentFactory; |
| this.qvtrResource = qvtrResource; |
| this.umlxResource = umlxResource; |
| } |
| |
| public void addReference(@NonNull Element qvtrElement) { |
| references.add(qvtrElement); |
| } |
| |
| protected <T extends UMLXElement> @Nullable T basicGetUMLXElement(@NonNull Class<T> umlxClass, @NonNull Element qvtrElement) { |
| UMLXElement umlxElement = qvtr2umlx.get(qvtrElement); |
| if (umlxElement == null) { |
| return null; |
| } |
| if (!umlxClass.isAssignableFrom(umlxElement.getClass())) { |
| throw new ClassCastException("UMLX element " + umlxElement + " cannot be cast to " + umlxClass); |
| } |
| @SuppressWarnings("unchecked")T castElement = (T)umlxElement; |
| return castElement; |
| } |
| |
| protected @NonNull RelDomainNode getContainingRelDomainNode(@NonNull OCLExpression qvtrExpression) { |
| for (EObject eObject = qvtrExpression, eContainer; (eContainer = eObject.eContainer()) != null; eObject = eContainer) { |
| if (eContainer instanceof RelationCallExp) { |
| RelationCallExp qvtrRelationCallExp = (RelationCallExp) eContainer; |
| int argumentIndex = qvtrRelationCallExp.getArgument().indexOf(eObject); |
| assert argumentIndex >= 0; |
| // Relation referredRelation = QVTrelationUtil.getReferredRelation(qvtrRelationCallExp); |
| RelationDomain referredDomain = QVTrelationUtil.getRelationCallExpArgumentDomain(qvtrRelationCallExp, argumentIndex); |
| for (EObject eObject2 = qvtrRelationCallExp, eContainer2; (eContainer2 = eObject2.eContainer()) != null; eObject2 = eContainer2) { |
| if (eContainer2 instanceof Relation) { |
| Relation qvtrRelation = (Relation) eContainer2; |
| RelationDomain rRelationDomain = QVTrelationUtil.getRelationDomain(qvtrRelation, QVTrelationUtil.getTypedModel(referredDomain)); |
| return getUMLXElement(RelDomainNode.class, rRelationDomain); |
| } |
| } |
| } |
| if (eContainer instanceof RelationDomain) { |
| return getUMLXElement(RelDomainNode.class, (RelationDomain) eContainer); |
| } |
| } |
| Relation qvtrRelation = QVTrelationUtil.getContainingRelation(qvtrExpression); |
| RelDiagram relDiagram = getUMLXElement(RelDiagram.class, qvtrRelation); |
| return getPrimitiveRelDomainNode(relDiagram); |
| } |
| |
| public @Nullable EStructuralFeature getEcoreOf(@NonNull Property qvtrProperty) { |
| EStructuralFeature ecoreOfPivot = environmentFactory.getMetamodelManager().getEcoreOfPivot(EStructuralFeature.class, qvtrProperty); |
| return ecoreOfPivot; |
| } |
| |
| public @Nullable EClassifier getEcoreOf(@NonNull Type qvtrType) { |
| // EClassifier ecoreOfPivot = environmentFactory.getMetamodelManager().getEcoreOfPivot(EClassifier.class, qvtrType); // CCE since RelationModel needs derived visitor |
| EClassifier ecoreOfPivot = (EClassifier)qvtrType.getESObject(); |
| if ((ecoreOfPivot == null) && (qvtrType instanceof PrimitiveType)) { |
| StandardLibrary standardLibrary = environmentFactory.getStandardLibrary(); |
| if (qvtrType == standardLibrary.getStringType()) { |
| return EcorePackage.Literals.ESTRING; |
| } |
| else if (qvtrType == standardLibrary.getBooleanType()) { |
| return EcorePackage.Literals.EBOOLEAN_OBJECT; |
| } |
| else if (qvtrType == standardLibrary.getIntegerType()) { |
| return EcorePackage.Literals.EBIG_INTEGER; |
| } |
| else if (qvtrType == standardLibrary.getRealType()) { |
| return EcorePackage.Literals.EBIG_DECIMAL; |
| } |
| } |
| return ecoreOfPivot; |
| } |
| |
| public @NonNull EnvironmentFactory getEnvironmentFactory() { |
| return environmentFactory; |
| } |
| |
| protected @NonNull String getPackagePath(@NonNull StringBuilder s, @NonNull Namespace qvtrNamespace) { |
| EObject eContainer = qvtrNamespace.eContainer(); |
| if ((eContainer instanceof Namespace) && !(eContainer instanceof Model)) { |
| getPackagePath(s, (Namespace)eContainer); |
| s.append("::"); |
| } |
| s.append(PivotUtil.getName(qvtrNamespace)); |
| return s.toString(); |
| } |
| |
| protected @NonNull RelDomainNode getPrimitiveRelDomainNode(@NonNull RelDiagram relDiagram) { |
| for (@NonNull RelDomainNode relDomainNode : UMLXUtil.getOwnedRelDomainNodes(relDiagram)) { |
| if (relDomainNode.getReferredTxTypedModelNode() == null) { |
| return relDomainNode; |
| } |
| } |
| RelDomainNode relDomainNode = UMLXFactory.eINSTANCE.createRelDomainNode(); |
| // context.install(qvtrRelationDomain, relDomainNode); |
| relDiagram.getOwnedRelDomainNodes().add(relDomainNode); |
| return relDomainNode; |
| } |
| |
| public @NonNull String getProjectName(@NonNull URI traceURI) { |
| URI trimFileExtension = traceURI.trimFileExtension(); |
| if (trimFileExtension.isPlatform()) { |
| return trimFileExtension.segment(1); |
| } |
| else { |
| return trimFileExtension.segment(0); |
| } |
| } |
| |
| public @NonNull StandardLibrary getStandardLibrary() { |
| return environmentFactory.getStandardLibrary(); |
| } |
| |
| protected <T extends UMLXElement> @NonNull T getUMLXElement(@NonNull Class<T> umlxClass, @NonNull Element qvtrElement) { |
| UMLXElement umlxElement = qvtr2umlx.get(qvtrElement); |
| if (umlxElement == null) { |
| throw new IllegalArgumentException("Missing UMLX element for " + qvtrElement); |
| } |
| if (!umlxClass.isAssignableFrom(umlxElement.getClass())) { |
| throw new ClassCastException("UMLX element " + umlxElement + " cannot be cast to " + umlxClass); |
| } |
| @SuppressWarnings("unchecked")T castElement = (T)umlxElement; |
| return castElement; |
| } |
| |
| /** |
| * Create a new trace for the given list of generated objects for the given |
| * context and copy its comments. |
| */ |
| protected void install(@NonNull Element qvtrElement, @NonNull UMLXElement umlxElement) { |
| UMLXElement oldUmlxElement = qvtr2umlx.put(qvtrElement, umlxElement); |
| for (@NonNull Comment comment : QVTbaseUtil.getOwnedComments(qvtrElement)) { |
| umlxElement.getComments().add(comment.getBody()); |
| } |
| assert oldUmlxElement == null; |
| } |
| |
| public void transform() throws CompilerChainException { |
| for (EObject eObject : qvtrResource.getContents()) { |
| if (eObject instanceof RelationModel) { |
| UMLXModel umlxModel = UMLXFactory.eINSTANCE.createUMLXModel(); |
| ((Element)eObject).accept(new CreateTransformationVisitor(this, umlxModel)); |
| umlxResource.getContents().add(umlxModel); |
| } |
| } |
| if (!references.isEmpty()) { |
| ReferenceVisitor referenceVisitor = new ReferenceVisitor(this); |
| for (@NonNull Element element : references) { |
| element.accept(referenceVisitor); |
| } |
| } |
| } |
| } |