diff options
author | Ed Willink | 2017-01-28 09:14:33 +0000 |
---|---|---|
committer | Ed Willink | 2017-02-01 07:21:38 +0000 |
commit | f903d69885827e22e20a2c4cc1792e65d6c21af5 (patch) | |
tree | dda247228dc883ff57f4a1d7ece480c915af089c | |
parent | 5e6d63baf702a55e9ed017254b368a4b74b0174f (diff) | |
download | org.eclipse.qvtd-f903d69885827e22e20a2c4cc1792e65d6c21af5.tar.gz org.eclipse.qvtd-f903d69885827e22e20a2c4cc1792e65d6c21af5.tar.xz org.eclipse.qvtd-f903d69885827e22e20a2c4cc1792e65d6c21af5.zip |
[495621] More comprehensive UMLX support
20 files changed, 1913 insertions, 885 deletions
diff --git a/plugins/org.eclipse.qvtd.umlx.design/description/umlx.odesign b/plugins/org.eclipse.qvtd.umlx.design/description/umlx.odesign index 30e54ae93..c70366d64 100644 --- a/plugins/org.eclipse.qvtd.umlx.design/description/umlx.odesign +++ b/plugins/org.eclipse.qvtd.umlx.design/description/umlx.odesign @@ -265,6 +265,21 @@ <foregroundColor xsi:type="description:SystemColor" href="environment:/viewpoint#//@systemColors/@entries[name='white']"/>
</style>
</containerMappings>
+ <containerMappings name="TxQueryContainer" semanticCandidatesExpression="feature:ownedTxQueryNodes" domainClass="umlx.TxQueryNode" childrenPresentation="List">
+ <subNodeMappings name="TxParameterNode" semanticCandidatesExpression="feature:ownedTxParameterNodes" domainClass="umlx.TxParameterNode">
+ <style xsi:type="style:SquareDescription" borderSizeComputationExpression="2" labelExpression="service: umlxLabel" iconPath="/org.eclipse.qvtd.xtext.qvtbase.ui/icons/FunctionParameter.gif" labelAlignment="LEFT" tooltipExpression="service: umlxTooltipExpression" sizeComputationExpression="0" labelPosition="node" resizeKind="EAST_WEST">
+ <borderColor xsi:type="description:SystemColor" href="environment:/viewpoint#//@systemColors/@entries[name='light_orange']"/>
+ <labelColor xsi:type="description:SystemColor" href="environment:/viewpoint#//@systemColors/@entries[name='black']"/>
+ <color xsi:type="description:SystemColor" href="environment:/viewpoint#//@systemColors/@entries[name='white']"/>
+ </style>
+ </subNodeMappings>
+ <style xsi:type="style:FlatContainerStyleDescription" borderSizeComputationExpression="2" labelExpression="service:umlxLabel" iconPath="/org.eclipse.qvtd.xtext.qvtbase.ui/icons/Function.gif" tooltipExpression="service: umlxTooltipExpression">
+ <borderColor xsi:type="description:SystemColor" href="environment:/viewpoint#//@systemColors/@entries[name='blue']"/>
+ <labelColor xsi:type="description:SystemColor" href="environment:/viewpoint#//@systemColors/@entries[name='black']"/>
+ <backgroundColor xsi:type="description:SystemColor" href="environment:/viewpoint#//@systemColors/@entries[name='white']"/>
+ <foregroundColor xsi:type="description:SystemColor" href="environment:/viewpoint#//@systemColors/@entries[name='white']"/>
+ </style>
+ </containerMappings>
<toolSections name="TxNodesId" label="Nodes">
<ownedTools xsi:type="tool:ContainerCreationDescription" name="Import" containerMappings="//@ownedViewpoints[name='umlx-viewpoint-id']/@ownedRepresentations[name='UMLX%20Transformation%20Diagram']/@defaultLayer/@containerMappings[name='TxImportContainer']" iconPath="/org.eclipse.uml2.uml.edit/icons/full/obj16/PackageImport.gif">
<variable name="container"/>
@@ -295,6 +310,24 @@ </firstModelOperations>
</initialOperation>
</ownedTools>
+ <ownedTools xsi:type="tool:ContainerCreationDescription" name="Query" containerMappings="//@ownedViewpoints[name='umlx-viewpoint-id']/@ownedRepresentations[name='UMLX%20Transformation%20Diagram']/@defaultLayer/@containerMappings[name='TxQueryContainer']" iconPath="/org.eclipse.qvtd.xtext.qvtbase.ui/icons/Function.gif">
+ <variable name="container"/>
+ <viewVariable name="containerView"/>
+ <initialOperation>
+ <firstModelOperations xsi:type="tool_1:ChangeContext" browseExpression="var:container">
+ <subModelOperations xsi:type="tool_1:CreateInstance" typeName="umlx.TxQueryNode" referenceName="ownedTxQueryNodes"/>
+ </firstModelOperations>
+ </initialOperation>
+ </ownedTools>
+ <ownedTools xsi:type="tool:NodeCreationDescription" name="Query Parameter" nodeMappings="//@ownedViewpoints[name='umlx-viewpoint-id']/@ownedRepresentations[name='UMLX%20Transformation%20Diagram']/@defaultLayer/@containerMappings[name='TxQueryContainer']/@subNodeMappings[name='TxParameterNode']" iconPath="/org.eclipse.qvtd.xtext.qvtbase.ui/icons/FunctionParameter.gif">
+ <variable name="container"/>
+ <viewVariable name="containerView"/>
+ <initialOperation>
+ <firstModelOperations xsi:type="tool_1:ChangeContext">
+ <subModelOperations xsi:type="tool_1:CreateInstance" typeName="umlx.TxParameterNode" referenceName="ownedTxParameterNodes"/>
+ </firstModelOperations>
+ </initialOperation>
+ </ownedTools>
<ownedTools xsi:type="tool:ContainerCreationDescription" name="Relation" containerMappings="//@ownedViewpoints[name='umlx-viewpoint-id']/@ownedRepresentations[name='UMLX%20Transformation%20Diagram']/@defaultLayer/@containerMappings[name='TxRelDiagramContainer']" iconPath="/org.eclipse.qvtd.umlx.design/icons/UMLXRelation.gif">
<variable name="container"/>
<viewVariable name="containerView"/>
diff --git a/plugins/org.eclipse.qvtd.umlx/plugin.xml b/plugins/org.eclipse.qvtd.umlx/plugin.xml index 97e454132..f404016c5 100644 --- a/plugins/org.eclipse.qvtd.umlx/plugin.xml +++ b/plugins/org.eclipse.qvtd.umlx/plugin.xml @@ -19,8 +19,16 @@ </extension> <extension point="org.eclipse.ocl.pivot.label_generator"> + <generator for="org.eclipse.qvtd.umlx.RelDomainNode" + class="org.eclipse.qvtd.umlx.labels.RelDomainNodeLabelGenerator"/> <generator for="org.eclipse.qvtd.umlx.RelPatternEdge" class="org.eclipse.qvtd.umlx.labels.RelPatternEdgeLabelGenerator"/> + <generator for="org.eclipse.qvtd.umlx.RelPatternClassNode" + class="org.eclipse.qvtd.umlx.labels.RelPatternClassNodeLabelGenerator"/> + <generator for="org.eclipse.qvtd.umlx.UMLXModel" + class="org.eclipse.qvtd.umlx.labels.UMLXModelLabelGenerator"/> + <generator for="org.eclipse.qvtd.umlx.UMLXNamedElement" + class="org.eclipse.qvtd.umlx.labels.UMLXNamedElementLabelGenerator"/> </extension> </plugin> diff --git a/plugins/org.eclipse.qvtd.umlx/src/org/eclipse/qvtd/umlx/labels/RelDomainNodeLabelGenerator.java b/plugins/org.eclipse.qvtd.umlx/src/org/eclipse/qvtd/umlx/labels/RelDomainNodeLabelGenerator.java new file mode 100644 index 000000000..a3f47d23a --- /dev/null +++ b/plugins/org.eclipse.qvtd.umlx/src/org/eclipse/qvtd/umlx/labels/RelDomainNodeLabelGenerator.java @@ -0,0 +1,33 @@ +/******************************************************************************* + * Copyright (c) 2017 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.qvtd.umlx.labels; + +import org.eclipse.jdt.annotation.NonNull; +import org.eclipse.ocl.pivot.labels.AbstractLabelGenerator; +import org.eclipse.qvtd.umlx.RelDomainNode; +import org.eclipse.qvtd.umlx.TxTypedModelNode; + +public final class RelDomainNodeLabelGenerator extends AbstractLabelGenerator<@NonNull RelDomainNode> +{ + public static void initialize(@NonNull Registry registry) { + registry.install(RelDomainNode.class, new RelDomainNodeLabelGenerator()); + } + + public RelDomainNodeLabelGenerator() { + super(RelDomainNode.class); + } + + @Override + public void buildLabelFor(@NonNull Builder labelBuilder, @NonNull RelDomainNode object) { + TxTypedModelNode txTypedModelNode = object.getReferredTxTypedModelNode(); + labelBuilder.appendString(txTypedModelNode != null ? txTypedModelNode.getName() : null); + } +}
\ No newline at end of file diff --git a/plugins/org.eclipse.qvtd.umlx/src/org/eclipse/qvtd/umlx/labels/RelPatternClassNodeLabelGenerator.java b/plugins/org.eclipse.qvtd.umlx/src/org/eclipse/qvtd/umlx/labels/RelPatternClassNodeLabelGenerator.java new file mode 100644 index 000000000..00814d93b --- /dev/null +++ b/plugins/org.eclipse.qvtd.umlx/src/org/eclipse/qvtd/umlx/labels/RelPatternClassNodeLabelGenerator.java @@ -0,0 +1,31 @@ +/******************************************************************************* + * Copyright (c) 2017 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.qvtd.umlx.labels; + +import org.eclipse.jdt.annotation.NonNull; +import org.eclipse.ocl.pivot.labels.AbstractLabelGenerator; +import org.eclipse.qvtd.umlx.RelPatternClassNode; + +public final class RelPatternClassNodeLabelGenerator extends AbstractLabelGenerator<@NonNull RelPatternClassNode> +{ + public static void initialize(@NonNull Registry registry) { + registry.install(RelPatternClassNode.class, new RelPatternClassNodeLabelGenerator()); + } + + public RelPatternClassNodeLabelGenerator() { + super(RelPatternClassNode.class); + } + + @Override + public void buildLabelFor(@NonNull Builder labelBuilder, @NonNull RelPatternClassNode object) { + labelBuilder.appendString(object.getName()); + } +}
\ No newline at end of file diff --git a/plugins/org.eclipse.qvtd.umlx/src/org/eclipse/qvtd/umlx/labels/RelPatternEdgeLabelGenerator.java b/plugins/org.eclipse.qvtd.umlx/src/org/eclipse/qvtd/umlx/labels/RelPatternEdgeLabelGenerator.java index 33e1f2305..c22c3fa7c 100644 --- a/plugins/org.eclipse.qvtd.umlx/src/org/eclipse/qvtd/umlx/labels/RelPatternEdgeLabelGenerator.java +++ b/plugins/org.eclipse.qvtd.umlx/src/org/eclipse/qvtd/umlx/labels/RelPatternEdgeLabelGenerator.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2014 Willink Transformations and others. + * Copyright (c) 2017 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 @@ -10,15 +10,16 @@ *******************************************************************************/ package org.eclipse.qvtd.umlx.labels; -import org.eclipse.emf.ecore.EGenericType; import org.eclipse.jdt.annotation.NonNull; import org.eclipse.ocl.pivot.labels.AbstractLabelGenerator; +import org.eclipse.qvtd.umlx.RelPatternClassNode; import org.eclipse.qvtd.umlx.RelPatternEdge; +import org.eclipse.qvtd.umlx.RelPatternNode; -public final class RelPatternEdgeLabelGenerator extends AbstractLabelGenerator<RelPatternEdge> +public final class RelPatternEdgeLabelGenerator extends AbstractLabelGenerator<@NonNull RelPatternEdge> { public static void initialize(@NonNull Registry registry) { - registry.install(EGenericType.class, new RelPatternEdgeLabelGenerator()); + registry.install(RelPatternEdge.class, new RelPatternEdgeLabelGenerator()); } public RelPatternEdgeLabelGenerator() { @@ -27,25 +28,12 @@ public final class RelPatternEdgeLabelGenerator extends AbstractLabelGenerator<R @Override public void buildLabelFor(@NonNull Builder labelBuilder, @NonNull RelPatternEdge object) { - // EClassifier eClassifier = object.getEClassifier(); - // if (eClassifier != null) { - // labelBuilder.appendObject(eClassifier); - // } - // else { - // ETypeParameter eTypeParameter = object.getETypeParameter(); - // labelBuilder.appendObject(eTypeParameter); - // } - // List<EGenericType> eTypeArguments = object.getETypeArguments(); - // int size = eTypeArguments.size(); - // if (size > 0) { - labelBuilder.appendString("<"); - // for (int i = 0; i < size; i++) { - // if (i > 0) { - // labelBuilder.appendString(","); - // } - // labelBuilder.appendObject(eTypeArguments.get(0)); - // } - labelBuilder.appendString(">"); - // } + RelPatternClassNode source = object.getSource(); + RelPatternNode target = object.getTarget(); + labelBuilder.appendString(source != null ? source.getName() : null); + labelBuilder.appendString(" -> "); + if (target instanceof RelPatternClassNode) { + labelBuilder.appendString(((RelPatternClassNode)target).getName()); + } } }
\ No newline at end of file diff --git a/plugins/org.eclipse.qvtd.umlx/src/org/eclipse/qvtd/umlx/labels/UMLXModelLabelGenerator.java b/plugins/org.eclipse.qvtd.umlx/src/org/eclipse/qvtd/umlx/labels/UMLXModelLabelGenerator.java new file mode 100644 index 000000000..345ea0fe8 --- /dev/null +++ b/plugins/org.eclipse.qvtd.umlx/src/org/eclipse/qvtd/umlx/labels/UMLXModelLabelGenerator.java @@ -0,0 +1,33 @@ +/******************************************************************************* + * Copyright (c) 2017 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.qvtd.umlx.labels; + +import org.eclipse.emf.ecore.resource.Resource; +import org.eclipse.jdt.annotation.NonNull; +import org.eclipse.ocl.pivot.labels.AbstractLabelGenerator; +import org.eclipse.qvtd.umlx.UMLXModel; + +public final class UMLXModelLabelGenerator extends AbstractLabelGenerator<@NonNull UMLXModel> +{ + public static void initialize(@NonNull Registry registry) { + registry.install(UMLXModel.class, new UMLXModelLabelGenerator()); + } + + public UMLXModelLabelGenerator() { + super(UMLXModel.class); + } + + @Override + public void buildLabelFor(@NonNull Builder labelBuilder, @NonNull UMLXModel object) { + Resource eResource = object.eResource(); + labelBuilder.appendString(eResource != null ? String.valueOf(eResource.getURI()) : null); + } +}
\ No newline at end of file diff --git a/plugins/org.eclipse.qvtd.umlx/src/org/eclipse/qvtd/umlx/labels/UMLXNamedElementLabelGenerator.java b/plugins/org.eclipse.qvtd.umlx/src/org/eclipse/qvtd/umlx/labels/UMLXNamedElementLabelGenerator.java new file mode 100644 index 000000000..07831d8ba --- /dev/null +++ b/plugins/org.eclipse.qvtd.umlx/src/org/eclipse/qvtd/umlx/labels/UMLXNamedElementLabelGenerator.java @@ -0,0 +1,31 @@ +/******************************************************************************* + * Copyright (c) 2017 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.qvtd.umlx.labels; + +import org.eclipse.jdt.annotation.NonNull; +import org.eclipse.ocl.pivot.labels.AbstractLabelGenerator; +import org.eclipse.qvtd.umlx.UMLXNamedElement; + +public final class UMLXNamedElementLabelGenerator extends AbstractLabelGenerator<@NonNull UMLXNamedElement> +{ + public static void initialize(@NonNull Registry registry) { + registry.install(UMLXNamedElement.class, new UMLXNamedElementLabelGenerator()); + } + + public UMLXNamedElementLabelGenerator() { + super(UMLXNamedElement.class); + } + + @Override + public void buildLabelFor(@NonNull Builder labelBuilder, @NonNull UMLXNamedElement object) { + labelBuilder.appendString(object.getName()); + } +}
\ No newline at end of file diff --git a/plugins/org.eclipse.qvtd.umlx/src/org/eclipse/qvtd/umlx/qvtr2umlx/QVTr2UMLX.java b/plugins/org.eclipse.qvtd.umlx/src/org/eclipse/qvtd/umlx/qvtr2umlx/QVTr2UMLX.java index 08da4ee72..e1bd45132 100644 --- a/plugins/org.eclipse.qvtd.umlx/src/org/eclipse/qvtd/umlx/qvtr2umlx/QVTr2UMLX.java +++ b/plugins/org.eclipse.qvtd.umlx/src/org/eclipse/qvtd/umlx/qvtr2umlx/QVTr2UMLX.java @@ -10,6 +10,8 @@ *******************************************************************************/ 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; @@ -40,14 +42,18 @@ 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.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; @@ -66,36 +72,36 @@ 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.RelPatternExpressionNode; 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.RelPatternNode; -import org.eclipse.qvtd.umlx.RelPatternEdge; import org.eclipse.qvtd.umlx.RelPatternClassNode; +import org.eclipse.qvtd.umlx.RelPatternEdge; +import org.eclipse.qvtd.umlx.RelPatternExpressionNode; +import org.eclipse.qvtd.umlx.RelPatternNode; import org.eclipse.qvtd.umlx.TxDiagram; import org.eclipse.qvtd.umlx.TxImportNode; 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.utilities.UMLXUtil; import com.google.common.collect.Iterables; public class QVTr2UMLX { - protected static class CreateVisitor extends AbstractExtendingQVTrelationVisitor<@Nullable UMLXElement, @NonNull QVTr2UMLX> + protected static abstract class AbstractVisitor extends AbstractExtendingQVTrelationVisitor<@Nullable UMLXElement, @NonNull QVTr2UMLX> { - protected final @NonNull UMLXModel umlxModel; - - public CreateVisitor(@NonNull QVTr2UMLX context, @NonNull UMLXModel umlxModel) { + public AbstractVisitor(@NonNull QVTr2UMLX context) { super(context); - this.umlxModel = umlxModel; } protected <T1 extends Element, T2 extends UMLXElement> @Nullable T2 create(@Nullable T1 source) { @@ -115,30 +121,18 @@ public class QVTr2UMLX } } - protected @NonNull RelPatternClassNode createRelPatternClassNode(@NonNull TypedElement qvtrTypedElement) { - RelPatternClassNode relPatternClassNode = UMLXFactory.eINSTANCE.createRelPatternClassNode(); - 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()); - } - relPatternClassNode.setIsRequired(qvtrTypedElement.isIsRequired()); + 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; - relPatternClassNode.setIsMany(true); - relPatternClassNode.setIsNullFree(qvtrCollectionType.isIsNullFree()); - relPatternClassNode.setIsOrdered(qvtrCollectionType.isOrdered()); - relPatternClassNode.setIsUnique(qvtrCollectionType.isUnique()); + umlxTypedElement.setIsMany(true); + umlxTypedElement.setIsNullFree(qvtrCollectionType.isIsNullFree()); + umlxTypedElement.setIsOrdered(qvtrCollectionType.isOrdered()); + umlxTypedElement.setIsUnique(qvtrCollectionType.isUnique()); qvtrType = PivotUtil.getElementalType(qvtrCollectionType); } - relPatternClassNode.setReferredEClassifier(context.getEcoreOf(qvtrType)); - return relPatternClassNode; + umlxTypedElement.setReferredEClassifier(context.getEcoreOf(qvtrType)); } protected <T extends UMLXElement> @NonNull T visit(@NonNull Class<T> umlxClass, @NonNull Element qvtrElement) { @@ -153,61 +147,151 @@ public class QVTr2UMLX return castElement; } - @Override - public @Nullable UMLXElement visitImport(@NonNull Import asImport) { - TxImportNode txImportNode = UMLXFactory.eINSTANCE.createTxImportNode(); - context.install(asImport, txImportNode); - txImportNode.setName(asImport.getName()); - txImportNode.setUri(EcoreUtil.getURI(asImport.getImportedNamespace().getESObject()).toString()); - return txImportNode; - } - - @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 String visitOCLExpression(@NonNull OCLExpression qvtrExpression) { + // return PrettyPrinter.print(qvtrExpression); + // } @Override public @Nullable UMLXElement visitOCLExpression(@NonNull OCLExpression qvtrExpression) { RelDomainNode relDomainNode = context.getContainingRelDomainNode(qvtrExpression); RelPatternExpressionNode relPatternExpressionNode = UMLXFactory.eINSTANCE.createRelPatternExpressionNode(); context.install(qvtrExpression, relPatternExpressionNode); - relPatternExpressionNode.setExpression(PrettyPrinter.print(qvtrExpression)); + for (String line : PrettyPrinter.print(qvtrExpression).split("\\n")) { + relPatternExpressionNode.getInitExpressionLines().add(line); + } relDomainNode.getOwnedRelPatternNodes().add(relPatternExpressionNode); return relPatternExpressionNode; } @Override - public @Nullable UMLXElement visitPackage(org.eclipse.ocl.pivot.@NonNull Package qvtrPackage) { - if (PivotConstants.ORPHANAGE_URI.equals(qvtrPackage.getURI())) { - return null; + public @Nullable RelPatternClassNode visitVariableExp(@NonNull VariableExp qvtrVariableExp) { + RelPatternClassNode relPatternNode = context.getUMLXElement(RelPatternClassNode.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); + } + } } - // 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; + 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 RelPatternClassNode createRelPatternClassNode(@NonNull TypedElement qvtrTypedElement) { + RelPatternClassNode relPatternClassNode = UMLXFactory.eINSTANCE.createRelPatternClassNode(); + 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) { - RelDiagram relDiagram = UMLXFactory.eINSTANCE.createRelDiagram(); context.install(qvtrRelation, relDiagram); relDiagram.setIsTop(qvtrRelation.isIsTopLevel()); relDiagram.setName(qvtrRelation.getName()); @@ -218,14 +302,29 @@ public class QVTr2UMLX // // Create the primitive domain and its variables // - List<RelPatternNode> ownedNodes = null; - for (@NonNull Variable qvtrVariable : QVTrelationUtil.getOwnedVariable(qvtrRelation)) { + for (@NonNull Variable qvtrVariable : QVTrelationUtil.getOwnedVariables(qvtrRelation)) { RelPatternClassNode relPatternClassNode = context.basicGetUMLXElement(RelPatternClassNode.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) { + System.out.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) { - RelDomainNode relDomainNode = context.getPrimitiveRelDomainNode(relDiagram); - ownedNodes = relDomainNode.getOwnedRelPatternNodes(); + ownedNodes = getPrimitiveNodes(); } ownedNodes.add(relPatternClassNode); } @@ -285,12 +384,25 @@ public class QVTr2UMLX if (qvtrRelationDomain.isIsEnforceable()) { tyTypedModelNode.setEnforce(true); } - List<RelPatternNode> ownedNodes = relDomainNode.getOwnedRelPatternNodes(); for (@NonNull EObject eObject : new TreeIterable(qvtrRelationDomain, false)) { if (eObject instanceof TemplateExp) { TemplateExp qvtrTemplateExp = (TemplateExp)eObject; RelPatternClassNode 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) { + System.out.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; @@ -305,6 +417,89 @@ public class QVTr2UMLX context.addReference(qvtrRelationDomain); return relDomainNode; } + } + + protected static class CreateTransformationVisitor extends AbstractVisitor + { + protected final @NonNull UMLXModel umlxModel; + + 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 visitImport(@NonNull Import asImport) { + TxImportNode txImportNode = UMLXFactory.eINSTANCE.createTxImportNode(); + context.install(asImport, txImportNode); + txImportNode.setName(asImport.getName()); + txImportNode.setUri(EcoreUtil.getURI(asImport.getImportedNamespace().getESObject()).toString()); + return txImportNode; + } + + @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) { @@ -337,6 +532,7 @@ public class QVTr2UMLX createAll(QVTrelationUtil.getModelParameters(qvtrTransformation), 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); @@ -356,52 +552,14 @@ public class QVTr2UMLX } return txTypedModelNode; } - - @Override - public @Nullable UMLXElement visitVariableExp(@NonNull VariableExp qvtrVariableExp) { - RelPatternClassNode relPatternNode = context.getUMLXElement(RelPatternClassNode.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 ReferenceVisitor extends AbstractExtendingQVTrelationVisitor<@Nullable UMLXElement, @NonNull QVTr2UMLX> + protected static class ReferenceVisitor extends AbstractVisitor { public ReferenceVisitor(@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 <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 UMLXElement visiting(@NonNull Visitable visitable) { - throw new IllegalArgumentException("Unsupported " + visitable.eClass().getName() + " for " + getClass().getSimpleName()); - } - @Override public @Nullable UMLXElement visitCollectionTemplateExp(@NonNull CollectionTemplateExp qvtrCollectionTemplateExp) { RelPatternClassNode relPatternNode = context.getUMLXElement(RelPatternClassNode.class, qvtrCollectionTemplateExp); @@ -429,20 +587,15 @@ public class QVTr2UMLX 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 visitOCLExpression(@NonNull OCLExpression qvtrExpression) { - RelDomainNode relDomainNode = context.getContainingRelDomainNode(qvtrExpression); - RelPatternExpressionNode relPatternExpressionNode = UMLXFactory.eINSTANCE.createRelPatternExpressionNode(); - context.install(qvtrExpression, relPatternExpressionNode); - relPatternExpressionNode.setExpression(PrettyPrinter.print(qvtrExpression)); - relDomainNode.getOwnedRelPatternNodes().add(relPatternExpressionNode); - return relPatternExpressionNode; - } - - @Override public @Nullable UMLXElement visitObjectTemplateExp(@NonNull ObjectTemplateExp qvtrObjectTemplateExp) { RelPatternClassNode relPatternNode = context.getUMLXElement(RelPatternClassNode.class, qvtrObjectTemplateExp); for (@NonNull PropertyTemplateItem qvtrPropertyTemplateItem : QVTrelationUtil.getOwnedParts(qvtrObjectTemplateExp)) { @@ -451,7 +604,7 @@ public class QVTr2UMLX RelPatternNode relPartPatternNode = visit(RelPatternNode.class, partValue); RelPatternEdge relPatternEdge = UMLXFactory.eINSTANCE.createRelPatternEdge(); Property oppositeProperty = partProperty.getOpposite(); - if (partProperty.isIsComposite()) { + if (partProperty.isIsComposite()) { // FIXME direction only needs to avoid a null/implicit EReference // relPatternEdge.setIsOpposite(false); relPatternEdge.setReferredEStructuralFeature(context.getEcoreOf(partProperty)); relPatternEdge.setSource(relPatternNode); @@ -477,6 +630,11 @@ public class QVTr2UMLX } 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; } @@ -520,12 +678,6 @@ public class QVTr2UMLX RelPatternClassNode relPatternNode = context.getUMLXElement(RelPatternClassNode.class, qvtrSharedVariable); return relPatternNode; } - - @Override - public @Nullable UMLXElement visitVariableExp(@NonNull VariableExp qvtrVariableExp) { - RelPatternClassNode relPatternNode = context.getUMLXElement(RelPatternClassNode.class, PivotUtil.getReferredVariable(qvtrVariableExp)); - return relPatternNode; - } } protected final @NonNull EnvironmentFactory environmentFactory; @@ -557,15 +709,28 @@ public class QVTr2UMLX } protected @NonNull RelDomainNode getContainingRelDomainNode(@NonNull OCLExpression qvtrExpression) { - RelationDomain qvtrRelationDomain = QVTrelationUtil.basicGetContainingRelationDomain(qvtrExpression); - if (qvtrRelationDomain != null) { - return getUMLXElement(RelDomainNode.class, qvtrRelationDomain); - } - else { - Relation qvtrRelation = QVTrelationUtil.getContainingRelation(qvtrExpression); - RelDiagram relDiagram = getUMLXElement(RelDiagram.class, qvtrRelation); - return getPrimitiveRelDomainNode(relDiagram); + 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) { @@ -662,7 +827,7 @@ public class QVTr2UMLX for (EObject eObject : qvtrResource.getContents()) { if (eObject instanceof RelationModel) { UMLXModel umlxModel = UMLXFactory.eINSTANCE.createUMLXModel(); - ((Element)eObject).accept(new CreateVisitor(this, umlxModel)); + ((Element)eObject).accept(new CreateTransformationVisitor(this, umlxModel)); umlxResource.getContents().add(umlxModel); } } diff --git a/plugins/org.eclipse.qvtd.umlx/src/org/eclipse/qvtd/umlx/resource/UMLX2XMIidVisitor.java b/plugins/org.eclipse.qvtd.umlx/src/org/eclipse/qvtd/umlx/resource/UMLX2XMIidVisitor.java index 38a6baf6f..27d5f9bb5 100644 --- a/plugins/org.eclipse.qvtd.umlx/src/org/eclipse/qvtd/umlx/resource/UMLX2XMIidVisitor.java +++ b/plugins/org.eclipse.qvtd.umlx/src/org/eclipse/qvtd/umlx/resource/UMLX2XMIidVisitor.java @@ -29,7 +29,9 @@ import org.eclipse.qvtd.umlx.TxDiagram; import org.eclipse.qvtd.umlx.TxImportNode; 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.UMLXModel; @@ -81,8 +83,10 @@ public class UMLX2XMIidVisitor extends AbstractExtendingUMLXVisitor<Boolean, UML public static final @NonNull String TX_DIAGRAM_PREFIX = "T."; //$NON-NLS-1$ public static final @NonNull String TX_IMPORT_PREFIX = "I."; //$NON-NLS-1$ public static final @NonNull String TX_KEY_PREFIX = "K."; //$NON-NLS-1$ - public static final @NonNull String TX_KEY_PART_PREFIX = "P."; //$NON-NLS-1$ - public static final @NonNull String TX_MODEL_PARAMETER_PREFIX = "M."; //$NON-NLS-1$ + public static final @NonNull String TX_KEY_PART_PREFIX = "Kp."; //$NON-NLS-1$ + public static final @NonNull String TX_MODEL_PARAMETER_PREFIX = "Tp."; //$NON-NLS-1$ + public static final @NonNull String TX_QUERY_PREFIX = "Q."; //$NON-NLS-1$ + public static final @NonNull String TX_QUERY_PARAMETER_PREFIX = "Qp."; //$NON-NLS-1$ public static final @NonNull String TX_USED_PACKAGE_PREFIX = "U."; //$NON-NLS-1$ /* public static final @NonNull String ACCUMULATOR_PREFIX = "a"; //$NON-NLS-1$ @@ -220,8 +224,8 @@ public class UMLX2XMIidVisitor extends AbstractExtendingUMLXVisitor<Boolean, UML appendNameOf(s, UMLXUtil.getSource(incoming.get(0))); } else { - String expression = relPatternExpressionNode.getExpression(); - int hash = expression != null ? expression.hashCode() : 0; + List<String> initExpressionLines = relPatternExpressionNode.getInitExpressionLines(); + int hash = initExpressionLines.hashCode(); s.append(Integer.toString(hash)); } } @@ -386,6 +390,14 @@ public class UMLX2XMIidVisitor extends AbstractExtendingUMLXVisitor<Boolean, UML } @Override + public Boolean visitTxParameterNode(@NonNull TxParameterNode object) { + s.append(TX_QUERY_PARAMETER_PREFIX); + appendParent(object); + appendNameOf(s, object); + return true; + } + + @Override public Boolean visitTxPartNode(@NonNull TxPartNode object) { String name = object.getReferredEStructuralFeature().getName(); if (name != null) { @@ -401,6 +413,20 @@ public class UMLX2XMIidVisitor extends AbstractExtendingUMLXVisitor<Boolean, UML } @Override + public Boolean visitTxQueryNode(@NonNull TxQueryNode object) { + s.append(TX_QUERY_PREFIX); + appendParent(object); + appendNameOf(s, object); + for (TxParameterNode txParameterNode : object.getOwnedTxParameterNodes()) { + s.append(FIELD_SEPARATOR); + if (txParameterNode != null) { + appendNameOf(s, txParameterNode); + } + } + return true; + } + + @Override public Boolean visitTxTypedModelNode(@NonNull TxTypedModelNode object) { String name = object.getName(); if (name != null) { diff --git a/plugins/org.eclipse.qvtd.umlx/src/org/eclipse/qvtd/umlx/umlx2qvtr/PatternForest.java b/plugins/org.eclipse.qvtd.umlx/src/org/eclipse/qvtd/umlx/umlx2qvtr/PatternForest.java new file mode 100644 index 000000000..cfe99747e --- /dev/null +++ b/plugins/org.eclipse.qvtd.umlx/src/org/eclipse/qvtd/umlx/umlx2qvtr/PatternForest.java @@ -0,0 +1,778 @@ +/******************************************************************************* + * Copyright (c) 2016 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.qvtd.umlx.umlx2qvtr; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.EReference; +import org.eclipse.emf.ecore.EStructuralFeature; +import org.eclipse.jdt.annotation.NonNull; +import org.eclipse.jdt.annotation.Nullable; +import org.eclipse.ocl.pivot.Element; +import org.eclipse.ocl.pivot.OCLExpression; +import org.eclipse.ocl.pivot.Property; +import org.eclipse.ocl.pivot.StringLiteralExp; +import org.eclipse.ocl.pivot.Variable; +import org.eclipse.ocl.pivot.VariableDeclaration; +import org.eclipse.ocl.pivot.VariableExp; +import org.eclipse.ocl.pivot.internal.utilities.PivotUtilInternal; +import org.eclipse.ocl.pivot.utilities.ClassUtil; +import org.eclipse.ocl.pivot.utilities.EnvironmentFactory; +import org.eclipse.ocl.pivot.utilities.MetamodelManager; +import org.eclipse.qvtd.pivot.qvtbase.TypedModel; +import org.eclipse.qvtd.pivot.qvtrelation.DomainPattern; +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.SharedVariable; +import org.eclipse.qvtd.pivot.qvtrelation.TemplateVariable; +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.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.RelPatternClassNode; +import org.eclipse.qvtd.umlx.RelPatternEdge; +import org.eclipse.qvtd.umlx.RelPatternExpressionNode; +import org.eclipse.qvtd.umlx.RelPatternNode; +import org.eclipse.qvtd.umlx.TxTypedModelNode; +import org.eclipse.qvtd.umlx.utilities.UMLXUtil; + +import com.google.common.collect.Iterables; + +public class PatternForest +{ + private class TreeEdge + { + private @NonNull RelPatternEdge patternEdge; + private boolean isGraph; + private boolean isOpposite; + private @NonNull TreeClassNode parent; + private @NonNull TreeNode child; + + public TreeEdge(boolean isGraph, @NonNull RelPatternEdge patternEdge, boolean isOpposite, @NonNull TreeClassNode parent, @NonNull TreeNode child) { + this.isGraph = isGraph; + this.patternEdge = patternEdge; + this.isOpposite = isOpposite; + this.parent = parent; + this.child = child; + parent.addChildEdge(this); + TreeEdge oldEdge = patternEdge2treeEdge.put(patternEdge, this); + assert oldEdge == null; + if (isGraph) { + child.addGraphEdge(this); + } + // else { + // assert child.parentEdge == this; --not yet constructed + // } + if (isOpposite) { + toString(); + } + } + + @Override + public String toString() { + return patternEdge.toString(); + } + } + + private static abstract class TreeNode + { + protected @Nullable TreeEdge parentEdge = null; + protected @Nullable List<@NonNull TreeEdge> graphEdges = null; + // protected boolean isInvoked = false; + + public void addGraphEdge(@NonNull TreeEdge graphEdge) { + List<@NonNull TreeEdge> graphEdges2 = graphEdges; + if (graphEdges2 == null) { + graphEdges = graphEdges2 = new ArrayList<>(); + } + assert !graphEdges2.contains(graphEdge); + graphEdges2.add(graphEdge); + } + + protected abstract void toString(@NonNull StringBuilder s, int depth); + } + + private class TreeClassNode extends TreeNode + { + // Definition structure + private @NonNull TreeRoot treeRoot; + private @NonNull RelPatternClassNode patternNode; + private @NonNull List<@NonNull TreeEdge> childEdges = new ArrayList<>(); + // Derived structure + // private boolean isShared = false; + private Variable variable = null; + protected boolean isRealized = false; + + public TreeClassNode(@NonNull TreeRoot treeRoot, @NonNull RelPatternClassNode rootPatternNode) { + this.treeRoot = treeRoot; + this.patternNode = rootPatternNode; + TreeNode oldNode = patternNode2treeNode.put(rootPatternNode, this); + assert oldNode == null; + allNodes.add(rootPatternNode); + treeRoot.addNode(this); + } + + public TreeClassNode(@NonNull RelPatternEdge patternEdge, boolean isOpposite, @NonNull TreeClassNode parentNode) { + this.treeRoot = parentNode.treeRoot; + this.patternNode = isOpposite ? UMLXUtil.getSource(patternEdge) : (RelPatternClassNode)UMLXUtil.getTarget(patternEdge); + this.parentEdge = new TreeEdge(false, patternEdge, isOpposite, parentNode, this); + assert parentNode.patternNode == (isOpposite ? patternEdge.getTarget() : patternEdge.getSource()); + TreeNode oldNode = patternNode2treeNode.put(patternNode, this); + assert oldNode == null; + allNodes.add(patternNode); + } + + public void addChildEdge(@NonNull TreeEdge childEdge) { + assert !childEdges.contains(childEdge); + childEdges.add(childEdge); + } + + public @NonNull Variable getVariable() { + Variable variable2 = variable; + if (variable2 == null) { + org.eclipse.ocl.pivot.Class asClass = umlx2qvtr.getReferredType(patternNode); + TreeEdge parentEdge2 = parentEdge; + boolean isRestVariable = isRestVariable(parentEdge2); + boolean isGraphLeafVariable = isGraphLeafVariable(); + boolean isUnenforcedLeafVariable = isUnrealizedLeafVariable(); + if (isRestVariable || isGraphLeafVariable || isUnenforcedLeafVariable) { + String name = patternNode.isIsAnon() ? null : UMLXUtil.getName(patternNode); + variable2 = umlx2qvtr.createSharedVariable(name, asClass, patternNode.isIsRequired(), null); + umlx2qvtr.install(patternNode, variable2); + } + else { + variable2 = umlx2qvtr.createTemplateVariable(UMLXUtil.getName(patternNode), asClass, patternNode.isIsRequired(), null); + } + // } + allVariables.add(variable2); + variable = variable2; + } + return variable2; + } + + private boolean isGraphLeafVariable() { + if (childEdges.isEmpty()) { + List<@NonNull TreeEdge> graphEdges2 = graphEdges; + if (graphEdges2 != null) { + for (@NonNull TreeEdge graphEdge : graphEdges2) { + if (graphEdge.parent.treeRoot != treeRoot) { + return true; + } + } + } + } + return false; + } + + private boolean isRestVariable(TreeEdge parentEdge2) { + return (parentEdge2 != null) && (parentEdge2.patternEdge.getSourceIndex() < 0); + } + + private boolean isUnrealizedLeafVariable() { + // if (!isRealized) { + // return false; + // } + if (parentEdge == null) { + return false; + } + if (isRealized) { + return false; + } + if (!childEdges.isEmpty()) { + return false; + } + // if (treeRoot.relDomainNode.getReferredTxTypedModelNode().isEnforce()) { + // return false; + // } + // if (isInvoked) { + // return true; + // } + if ((graphEdges != null) && !graphEdges.isEmpty()) { + return true; + } + return false; + } + + public void setIsRealized() { + if (!isRealized) { + isRealized = true; + for (@NonNull TreeEdge childEdge : childEdges) { + EStructuralFeature eStructuralFeature = childEdge.patternEdge.getReferredEStructuralFeature(); + if ((eStructuralFeature == null) || ((eStructuralFeature instanceof EReference) && ((EReference)eStructuralFeature).isContainment())) { + ((TreeClassNode)childEdge.child).setIsRealized(); + } + } + } + } + + @Override + public String toString() { + return patternNode.toString(); + } + + @Override + protected void toString(@NonNull StringBuilder s, int depth) { + s.append(patternNode); + depth++; + for (@NonNull TreeEdge treeEdge : childEdges) { + s.append("\n"); + for (int i = 0; i < depth; i++) { + s.append(" "); + } + EStructuralFeature eStructuralFeature = treeEdge.patternEdge.getReferredEStructuralFeature(); + if (eStructuralFeature != null) { + s.append(eStructuralFeature.getName()); + } + else { + s.append(treeEdge.patternEdge); + } + if (treeEdge.isGraph) { + s.append(" => "); + s.append(treeEdge.child); + } + else if (treeEdge.child instanceof TreeExpressionNode) { + s.append(" := "); + s.append(treeEdge.child); + } + else { + s.append(" = "); + treeEdge.child.toString(s, depth); + } + } + } + } + + private class TreeExpressionNode extends TreeNode + { + private @NonNull RelPatternExpressionNode patternNode; + + public TreeExpressionNode(@NonNull RelPatternEdge patternEdge, @NonNull TreeClassNode parentNode) { + this.patternNode = (RelPatternExpressionNode) UMLXUtil.getTarget(patternEdge); + this.parentEdge = new TreeEdge(false, patternEdge, false, parentNode, this); + assert parentNode.patternNode == patternEdge.getSource(); + TreeNode oldNode = patternNode2treeNode.put(patternNode, this); + assert oldNode == null; + } + + @Override + public String toString() { + return patternNode.toString(); + } + + @Override + protected void toString(@NonNull StringBuilder s, int depth) { + s.append(patternNode); + } + } + + private class TreeRoot + { + protected final @NonNull RelDomainNode relDomainNode; + private @NonNull List<@NonNull TreeClassNode> rootNodes = new ArrayList<>(); + + public TreeRoot(@NonNull RelDomainNode relDomainNode) { + this.relDomainNode = relDomainNode; + treeRoots.add(this); + } + + public void addNode(@NonNull TreeClassNode rootNode) { + rootNodes.add(rootNode); + } + + public @NonNull String getName() { + TxTypedModelNode txTypedModelNode = relDomainNode.getReferredTxTypedModelNode(); + if (txTypedModelNode != null) { + return UMLXUtil.getName(txTypedModelNode); + } + else { + return "«primitive»"; + } + } + + @Override + public String toString() { + return relDomainNode.toString(); + } + } + + protected final @NonNull UMLX2QVTr umlx2qvtr; + protected final @NonNull MetamodelManager metamodelManager; + protected final @NonNull RelDiagram relDiagram; + // + private final @NonNull List<@NonNull RelPatternClassNode> allNodes = new ArrayList<>(); + private final @NonNull List<@NonNull TreeRoot> treeRoots = new ArrayList<>(); + private final Map<@NonNull RelDomainNode, @NonNull TreeRoot> domainNode2treeRoot = new HashMap<>(); + private final Map<@NonNull RelPatternNode, @NonNull TreeNode> patternNode2treeNode = new HashMap<>(); + private final Map<@NonNull RelPatternEdge, @NonNull TreeEdge> patternEdge2treeEdge = new HashMap<>(); + private final @NonNull Map<@NonNull RelPatternClassNode, @NonNull Element> relPatternNode2qvtrElement = new HashMap<>(); + private final @NonNull List<@NonNull RelationDomain> allDomains = new ArrayList<>(); + private final @NonNull List<@NonNull Variable> allVariables = new ArrayList<>(); + + public PatternForest(@NonNull UMLX2QVTr umlx2qvtr, @NonNull RelDiagram relDiagram) { + this.umlx2qvtr = umlx2qvtr; + EnvironmentFactory environmentFactory = umlx2qvtr.getEnvironmentFactory(); + this.metamodelManager = environmentFactory.getMetamodelManager(); + this.relDiagram = relDiagram; + analyzePatternRoots(); + analyzePatternTree(); + // analyzeIsolatedNodes(); + analyzeRealizedEdges(); // FIXME not needed + // analyzeInvocationEdges(); // FIXME not needed + } + + /* private void analyzeInvocationEdges() { + for (@NonNull RelInvocationNode relInvocationNode : UMLXUtil.getOwnedRelInvocationNodes(relDiagram)) { + for (@NonNull RelInvocationEdge relInvocationEdge : UMLXUtil.getOwnedRelInvocationEdges(relInvocationNode)) { + RelPatternNode invokingRelPatternNode = relInvocationEdge.getInvokingRelPatternNode(); + TreeNode treeNode = patternNode2treeNode.get(invokingRelPatternNode); + assert treeNode != null; + treeNode.isInvoked = true; + } + } + } */ + + private void analyzePatternRoots() { + for (@NonNull RelDomainNode relDomainNode : UMLXUtil.getOwnedRelDomainNodes(relDiagram)) { + TreeRoot treeRoot = new TreeRoot(relDomainNode); + domainNode2treeRoot.put(relDomainNode, treeRoot); + for (@NonNull RelPatternNode relPatternNode : UMLXUtil.getOwnedRelPatternNodes(relDomainNode)) { + if (relPatternNode.isIsRoot() && (relPatternNode instanceof RelPatternClassNode)) { + RelPatternClassNode rootGraphNode = (RelPatternClassNode) relPatternNode; + patternNode2treeNode.put(rootGraphNode, new TreeClassNode(treeRoot, rootGraphNode)); + } + } + } + } + + private void analyzePatternTree() { + int iSimple = 0; + for (; iSimple < allNodes.size(); iSimple++) { + connectSimpleTreeEdges(allNodes.get(iSimple)); + } + for (int iComplex = 0; iComplex < allNodes.size(); iComplex++) { + connectComplexTreeEdges(allNodes.get(iComplex)); + for (; iSimple < allNodes.size(); iSimple++) { + connectSimpleTreeEdges(allNodes.get(iSimple)); + } + } + // + // Identify the shared leaf nodes to be realized as shared variables. + // + // Set<@NonNull TreeNode> sharedTreeLeafNodes = new HashSet<>(); + // for (@NonNull TreeNode rootTreeNode : treeRoots) { + // rootTreeNode.gatherSharedTreeLeafNodes(sharedTreeLeafNodes); + // } + } + + private void analyzeRealizedEdges() { + for (@NonNull TreeRoot treeRoot : treeRoots) { + TxTypedModelNode txTypedModelNode = treeRoot.relDomainNode.getReferredTxTypedModelNode(); + if ((txTypedModelNode != null) && txTypedModelNode.isEnforce()) { + for (@NonNull TreeClassNode rootNode : treeRoot.rootNodes) { + rootNode.setIsRealized(); + } + } + } + } + + private void connectComplexTreeEdges(@NonNull RelPatternClassNode relNode) { + for (@NonNull RelPatternEdge relPatternEdge : Iterables.concat(UMLXUtil.getOutgoing(relNode), UMLXUtil.getIncoming(relNode))) { + if (!patternEdge2treeEdge.containsKey(relPatternEdge)) { + RelPatternNode sourceNode = UMLXUtil.getSource(relPatternEdge); + TreeClassNode parentNode = (TreeClassNode) patternNode2treeNode.get(sourceNode); + if (parentNode != null) { + RelPatternNode targetNode = UMLXUtil.getTarget(relPatternEdge); + TreeNode childNode = patternNode2treeNode.get(targetNode); + if (childNode != null) { + new TreeEdge(true, relPatternEdge, false, parentNode, childNode); + } + else { + new TreeClassNode(relPatternEdge, false, parentNode); + } + } + else if (relPatternEdge.getReferredEStructuralFeature() instanceof EReference){ + sourceNode = UMLXUtil.getTarget(relPatternEdge); + parentNode = (TreeClassNode) patternNode2treeNode.get(sourceNode); + if (parentNode != null) { + RelPatternNode targetNode = UMLXUtil.getSource(relPatternEdge); + TreeNode childNode = patternNode2treeNode.get(targetNode); + if (childNode != null) { + new TreeEdge(true, relPatternEdge, true, parentNode, childNode); + } + else { + new TreeClassNode(relPatternEdge, true, parentNode); + } + } + } + } + } + } + + private void connectSimpleTreeEdges(@NonNull RelPatternClassNode relNode) { + for (@NonNull RelPatternEdge relPatternEdge : Iterables.concat(UMLXUtil.getOutgoing(relNode), UMLXUtil.getIncoming(relNode))) { + if (!patternEdge2treeEdge.containsKey(relPatternEdge)) { + RelPatternNode sourceNode = UMLXUtil.getSource(relPatternEdge); + TreeClassNode parentNode = (TreeClassNode) patternNode2treeNode.get(sourceNode); + if (parentNode != null) { + EStructuralFeature eStructuralFeature = relPatternEdge.getReferredEStructuralFeature(); + if ((eStructuralFeature != null) && !eStructuralFeature.isMany()) { + RelPatternNode targetNode = UMLXUtil.getTarget(relPatternEdge); + TreeNode childNode = patternNode2treeNode.get(targetNode); + if (childNode != null) { + new TreeEdge(true, relPatternEdge, false, parentNode, childNode); + } + else if (targetNode instanceof RelPatternClassNode) { + new TreeClassNode(relPatternEdge, false, parentNode); + } + else { + new TreeExpressionNode(relPatternEdge, parentNode); + } + } + } + } + } + } + + /** + * First pass, create all the declared elements. + */ + public @NonNull Relation create() { + Iterable<@NonNull RelDomainNode> relDomainNodes = UMLXUtil.getOwnedRelDomainNodes(relDiagram); + // + // Create the nodes of the QVTr template pattern. + // + for (@NonNull RelDomainNode relDomainNode : relDomainNodes) { + for (@NonNull RelPatternNode relPatternNode : UMLXUtil.getOwnedRelPatternNodes(relDomainNode)) { + if (relPatternNode instanceof RelPatternClassNode) { + createRelationNode((RelPatternClassNode)relPatternNode); + } + } + } + // + // Create the edges of the QVTr template pattern. + // + for (@NonNull RelDomainNode relDomainNode : relDomainNodes) { + for (@NonNull RelPatternEdge relPatternEdge : UMLXUtil.getOwnedRelPatternEdges(relDomainNode)) { + createRelationEdge(relPatternEdge); + } + } + // + // Create the patterns of the QVTr template pattern. + // + for (@NonNull RelDomainNode relDomainNode : relDomainNodes) { + if (relDomainNode.getReferredTxTypedModelNode() != null) { + createRelationDomain(relDomainNode); + } + } + // + // Create the Relation + // + Relation qvtrRelation = createRelation(); + // + // Create non-pattern shared variables + // + for (@NonNull RelDomainNode relDomainNode : relDomainNodes) { + for (@NonNull RelPatternNode relPatternNode : UMLXUtil.getOwnedRelPatternNodes(relDomainNode)) { + if (!relPatternNode.isIsRoot() && (relPatternNode instanceof RelPatternClassNode)) { + RelPatternClassNode relPatternClassNode = (RelPatternClassNode)relPatternNode; + TreeNode treeNode = patternNode2treeNode.get(relPatternClassNode); + if (treeNode == null) { + org.eclipse.ocl.pivot.Class asClass = umlx2qvtr.getReferredType(relPatternClassNode); + String name = relPatternClassNode.isIsAnon() ? null : UMLXUtil.getName(relPatternClassNode); + Variable variable = umlx2qvtr.createSharedVariable(name, asClass, relPatternClassNode.isIsRequired(), null); + qvtrRelation.getVariable().add(variable); + umlx2qvtr.install(relPatternClassNode, variable); + } + } + } + } + // + // Compute derived properties + // + for (@NonNull RelationDomain qvtrRelationDomain : allDomains) { + for (@NonNull DomainPattern qvtrDomainPattern : QVTrelationUtil.getOwnedPatterns(qvtrRelationDomain)) { + TemplateExp rootTemplateExpression = QVTrelationUtil.getOwnedTemplateExpression(qvtrDomainPattern); + qvtrRelationDomain.getRootVariable().add(QVTrelationUtil.getBindsTo(rootTemplateExpression)); + List<@NonNull Variable> boundVariables = new ArrayList<>(); + umlx2qvtr.computeBoundVariables(boundVariables, rootTemplateExpression); + List<Variable> bindsTo = qvtrDomainPattern.getBindsTo(); + Iterables.addAll(ClassUtil.nullFree(bindsTo), boundVariables); + } + } + return qvtrRelation; + } + + private @NonNull Relation createRelation() { + Relation qvtrRelation = umlx2qvtr.createRelation(UMLXUtil.getName(relDiagram), allDomains); + umlx2qvtr.install(relDiagram, qvtrRelation); + // Collections.sort(qvtrAllVariables, NameUtil.NAMEABLE_COMPARATOR); + // Iterables.addAll(QVTrelationUtil.Internal.getOwnedVariablesList(qvtrRelation), qvtrAllVariables); + qvtrRelation.setIsTopLevel(relDiagram.isIsTop()); + qvtrRelation.getVariable().addAll(allVariables); + return qvtrRelation; + } + + private @NonNull RelationDomain createRelationDomain(@NonNull RelDomainNode relDomainNode) { + TxTypedModelNode txTypedModelNode = UMLXUtil.getReferredTxTypedModelNode(relDomainNode); + TypedModel qvtrTypedModel = umlx2qvtr.getQVTrElement(TypedModel.class, txTypedModelNode); + RelationDomain qvtrRelationDomain = umlx2qvtr.createRelationDomain(qvtrTypedModel); + qvtrRelationDomain.setIsCheckable(txTypedModelNode.isCheck()); + qvtrRelationDomain.setIsEnforceable(txTypedModelNode.isEnforce()); + umlx2qvtr.install(relDomainNode, qvtrRelationDomain); + allDomains.add(qvtrRelationDomain); + // + TreeRoot treeRoot = domainNode2treeRoot.get(relDomainNode); + assert treeRoot != null; + for (@NonNull TreeClassNode rootNode : treeRoot.rootNodes) { + Element qvtrElement = relPatternNode2qvtrElement.get(rootNode.patternNode); + qvtrRelationDomain.getPattern().add(umlx2qvtr.createDomainPattern((TemplateExp)qvtrElement)); + } + return qvtrRelationDomain; + } + + private @Nullable Element createRelationEdge(@NonNull RelPatternEdge relPatternEdge) { + TreeEdge treeEdge = patternEdge2treeEdge.get(relPatternEdge); + assert treeEdge != null; + TreeNode treeSource = treeEdge.parent; + TreeNode treeTarget = treeEdge.child; + RelPatternClassNode relSource; + RelPatternNode relTarget; + EStructuralFeature eStructuralFeature = relPatternEdge.getReferredEStructuralFeature(); + int sourceIndex; + if (treeEdge.isOpposite) { + relSource = (RelPatternClassNode) relPatternEdge.getTarget(); + relTarget = relPatternEdge.getSource(); + // eStructuralFeature = ((EReference)relPatternEdge.getReferredEStructuralFeature()).getEOpposite(); + sourceIndex = 0; + } + else { + relSource = relPatternEdge.getSource(); + relTarget = relPatternEdge.getTarget(); + // eStructuralFeature = relPatternEdge.getReferredEStructuralFeature(); + sourceIndex = relPatternEdge.getSourceIndex(); + } + TemplateExp qvtrSourceExpression = (TemplateExp)relPatternNode2qvtrElement.get(relSource); + assert qvtrSourceExpression != null; + Element qvtrTarget = relPatternNode2qvtrElement.get(relTarget); + assert treeSource == patternNode2treeNode.get(relSource); + assert treeTarget == patternNode2treeNode.get(relTarget); + if (qvtrTarget == null) { // FIXME is a temporary StringLiteralExp still necessary? + RelPatternExpressionNode relPatternExpressionNode = ((TreeExpressionNode)treeTarget).patternNode; + StringBuilder s = new StringBuilder(); + for (String line : relPatternExpressionNode.getInitExpressionLines()) { + s.append(line); + s.append("\n"); + } + OCLExpression targetExpression = umlx2qvtr.createStringLiteralExp(s.toString()); + umlx2qvtr.install(relPatternExpressionNode, targetExpression); + // addReference1(relPatternExpressionNode); + qvtrTarget = targetExpression; + } + assert (sourceIndex == 0) == (eStructuralFeature != null); + if (sourceIndex != 0) { + CollectionTemplateExp qvtrCollectionTemplateExp = (CollectionTemplateExp) qvtrSourceExpression; + if (sourceIndex < 0) { + qvtrCollectionTemplateExp.setRest((SharedVariable)qvtrTarget); + } + else { + int javaIndex = sourceIndex-1; + while (qvtrCollectionTemplateExp.getMember().size() < javaIndex) { + qvtrCollectionTemplateExp.getMember().add(umlx2qvtr.createNullLiteralExp()); + } + if (qvtrTarget instanceof Variable) { + qvtrTarget = umlx2qvtr.createVariableExp((Variable)qvtrTarget); + } + if (javaIndex < qvtrCollectionTemplateExp.getMember().size()) { + qvtrCollectionTemplateExp.getMember().set(javaIndex, (OCLExpression)qvtrTarget); + } + else { + qvtrCollectionTemplateExp.getMember().add((OCLExpression)qvtrTarget); + } + } + } + else { + assert !(qvtrTarget instanceof VariableExp); + if (treeEdge.isGraph && (qvtrTarget instanceof TemplateExp)) { + qvtrTarget = ((TemplateExp)qvtrTarget).getBindsTo(); + } + if (qvtrTarget instanceof VariableDeclaration) { + qvtrTarget = umlx2qvtr.createVariableExp((VariableDeclaration)qvtrTarget); + } + ObjectTemplateExp qvtrObjectTemplateExp = (ObjectTemplateExp) qvtrSourceExpression; + Property asProperty = metamodelManager.getASOfEcore(Property.class, eStructuralFeature); + assert asProperty != null; + if (treeEdge.isOpposite) { + asProperty = asProperty.getOpposite(); + assert asProperty != null; + } + assert qvtrTarget != null; + qvtrObjectTemplateExp.getPart().add(umlx2qvtr.createPropertyTemplateItem(asProperty, (OCLExpression)qvtrTarget)); + } + return null; + } + + private @Nullable Element createRelationNode(@NonNull RelPatternClassNode relPatternClassNode) { + TreeClassNode treeNode = (TreeClassNode) patternNode2treeNode.get(relPatternClassNode); + if (treeNode == null) { + // FIXME create shared variable + return null; + } + Variable asVariable = treeNode.getVariable(); + // if (asVariable != null) { + // return asVariable; + // } + if (asVariable instanceof TemplateVariable) { + TemplateExp qvtrExpression = null; + org.eclipse.ocl.pivot.Class type = (org.eclipse.ocl.pivot.Class)asVariable.getType(); + if (type == null) { + type = metamodelManager.getStandardLibrary().getOclInvalidType(); + } + for (@NonNull TreeEdge childEdge : treeNode.childEdges) { + if (childEdge.patternEdge.getSourceIndex() != 0) { + qvtrExpression = umlx2qvtr.createCollectionTemplateExp((TemplateVariable) asVariable, type, asVariable.isIsRequired()); + break; + } + } + if ((qvtrExpression == null) && asVariable.isIsMany()) { + qvtrExpression = umlx2qvtr.createCollectionTemplateExp((TemplateVariable) asVariable, type, asVariable.isIsRequired()); + } + if (qvtrExpression == null) { + qvtrExpression = umlx2qvtr.createObjectTemplateExp((TemplateVariable) asVariable, type, asVariable.isIsRequired()); + } + relPatternNode2qvtrElement.put(relPatternClassNode, qvtrExpression); + umlx2qvtr.install(relPatternClassNode, qvtrExpression); + return qvtrExpression; + } + else { + relPatternNode2qvtrElement.put(relPatternClassNode, asVariable); + return asVariable; + } + } + + /** + * Second pass after all internal and external symbol defined; parse the OCL expression text. + */ + public void resolveExpressions() { + for (@NonNull RelDomainNode relDomainNode : UMLXUtil.getOwnedRelDomainNodes(relDiagram)) { + for (@NonNull RelPatternNode relPatternNode : UMLXUtil.getOwnedRelPatternNodes(relDomainNode)) { + List<String> lines = relPatternNode.getInitExpressionLines(); + if (lines.size() > 0) { + if (relPatternNode instanceof RelPatternClassNode) { + resolveRelPatternClassNodeExpression((@NonNull RelPatternClassNode) relPatternNode); + } + else { + resolveRelPatternExpressionNodeExpression((@NonNull RelPatternExpressionNode) relPatternNode); + } + } + } + } + for (@NonNull RelInvocationNode relInvocationNode : UMLXUtil.getOwnedRelInvocationNodes(relDiagram)) { + resolveInvocation(relInvocationNode); + // for (@NonNull RelInvocationEdge relInvocationEdge : UMLXUtil.getOwnedRelInvocationEdges(relInvocationNode)) { + // RelPatternNode invokingRelPatternNode = relInvocationEdge.getInvokingRelPatternNode(); + // TreeNode treeNode = patternNode2treeNode.get(invokingRelPatternNode); + // assert treeNode != null; + // treeNode.isInvoked = true; + // } + } + } + + private void resolveRelPatternClassNodeExpression(@NonNull RelPatternClassNode relPatternClassNode) { + SharedVariable qvtrVariable = umlx2qvtr.getQVTrElement(SharedVariable.class, relPatternClassNode); + List<String> lines = relPatternClassNode.getInitExpressionLines(); + if (lines.size() > 0) { + OCLExpression qvtrExpression = umlx2qvtr.parseContextualExpression(qvtrVariable, lines); + qvtrVariable.setOwnedInit(qvtrExpression); + } + } + + private void resolveRelPatternExpressionNodeExpression( @NonNull RelPatternExpressionNode relPatternExpressionNode) { + StringLiteralExp stringExpression = umlx2qvtr.basicGetQVTrElement(StringLiteralExp.class, relPatternExpressionNode); + if (stringExpression != null) { + resolveMemberExpression(relPatternExpressionNode, stringExpression); + } + else if (relPatternExpressionNode.getInvokingRelInvocationEdges().isEmpty()) { + // OCLExpression qvtrExpression = createUnparsedExpression(relPatternExpressionNode); + // addWhenPredicate(qvtrRelation, qvtrExpression); + } + else { + Relation qvtrRelation = umlx2qvtr.getQVTrElement(Relation.class, relDiagram); + OCLExpression qvtrExpression = umlx2qvtr.parseContextualExpression(qvtrRelation, UMLXUtil.getInitExpressionLines(relPatternExpressionNode)); + assert qvtrExpression != null; + umlx2qvtr.install(relPatternExpressionNode, qvtrExpression); + } + } + + protected void resolveMemberExpression(@NonNull RelPatternExpressionNode relPatternExpressionNode, @NonNull StringLiteralExp stringExpression) { + String textExpression = stringExpression.getStringSymbol(); + final EObject eContainer = stringExpression.eContainer(); + assert eContainer != null; + OCLExpression qvtrExpression = umlx2qvtr.parseContextualExpression(eContainer, Collections.singletonList(textExpression)); + if (qvtrExpression != null) { + EReference eContainmentFeature = stringExpression.eContainmentFeature(); + PivotUtilInternal.resetContainer(stringExpression); + eContainer.eSet(eContainmentFeature, qvtrExpression); + // context.reinstall(relPatternExpressionNode, qvtrExpression); + } + } + + private @Nullable Element resolveInvocation(@NonNull RelInvocationNode relInvocationNode) { + List<@NonNull OCLExpression> qvtrArguments = new ArrayList<>(); + for (@NonNull RelInvocationEdge relInvocationEdge : UMLXUtil.getOwnedRelInvocationEdges(relInvocationNode)) { + // relInvocationEdge.get + RelPatternNode referredRelPatternNode = UMLXUtil.getInvokingRelPatternNode(relInvocationEdge); //UMLXUtil.getReferredRelPatternNode(relInvocationEdge); + Element qvtrElement = umlx2qvtr.getQVTrElement(Element.class, referredRelPatternNode); + if (qvtrElement instanceof TemplateExp) { + qvtrElement = ((TemplateExp)qvtrElement).getBindsTo(); + } + if (qvtrElement instanceof Variable) { + qvtrElement = umlx2qvtr.createVariableExp((Variable)qvtrElement); + } + assert qvtrElement != null; + qvtrArguments.add((OCLExpression)qvtrElement); + } + RelDiagram referredRelDiagram = UMLXUtil.getReferredRelDiagram(relInvocationNode); + Relation qvtrReferredRelation = umlx2qvtr.getQVTrElement(Relation.class, referredRelDiagram); + RelationCallExp qvtrRelationCallExp = umlx2qvtr.createRelationCallExp(qvtrReferredRelation, qvtrArguments); + RelDiagram relDiagram = UMLXUtil.getOwningRelDiagram(relInvocationNode); + Relation qvtrRelation = umlx2qvtr.getQVTrElement(Relation.class, relDiagram); + if (!relInvocationNode.isIsThen()) { + umlx2qvtr.addWhenPredicate(qvtrRelation, qvtrRelationCallExp); + } + else { + umlx2qvtr.addWherePredicate(qvtrRelation, qvtrRelationCallExp); + } + return qvtrRelationCallExp; + } + + @Override + public String toString() { + StringBuilder s = new StringBuilder(); + s.append(relDiagram.getName()); + for (@NonNull TreeRoot treeRoot : treeRoots) { + s.append("\n" + String.valueOf(treeRoot.getName())); + for (@NonNull TreeNode treeNode : treeRoot.rootNodes) { + s.append("\n "); + treeNode.toString(s, 1); + } + } + return s.toString(); + } +} diff --git a/plugins/org.eclipse.qvtd.umlx/src/org/eclipse/qvtd/umlx/umlx2qvtr/UMLX2QVTr.java b/plugins/org.eclipse.qvtd.umlx/src/org/eclipse/qvtd/umlx/umlx2qvtr/UMLX2QVTr.java index cd2f881fe..3a80744a7 100644 --- a/plugins/org.eclipse.qvtd.umlx/src/org/eclipse/qvtd/umlx/umlx2qvtr/UMLX2QVTr.java +++ b/plugins/org.eclipse.qvtd.umlx/src/org/eclipse/qvtd/umlx/umlx2qvtr/UMLX2QVTr.java @@ -12,25 +12,19 @@ package org.eclipse.qvtd.umlx.umlx2qvtr; import java.util.ArrayList; import java.util.HashMap; -import java.util.HashSet; import java.util.List; import java.util.Map; -import java.util.Set; import java.util.StringTokenizer; import org.eclipse.emf.common.util.URI; -import org.eclipse.emf.ecore.EAttribute; import org.eclipse.emf.ecore.EClass; import org.eclipse.emf.ecore.EClassifier; 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.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.DataType; import org.eclipse.ocl.pivot.Element; import org.eclipse.ocl.pivot.ExpressionInOCL; import org.eclipse.ocl.pivot.Import; @@ -38,16 +32,11 @@ import org.eclipse.ocl.pivot.InvalidType; import org.eclipse.ocl.pivot.Namespace; import org.eclipse.ocl.pivot.OCLExpression; import org.eclipse.ocl.pivot.Property; -import org.eclipse.ocl.pivot.StandardLibrary; -import org.eclipse.ocl.pivot.StringLiteralExp; -import org.eclipse.ocl.pivot.Variable; -import org.eclipse.ocl.pivot.VariableExp; import org.eclipse.ocl.pivot.internal.context.AbstractParserContext; import org.eclipse.ocl.pivot.internal.manager.PivotMetamodelManager; import org.eclipse.ocl.pivot.internal.scoping.EnvironmentView; import org.eclipse.ocl.pivot.internal.scoping.ScopeView; import org.eclipse.ocl.pivot.internal.utilities.PivotUtilInternal; -import org.eclipse.ocl.pivot.utilities.ClassUtil; import org.eclipse.ocl.pivot.utilities.EnvironmentFactory; import org.eclipse.ocl.pivot.utilities.MetamodelManager; import org.eclipse.ocl.pivot.utilities.NameUtil; @@ -55,303 +44,36 @@ import org.eclipse.ocl.pivot.utilities.ParserContext; import org.eclipse.ocl.pivot.utilities.ParserException; import org.eclipse.ocl.pivot.utilities.PivotUtil; 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.Rule; 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.QVTrelationFactory; -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.TemplateVariable; import org.eclipse.qvtd.pivot.qvtrelation.utilities.QVTrelationHelper; 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.RelPatternNode; -import org.eclipse.qvtd.umlx.RelPatternEdge; -import org.eclipse.qvtd.umlx.RelPatternExpressionNode; -import org.eclipse.qvtd.umlx.RelPatternClassNode; import org.eclipse.qvtd.umlx.TxDiagram; import org.eclipse.qvtd.umlx.TxImportNode; 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.UMLXModel; +import org.eclipse.qvtd.umlx.UMLXTypedElement; import org.eclipse.qvtd.umlx.util.AbstractExtendingUMLXVisitor; import org.eclipse.qvtd.umlx.utilities.UMLXUtil; import com.google.common.collect.Iterables; -import com.google.common.collect.Lists; public class UMLX2QVTr extends QVTrelationHelper { - protected static class ConnectionHelper - { - protected final @NonNull UMLX2QVTr context; - protected final @NonNull MetamodelManager metamodelManager; - private final @NonNull Map<@NonNull RelPatternClassNode, @NonNull OCLExpression> relPatternNode2qvtrExpression = new HashMap<>(); - private final @NonNull Set<@NonNull RelPatternEdge> connectedEdges = new HashSet<>(); - private final @NonNull Set<@NonNull RelPatternClassNode> connectedClassNodeSet = new HashSet<>(); - - public ConnectionHelper(@NonNull UMLX2QVTr context) { - this.context = context; - this.metamodelManager = context.getMetamodelManager(); - } - - private boolean connectCollectionEdge(@NonNull RelPatternClassNode sourceNode, int sourceIndex, @NonNull RelPatternNode targetNode) { - CollectionTemplateExp sourceTemplateExp = (CollectionTemplateExp) relPatternNode2qvtrExpression.get(sourceNode); - OCLExpression targetExpression = relPatternNode2qvtrExpression.get(targetNode); - assert sourceTemplateExp != null; - if (sourceIndex > 0) { - if (targetExpression == null) { - if (targetNode instanceof RelPatternExpressionNode) { - targetExpression = createUnparsedExpression((RelPatternExpressionNode) targetNode); - } - else { - SharedVariable sharedVariable = context.getQVTrElement(SharedVariable.class, targetNode); - targetExpression = context.createVariableExp(sharedVariable); - } - } - List<@NonNull OCLExpression> ownedMembersList = QVTrelationUtil.Internal.getOwnedMembersList(sourceTemplateExp); - int javaIndex = sourceIndex - 1; - while (ownedMembersList.size() < javaIndex) { - ownedMembersList.add(context.createNullLiteralExp()); - } - if (ownedMembersList.size() == javaIndex) { - ownedMembersList.add(targetExpression); - } - else { - ownedMembersList.set(javaIndex, targetExpression); - } - return true; - } - else if (sourceIndex < 0) { - SharedVariable sharedVariable = context.getQVTrElement(SharedVariable.class, targetNode); - sourceTemplateExp.setRest(sharedVariable); - return true; - } - else { - return false; - } - } - - private boolean connectComplexEdge(@NonNull RelPatternClassNode sourceNode, @NonNull EStructuralFeature eStructuralFeature, @NonNull RelPatternNode targetNode) { - EReference eReference = (EReference)eStructuralFeature; - // assert !eReference.isMany(); - // EReference eOpposite = eReference.getEOpposite(); - // if ((eOpposite != null) && (targetNode instanceof RelPatternClassNode)) { - // connect((RelPatternClassNode)targetNode, eOpposite, sourceNode); - // return true; - // } - connectObjectEdge(sourceNode, eStructuralFeature, targetNode); - return true; - // throw new UnsupportedOperationException(); - // return false; - } - - private @NonNull Iterable<@NonNull RelPatternClassNode> connectComplexEdges(@NonNull RelPatternClassNode relNode) { - List<@NonNull RelPatternClassNode> newClassNodes = new ArrayList<>(); - for (@NonNull RelPatternEdge relEdge : UMLXUtil.getOutgoing(relNode)) { - if (!connectedEdges.contains(relEdge)) { - RelPatternClassNode sourceNode = relNode; - EStructuralFeature eStructuralFeature = relEdge.getReferredEStructuralFeature(); - RelPatternNode targetNode = UMLXUtil.getTarget(relEdge); - if (eStructuralFeature != null) { - if (connectComplexEdge(sourceNode, eStructuralFeature, targetNode)) { - if (targetNode instanceof RelPatternClassNode) { - newClassNodes.add((RelPatternClassNode)targetNode); - } - connectedEdges.add(relEdge); - } - } - else { - if (connectCollectionEdge(sourceNode, relEdge.getSourceIndex(), targetNode)) { - if (targetNode instanceof RelPatternClassNode) { - newClassNodes.add((RelPatternClassNode)targetNode); - } - connectedEdges.add(relEdge); - } - } - } - } - for (@NonNull RelPatternEdge relEdge : UMLXUtil.getIncoming(relNode)) { - if (!connectedEdges.contains(relEdge)) { - RelPatternClassNode sourceNode = UMLXUtil.getSource(relEdge); - EStructuralFeature eStructuralFeature = relEdge.getReferredEStructuralFeature(); - RelPatternClassNode targetNode = relNode; - if (eStructuralFeature != null) { - if (connectComplexEdge(sourceNode, eStructuralFeature, targetNode)) { - newClassNodes.add(targetNode); - connectedEdges.add(relEdge); - } - } - else { - if (connectCollectionEdge(sourceNode, relEdge.getSourceIndex(), targetNode)) { - if (targetNode instanceof RelPatternClassNode) { - newClassNodes.add(targetNode); - } - connectedEdges.add(relEdge); - } - } - } - } - return newClassNodes; - } - - public void connectNodes(@NonNull Iterable<@NonNull RelPatternClassNode> relRootPatternClassNodes) { - List<@NonNull RelPatternClassNode> connectedClassNodeList = Lists.newArrayList(relRootPatternClassNodes); - connectedClassNodeSet.addAll(connectedClassNodeList); - int iSimple = 0; - for (; iSimple < connectedClassNodeList.size(); iSimple++) { - RelPatternClassNode connectableClassNode = connectedClassNodeList.get(iSimple); - Iterable<@NonNull RelPatternClassNode> newClassNodes = connectSimpleEdges(connectableClassNode); - for (@NonNull RelPatternClassNode newClassNode : newClassNodes) { - if (connectedClassNodeSet.add(newClassNode)) { - connectedClassNodeList.add(newClassNode); - } - } - } - for (int iComplex = 0; iComplex < connectedClassNodeList.size(); iComplex++) { - RelPatternClassNode connectableClassNode = connectedClassNodeList.get(iComplex); - Iterable<@NonNull RelPatternClassNode> newClassNodes = connectComplexEdges(connectableClassNode); - for (@NonNull RelPatternClassNode newClassNode : newClassNodes) { - if (connectedClassNodeSet.add(newClassNode)) { - connectedClassNodeList.add(newClassNode); - } - } - for (; iSimple < connectedClassNodeList.size(); iSimple++) { - RelPatternClassNode connectableClassNode2 = connectedClassNodeList.get(iSimple); - Iterable<@NonNull RelPatternClassNode> newClassNodes2 = connectSimpleEdges(connectableClassNode2); - for (@NonNull RelPatternClassNode newClassNode : newClassNodes2) { - if (connectedClassNodeSet.add(newClassNode)) { - connectedClassNodeList.add(newClassNode); - } - } - } - } - } - - private void connectObjectEdge(@NonNull RelPatternClassNode sourceNode, @NonNull EStructuralFeature eStructuralFeature, @NonNull RelPatternNode targetNode) { - ObjectTemplateExp sourceTemplateExp = (ObjectTemplateExp) relPatternNode2qvtrExpression.get(sourceNode); - OCLExpression targetExpression = relPatternNode2qvtrExpression.get(targetNode); - assert sourceTemplateExp != null; - if (targetExpression == null) { - if (targetNode instanceof RelPatternExpressionNode) { - targetExpression = createUnparsedExpression((RelPatternExpressionNode)targetNode); - } - else { - SharedVariable sharedVariable = context.getQVTrElement(SharedVariable.class, targetNode); - targetExpression = context.createVariableExp(sharedVariable); - } - } - Property asProperty = metamodelManager.getASOfEcore(Property.class, eStructuralFeature); - assert asProperty != null; - // if (txPartNode.isIsOpposite()) { - // asProperty = asProperty.getOpposite(); - // } - PropertyTemplateItem qvtrPropertyTemplateItem = context.createPropertyTemplateItem(asProperty, targetExpression); - QVTrelationUtil.Internal.getOwnedPartsList(sourceTemplateExp).add(qvtrPropertyTemplateItem); - } - - private boolean connectSimpleEdge(@NonNull RelPatternClassNode sourceNode, @NonNull EStructuralFeature eStructuralFeature, @NonNull RelPatternNode targetNode) { - if (eStructuralFeature instanceof EAttribute) { - EAttribute eAttribute = (EAttribute)eStructuralFeature; - connectObjectEdge(sourceNode, eAttribute, targetNode); - return true; - } - EReference eReference = (EReference)eStructuralFeature; - if (!eReference.isMany()) { - connectObjectEdge(sourceNode, eReference, targetNode); - return true; - } - if (connectedClassNodeSet.contains(targetNode)) { - EReference eOpposite = eReference.getEOpposite(); - if (eOpposite != null) { - connectObjectEdge((RelPatternClassNode)targetNode, eOpposite, sourceNode); - return true; - } - } - return false; - } - - private @NonNull Iterable<@NonNull RelPatternClassNode> connectSimpleEdges(@NonNull RelPatternClassNode relNode) { - List<@NonNull RelPatternClassNode> newClassNodes = new ArrayList<>(); - for (@NonNull RelPatternEdge relEdge : UMLXUtil.getOutgoing(relNode)) { - if (!connectedEdges.contains(relEdge)) { - RelPatternClassNode sourceNode = relNode; - EStructuralFeature eStructuralFeature = relEdge.getReferredEStructuralFeature(); - RelPatternNode targetNode = UMLXUtil.getTarget(relEdge); - if (eStructuralFeature != null) { - if (connectSimpleEdge(sourceNode, eStructuralFeature, targetNode)) { - if (targetNode instanceof RelPatternClassNode) { - newClassNodes.add((RelPatternClassNode)targetNode); - } - connectedEdges.add(relEdge); - } - } - else { - if (connectCollectionEdge(sourceNode, relEdge.getSourceIndex(), targetNode)) { - if (targetNode instanceof RelPatternClassNode) { - newClassNodes.add((RelPatternClassNode)targetNode); - } - connectedEdges.add(relEdge); - } - } - } - } - for (@NonNull RelPatternEdge relEdge : UMLXUtil.getIncoming(relNode)) { - if (!connectedEdges.contains(relEdge)) { - RelPatternClassNode sourceNode = UMLXUtil.getSource(relEdge); - EStructuralFeature eStructuralFeature = relEdge.getReferredEStructuralFeature(); - RelPatternClassNode targetNode = relNode; - if (eStructuralFeature != null) { - if (connectSimpleEdge(sourceNode, eStructuralFeature, targetNode)) { - newClassNodes.add(targetNode); - connectedEdges.add(relEdge); - } - } - else { - if (connectCollectionEdge(sourceNode, relEdge.getSourceIndex(), targetNode)) { - if (targetNode instanceof RelPatternClassNode) { - newClassNodes.add(targetNode); - } - connectedEdges.add(relEdge); - } - } - } - } - return newClassNodes; - } - - protected @NonNull OCLExpression createUnparsedExpression(@NonNull RelPatternExpressionNode relPatternExpressionNode) { - OCLExpression targetExpression = context.createStringLiteralExp(UMLXUtil.getExpression(relPatternExpressionNode)); - context.install(relPatternExpressionNode, targetExpression); - context.addReference(relPatternExpressionNode); - return targetExpression; - } - - private OCLExpression get(@NonNull RelPatternClassNode relPatternNode) { - return relPatternNode2qvtrExpression.get(relPatternNode); - } - - private void put(@NonNull RelPatternClassNode relPatternNode, @NonNull OCLExpression qvtrExpression) { - relPatternNode2qvtrExpression.put(relPatternNode, qvtrExpression); - } - } - protected static class CreateVisitor extends AbstractExtendingUMLXVisitor<@Nullable Element, @NonNull UMLX2QVTr> { protected final @NonNull MetamodelManager metamodelManager; @@ -364,15 +86,7 @@ public class UMLX2QVTr extends QVTrelationHelper this.qvtrModel = qvtrModel; } - public <T1 extends UMLXElement, T2 extends Element> @Nullable T2 create(@Nullable T1 source) { - if (source == null) { - return null; - } - @SuppressWarnings("unchecked") @Nullable T2 target = (T2) source.accept(this); - return target; - } - - public <@NonNull T1 extends UMLXElement, T2 extends Element> void createAll(/*@NonNull*/ Iterable<T1> sources, /*@NonNull*/ List<? super T2> targets) { + private <@NonNull T1 extends UMLXElement, T2 extends Element> 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)) { @@ -381,70 +95,7 @@ public class UMLX2QVTr extends QVTrelationHelper } } - /** - * Accumulate a TemplateExp and TemplateVariable for relPatternNode and all transitively EReference-connection RelPatternNode in qvtrDomainClassNodes. - * No relationships between TemplateExps are established here. - * Return the TemplateExp for relPatternNode. - */ - private @NonNull OCLExpression createDomainPatternNodes(@NonNull RelPatternClassNode relPatternClassNode, @NonNull ConnectionHelper connectionHelper) { - OCLExpression qvtrTemplateExp = connectionHelper.get(relPatternClassNode); - if (qvtrTemplateExp == null) { - Variable asVariable = visit(Variable.class, relPatternClassNode); - if (asVariable instanceof TemplateVariable) { - TemplateVariable asTemplateVariable = (TemplateVariable)asVariable; - org.eclipse.ocl.pivot.Class asClass = metamodelManager.getASOfEcore(org.eclipse.ocl.pivot.Class.class, relPatternClassNode.getReferredEClassifier()); - assert asClass != null; - if (relPatternClassNode.isIsMany()/*asClass instanceof CollectionType*/) { - qvtrTemplateExp = context.createCollectionTemplateExp(asTemplateVariable, (CollectionType)asVariable.getType(), relPatternClassNode.isIsRequired()); - } - else { - qvtrTemplateExp = context.createObjectTemplateExp(asTemplateVariable, asClass, relPatternClassNode.isIsRequired()); - } - // context.putUMLX2QVTrTrace(relPatternNode, qvtrTemplateExp); - connectionHelper.put(relPatternClassNode, qvtrTemplateExp); - for (@NonNull RelPatternEdge relPatternEdge : UMLXUtil.getOutgoing(relPatternClassNode)) { - RelPatternNode relTargetNode = UMLXUtil.getTarget(relPatternEdge); - EStructuralFeature eStructuralFeature = relPatternEdge.getReferredEStructuralFeature(); - if ((relTargetNode instanceof RelPatternClassNode) && !(eStructuralFeature instanceof EAttribute)) { - createDomainPatternNodes((RelPatternClassNode)relTargetNode, connectionHelper); - } - } - for (@NonNull RelPatternEdge relPatternEdge : UMLXUtil.getIncoming(relPatternClassNode)) { - RelPatternClassNode relSourceNode = UMLXUtil.getSource(relPatternEdge); - EStructuralFeature eStructuralFeature = relPatternEdge.getReferredEStructuralFeature(); - if (!(eStructuralFeature instanceof EAttribute)) { - createDomainPatternNodes(relSourceNode, connectionHelper); - } - } - } - else { - qvtrTemplateExp = context.createVariableExp(asVariable); - } - } - return qvtrTemplateExp; - } - - /** - * Return the most positive non-zero source index of all incoming edges. Returns null if no incoming edge has a - * non-zeto source index. - */ - private @Nullable Integer getIncomingSourceIndex(@NonNull RelPatternClassNode relPatternClassNode) { - Integer mostPositiveSourceIndex = null; - for (@NonNull RelPatternEdge relPatternEdge : UMLXUtil.getIncoming(relPatternClassNode)) { - int sourceIndex = relPatternEdge.getSourceIndex(); - if (sourceIndex != 0) { - if (mostPositiveSourceIndex == null) { - mostPositiveSourceIndex = sourceIndex; - } - else if (mostPositiveSourceIndex < sourceIndex) { - mostPositiveSourceIndex = sourceIndex; - } - } - } - return mostPositiveSourceIndex; - } - - public org.eclipse.ocl.pivot.@NonNull Package getPackage(org.eclipse.ocl.pivot.@Nullable Package asParentPackage, @NonNull String name) { + private org.eclipse.ocl.pivot.@NonNull Package getPackage(org.eclipse.ocl.pivot.@Nullable Package asParentPackage, @NonNull String name) { List<org.eclipse.ocl.pivot.@NonNull Package> asPackages = (asParentPackage != null ? QVTbaseUtil.Internal.getOwnedPackagesList(asParentPackage) : QVTbaseUtil.Internal.getOwnedPackagesList(qvtrModel)); org.eclipse.ocl.pivot.Package qvtrPackage = NameUtil.getNameable(asPackages, name); if (qvtrPackage == null) { @@ -456,29 +107,7 @@ public class UMLX2QVTr extends QVTrelationHelper return qvtrPackage; } - public org.eclipse.ocl.pivot.@NonNull Package getRootPackage(@NonNull String name) { - org.eclipse.ocl.pivot.Package qvtrPackage = NameUtil.getNameable(qvtrModel.getOwnedPackages(), name); - if (qvtrPackage == null) { - @NonNull String nsURI = "http:/fixme"; // FIXME - qvtrPackage = PivotUtil.createPackage(name, null, nsURI, null); - qvtrModel.getOwnedPackages().add(qvtrPackage); - } - return qvtrPackage; - } - - protected <T extends Element> @NonNull T visit(@NonNull Class<T> qvtrClass, @NonNull UMLXElement umlxElement) { - Element qvtrElement = umlxElement.accept(this); - if (qvtrElement == null) { - throw new IllegalArgumentException("Missing UMLX element for " + umlxElement); - } - if (!qvtrClass.isAssignableFrom(qvtrElement.getClass())) { - throw new ClassCastException("UMLX element " + qvtrElement + " cannot be cast to " + qvtrClass); - } - @SuppressWarnings("unchecked")T castElement = (T)qvtrElement; - return castElement; - } - - public void visitAll(/*@NonNull*/ Iterable<? extends @NonNull UMLXElement> sources) { + private void visitAll(/*@NonNull*/ Iterable<? extends @NonNull UMLXElement> sources) { for (@NonNull UMLXElement source : sources) { source.accept(this); } @@ -486,126 +115,9 @@ public class UMLX2QVTr extends QVTrelationHelper @Override public @Nullable Element visitRelDiagram(@NonNull RelDiagram relDiagram) { - List<@NonNull RelationDomain> qvtrRelationDomains = new ArrayList<>(); - ConnectionHelper connectionHelper = new ConnectionHelper(context); - // Iterable<@NonNull RelPatternNode> relNodes = UMLXUtil.getOwnedNodes(relDiagram); - List<@NonNull RelPatternClassNode> relRootPatternClassNodes = new ArrayList<>(); - for (@NonNull RelDomainNode relDomainNode : UMLXUtil.getOwnedRelDomainNodes(relDiagram)) { - if (relDomainNode.getReferredTxTypedModelNode() != null) { - // - // Create the RelationDomain - // - RelationDomain qvtrRelationDomain = visit(RelationDomain.class, relDomainNode); - qvtrRelationDomains.add(qvtrRelationDomain); - // - // Create each DomainPattern, TemplateExp and TemplateVariable - // - for (@NonNull RelPatternNode relPatternNode : UMLXUtil.getOwnedRelPatternNodes(relDomainNode)) { - if (relPatternNode.isIsRoot() && (relPatternNode instanceof RelPatternClassNode)) { - OCLExpression qvtrTemplateExp = createDomainPatternNodes((@NonNull RelPatternClassNode) relPatternNode, connectionHelper); - DomainPattern qvtrRootPattern = context.createDomainPattern((TemplateExp) qvtrTemplateExp); - qvtrRelationDomain.getPattern().add(qvtrRootPattern); - relRootPatternClassNodes.add((RelPatternClassNode) relPatternNode); - } - } - } - } - for (@NonNull RelInvocationNode relInvocationNode : UMLXUtil.getOwnedRelInvocationNodes(relDiagram)) { - visit(relInvocationNode); - } - // - // Gather the TemplateVariables, create the SharedVariables - // - List<@NonNull Variable> qvtrAllVariables = new ArrayList<>(); - for (@NonNull RelDomainNode relDomainNode : UMLXUtil.getOwnedRelDomainNodes(relDiagram)) { - for (@NonNull RelPatternNode relNode : UMLXUtil.getOwnedRelPatternNodes(relDomainNode)) { - if (relNode instanceof RelPatternClassNode) { - RelPatternClassNode relPatternNode = (RelPatternClassNode) relNode; - Variable asVariable = context.basicGetQVTrElement(Variable.class, relPatternNode); - if (asVariable == null) { - asVariable = visit(SharedVariable.class, relPatternNode); - } - qvtrAllVariables.add(asVariable); - } - } - } - // - // Establish the TemplateVariable interrelationships - // - connectionHelper.connectNodes(relRootPatternClassNodes); - // - // Create the Relation - // - // Collections.sort(qvtrRelationDomains, NameUtil.NAMEABLE_COMPARATOR); - Relation qvtrRelation = context.createRelation(UMLXUtil.getName(relDiagram), qvtrRelationDomains); - context.install(relDiagram, qvtrRelation); - // Collections.sort(qvtrAllVariables, NameUtil.NAMEABLE_COMPARATOR); - Iterables.addAll(QVTrelationUtil.Internal.getOwnedVariablesList(qvtrRelation), qvtrAllVariables); - qvtrRelation.setIsTopLevel(relDiagram.isIsTop()); - // - // Compute derived properties - // - for (@NonNull RelationDomain qvtrRelationDomain : qvtrRelationDomains) { - for (@NonNull DomainPattern qvtrDomainPattern : QVTrelationUtil.getOwnedPatterns(qvtrRelationDomain)) { - TemplateExp rootTemplateExpression = QVTrelationUtil.getOwnedTemplateExpression(qvtrDomainPattern); - qvtrRelationDomain.getRootVariable().add(QVTrelationUtil.getBindsTo(rootTemplateExpression)); - List<@NonNull Variable> boundVariables = new ArrayList<>(); - context.computeBoundVariables(boundVariables, rootTemplateExpression); - List<Variable> bindsTo = qvtrDomainPattern.getBindsTo(); - Iterables.addAll(ClassUtil.nullFree(bindsTo), boundVariables); - } - } - return qvtrRelation; - } - - @Override - public @Nullable RelationDomain visitRelDomainNode(@NonNull RelDomainNode relDomainNode) { - TxTypedModelNode txTypedModelNode = UMLXUtil.getReferredTxTypedModelNode(relDomainNode); - TypedModel qvtrTypedModel = context.getQVTrElement(TypedModel.class, txTypedModelNode); - RelationDomain qvtrRelationDomain = context.createRelationDomain(qvtrTypedModel); - qvtrRelationDomain.setIsCheckable(txTypedModelNode.isCheck()); - qvtrRelationDomain.setIsEnforceable(txTypedModelNode.isEnforce()); - context.install(relDomainNode, qvtrRelationDomain); - return qvtrRelationDomain; - } - - @Override - public @Nullable Element visitRelInvocationNode(@NonNull RelInvocationNode relInvocationNode) { - context.addReference(relInvocationNode); - return null; - } - - @Override - public @Nullable Element visitRelPatternClassNode(@NonNull RelPatternClassNode relPatternClassNode) { - EClassifier eClassifier = UMLXUtil.getReferredEClassifier(relPatternClassNode); - if (eClassifier instanceof EClass) { - org.eclipse.ocl.pivot.Class asClass = metamodelManager.getASOfEcore(org.eclipse.ocl.pivot.Class.class, eClassifier); - assert asClass != null; - if (relPatternClassNode.isIsMany()) { - asClass = ((PivotMetamodelManager)metamodelManager).getCollectionType(relPatternClassNode.isIsOrdered(), relPatternClassNode.isIsUnique(), asClass, - relPatternClassNode.isIsNullFree(), null, null); - } - Variable asVariable; - Integer mostPositiveSourceIndex = getIncomingSourceIndex(relPatternClassNode); - if (mostPositiveSourceIndex == null) { - asVariable = context.createTemplateVariable(UMLXUtil.getName(relPatternClassNode), asClass, relPatternClassNode.isIsRequired(), null); - } - else if (mostPositiveSourceIndex > 0) { - asVariable = context.createTemplateVariable(UMLXUtil.getName(relPatternClassNode), asClass, relPatternClassNode.isIsRequired(), null); - } - else { - asVariable = context.createSharedVariable(relPatternClassNode.isIsAnon() ? null : UMLXUtil.getName(relPatternClassNode), asClass, relPatternClassNode.isIsRequired(), null); - } - context.install(relPatternClassNode, asVariable); - return asVariable; - } - else { - DataType asDataType = metamodelManager.getASOfEcore(DataType.class, eClassifier); - assert asDataType != null; - Variable asVariable = context.createSharedVariable(UMLXUtil.getName(relPatternClassNode), asDataType, relPatternClassNode.isIsRequired(), null); - context.install(relPatternClassNode, asVariable); - return asVariable; - } + PatternForest patternForest = new PatternForest(context, relDiagram); + context.patternForests.add(patternForest); + return patternForest.create(); // Pass 1: create the elements } @Override @@ -633,16 +145,17 @@ public class UMLX2QVTr extends QVTrelationHelper List<@NonNull Rule> allRelationsList = new ArrayList<>(); createAll(UMLXUtil.getOwnedRelDiagrams(txDiagram), allRelationsList); + createAll(UMLXUtil.getOwnedTxQueryNodes(txDiagram), QVTbaseUtil.Internal.getOwnedOperationsList(qvtrRelationalTransformation)); // Collections.sort(allRelationsList, NameUtil.NAMEABLE_COMPARATOR); Iterables.addAll(QVTrelationUtil.Internal.getOwnedRelationsList(qvtrRelationalTransformation), allRelationsList); - QVTbaseUtil.getContextVariable(context.getStandardLibrary(), qvtrRelationalTransformation); + QVTbaseUtil.getContextVariable(metamodelManager.getStandardLibrary(), qvtrRelationalTransformation); return qvtrRelationalTransformation; } @Override public @Nullable Element visitTxImportNode(@NonNull TxImportNode txImportNode) { String uri = txImportNode.getUri(); - EObject eObject = context.getEnvironmentFactory().getResourceSet().getEObject(URI.createURI(uri), true); + EObject eObject = metamodelManager.getEnvironmentFactory().getResourceSet().getEObject(URI.createURI(uri), true); try { Namespace asNamespace = metamodelManager.getASOf(Namespace.class, eObject); if (asNamespace != null) { @@ -687,6 +200,25 @@ public class UMLX2QVTr extends QVTrelationHelper } @Override + public @Nullable Element visitTxParameterNode(@NonNull TxParameterNode txParameterNode) { + org.eclipse.ocl.pivot.@NonNull Class asClass = context.getReferredType(txParameterNode); + FunctionParameter asFunctionParameter = context.createFunctionParameter(UMLXUtil.getName(txParameterNode), asClass, txParameterNode.isIsRequired()); + context.install(txParameterNode, asFunctionParameter); + return asFunctionParameter; + } + + @Override + public @Nullable Element visitTxQueryNode(@NonNull TxQueryNode txQueryNode) { + List<@NonNull FunctionParameter> qvtrParameters = new ArrayList<>(); + createAll(UMLXUtil.getOwnedTxParameterNodes(txQueryNode), qvtrParameters); + org.eclipse.ocl.pivot.@NonNull Class asClass = context.getReferredType(txQueryNode); + Function asFunction = context.createFunction(UMLXUtil.getName(txQueryNode), asClass, txQueryNode.isIsRequired(), qvtrParameters); + context.install(txQueryNode, asFunction); + context.txQueryNodes.add(txQueryNode); + return asFunction; + } + + @Override public @Nullable Element visitTxTypedModelNode(@NonNull TxTypedModelNode txTypedModelNode) { List<org.eclipse.ocl.pivot.@NonNull Package> usedPackages = new ArrayList<>(); createAll(UMLXUtil.getOwnedTxPackageNodes(txTypedModelNode), usedPackages); @@ -711,45 +243,6 @@ public class UMLX2QVTr extends QVTrelationHelper return null; } - /* @Override - public @Nullable UMLXElement visitRelationalTransformation(@NonNull RelationalTransformation qvtrTransformation) { - TxDiagram txDiagram = UMLXFactory.eINSTANCE.createTxDiagram(); - txDiagram.setName(qvtrTransformation.getName()); - TxTransformationNode txTransformationNode = UMLXFactory.eINSTANCE.createTxTransformationNode(); - context.putQVTr2UMLXTrace(qvtrTransformation, txTransformationNode); - txTransformationNode.setName(qvtrTransformation.getName()); - // txTransformationNode.setOwnedContext(create(qvtrTransformation.getOwnedContext())); - // createAll(qvtrTransformation.getOwnedOperations(), txTransformationNode.getOwnedOperations()); - createAll(QVTrelationUtil.getModelParameters(qvtrTransformation), txTransformationNode.getTxTypedModelNodes()); - createAll(QVTrelationUtil.getOwnedKey(qvtrTransformation), txTransformationNode.getTxKeyNodes()); - createAll(QVTrelationUtil.getRule(qvtrTransformation), txDiagram.getOwnedDiagrams()); - // doRules(qvtrTransformation, txTransformationNode); - // createAll(qvtrTransformation.getOwnedComments(), txTransformationNode.getOwnedComments()); - txDiagram.getOwnedNodes().add(txTransformationNode); - umlxModel.getOwnedDiagrams().add(txDiagram); - return null; - } */ - - /* @Override - public @Nullable UMLXElement visitTypedModel(@NonNull TypedModel qvtrTypedModel) { - TxTypedModelNode txTypedModelNode = UMLXFactory.eINSTANCE.createTxTypedModelNode(); - context.putQVTr2UMLXTrace(qvtrTypedModel, txTypedModelNode); - txTypedModelNode.setName(qvtrTypedModel.getName()); - for (org.eclipse.ocl.pivot.@NonNull Package usedPackage : QVTrelationUtil.getUsedPackages(qvtrTypedModel)) { - TxPackageNode txPackageNode = UMLXFactory.eINSTANCE.createTxPackageNode(); - // context.addTrace(usedPackage, txPackageNode); - txPackageNode.setReferredPackage(usedPackage.getEPackage()); - txTypedModelNode.getTxPackageNodes().add(txPackageNode); - } - return txTypedModelNode; - } */ - - /* @Override - public @Nullable UMLXElement visitVariableExp(@NonNull VariableExp qvtrVariableExp) { - RelPatternNode relPatternNode = context.getUMLXElement(RelPatternNode.class, PivotUtil.getReferredVariable(qvtrVariableExp)); - return relPatternNode; - } */ - @Override public @Nullable Element visiting(@NonNull UMLXElement umlxElement) { System.out.println("Unsupported " + umlxElement.eClass().getName() + " for " + getClass().getSimpleName()); @@ -758,85 +251,11 @@ public class UMLX2QVTr extends QVTrelationHelper } } - protected static class ReferenceVisitor extends AbstractExtendingUMLXVisitor<@Nullable Object, @NonNull UMLX2QVTr> - { - public ReferenceVisitor(@NonNull UMLX2QVTr context) { - super(context); - } - - @Override - public @Nullable Object visiting(@NonNull UMLXElement visitable) { - System.out.println("Unsupported " + visitable.eClass().getName() + " for " + getClass().getSimpleName()); - return null; - // throw new IllegalArgumentException("Unsupported " + visitable.eClass().getName() + " for " + getClass().getSimpleName()); - } - - @Override - public @Nullable Object visitRelInvocationNode(@NonNull RelInvocationNode relInvocationNode) { - List<@NonNull VariableExp> qvtrArguments = new ArrayList<>(); - for (@NonNull RelInvocationEdge relInvocationEdge : UMLXUtil.getOwnedRelInvocationEdges(relInvocationNode)) { - // relInvocationEdge.get - RelPatternNode referredRelPatternNode = UMLXUtil.getInvokingRelPatternNode(relInvocationEdge); //UMLXUtil.getReferredRelPatternNode(relInvocationEdge); - Variable qvtrVariable = context.getQVTrElement(Variable.class, referredRelPatternNode); - qvtrArguments.add(context.createVariableExp(qvtrVariable)); - } - RelDiagram referredRelDiagram = UMLXUtil.getReferredRelDiagram(relInvocationNode); - Relation qvtrReferredRelation = context.getQVTrElement(Relation.class, referredRelDiagram); - RelationCallExp qvtrRelationCallExp = context.createRelationCallExp(qvtrReferredRelation, qvtrArguments); - RelDiagram relDiagram = UMLXUtil.getOwningRelDiagram(relInvocationNode); - Relation qvtrRelation = context.getQVTrElement(Relation.class, relDiagram); - if (!relInvocationNode.isIsThen()) { - context.addWhenPredicate(qvtrRelation, qvtrRelationCallExp); - } - else { - context.addWherePredicate(qvtrRelation, qvtrRelationCallExp); - } - return qvtrRelationCallExp; - } - - @Override - public @Nullable Element visitRelPatternExpressionNode( @NonNull RelPatternExpressionNode relPatternExpressionNode) { - StringLiteralExp stringExpression = context.getQVTrElement(StringLiteralExp.class, relPatternExpressionNode); - String textExpression = stringExpression.getStringSymbol(); - final EObject eContainer = stringExpression.eContainer(); - // context.getEnvironmentFactory().getMetamodelManager().parseSpecification(specification); - ParserContext parserContext = new AbstractParserContext(context.getEnvironmentFactory(), null) { - - @Override - public @Nullable ScopeView computeLookup(@NonNull EObject target, @NonNull EnvironmentView environmentView, @NonNull ScopeView scopeView) { - - EObject pivot = eContainer; - if ((pivot instanceof Element) && (pivot.eResource() != null) && !(pivot instanceof InvalidType)) { - environmentView.computeLookups((Element) pivot, null); //PivotUtil.getPivot(Element.class, scopeView.getChild()); - } - return scopeView.getParent(); - } - }; - // if (parserContext == null) { - // throw new ParserException(PivotMessagesInternal.UnknownContextType_ERROR_, NameUtil.qualifiedNameFor(contextElement), PivotUtilInternal.getSpecificationRole(specification)); - // } - parserContext.setRootElement((Element) eContainer); - try { - ExpressionInOCL expressionInOCL = parserContext.parse(eContainer, textExpression); - if (expressionInOCL != null) { - OCLExpression qvtrExpression = expressionInOCL.getOwnedBody(); - EReference eContainmentFeature = stringExpression.eContainmentFeature(); - PivotUtilInternal.resetContainer(stringExpression); - PivotUtilInternal.resetContainer(qvtrExpression); - eContainer.eSet(eContainmentFeature, qvtrExpression); - } - } catch (ParserException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - return null; - } - } - private final @NonNull Resource umlxResource; private final @NonNull Resource qvtrResource; - private final @NonNull Map<@NonNull UMLXElement, @NonNull Element> umlx2qvtr = new HashMap<>(); - private final @NonNull Set<@NonNull UMLXElement> references = new HashSet<>(); + private final @NonNull Map<@NonNull UMLXElement, @NonNull Element> umlxElement2qvtrElement = new HashMap<>(); + private final @NonNull List<@NonNull PatternForest> patternForests = new ArrayList<>(); + private final @NonNull List<@NonNull TxQueryNode> txQueryNodes = new ArrayList<>(); public UMLX2QVTr(@NonNull EnvironmentFactory environmentFactory, @NonNull Resource umlxResource, @NonNull Resource qvtrResource) { super(environmentFactory); @@ -844,12 +263,8 @@ public class UMLX2QVTr extends QVTrelationHelper this.qvtrResource = qvtrResource; } - public void addReference(@NonNull UMLXElement umlxElement) { - references.add(umlxElement); - } - protected <T extends Element> @Nullable T basicGetQVTrElement(@NonNull Class<T> qvtrClass, @NonNull UMLXElement umlxElement) { - Element qvtrElement = umlx2qvtr.get(umlxElement); + Element qvtrElement = umlxElement2qvtrElement.get(umlxElement); if (qvtrElement == null) { return null; } @@ -860,27 +275,12 @@ public class UMLX2QVTr extends QVTrelationHelper return castElement; } - public @Nullable EStructuralFeature getEcoreOf(@NonNull Property qvtrProperty) { - EStructuralFeature ecoreOfPivot = environmentFactory.getMetamodelManager().getEcoreOfPivot(EStructuralFeature.class, qvtrProperty); - return ecoreOfPivot; - } - - public @NonNull EnvironmentFactory getEnvironmentFactory() { + protected @NonNull EnvironmentFactory getEnvironmentFactory() { return environmentFactory; } - public @NonNull String getProjectName(@NonNull URI traceURI) { - URI trimFileExtension = traceURI.trimFileExtension(); - if (trimFileExtension.isPlatform()) { - return trimFileExtension.segment(1); - } - else { - return trimFileExtension.segment(0); - } - } - protected <T extends Element> @NonNull T getQVTrElement(@NonNull Class<T> qvtrClass, @NonNull UMLXElement umlxElement) { - Element qvtrElement = umlx2qvtr.get(umlxElement); + Element qvtrElement = umlxElement2qvtrElement.get(umlxElement); if (qvtrElement == null) { throw new IllegalArgumentException("Missing UMLX element for " + umlxElement); } @@ -891,8 +291,16 @@ public class UMLX2QVTr extends QVTrelationHelper return castElement; } - public @NonNull StandardLibrary getStandardLibrary() { - return environmentFactory.getStandardLibrary(); + protected org.eclipse.ocl.pivot.@NonNull Class getReferredType(@NonNull UMLXTypedElement umlxTypedElement) { + PivotMetamodelManager metamodelManager = (PivotMetamodelManager) environmentFactory.getMetamodelManager(); + EClassifier eClassifier = UMLXUtil.getReferredEClassifier(umlxTypedElement); + org.eclipse.ocl.pivot.Class asClass = metamodelManager.getASOfEcore(org.eclipse.ocl.pivot.Class.class, eClassifier); + assert asClass != null; + if (umlxTypedElement.isIsMany()) { + asClass = metamodelManager.getCollectionType(umlxTypedElement.isIsOrdered(), umlxTypedElement.isIsUnique(), asClass, + umlxTypedElement.isIsNullFree(), null, null); + } + return asClass; } /** @@ -900,13 +308,94 @@ public class UMLX2QVTr extends QVTrelationHelper * context. */ protected void install(@NonNull UMLXElement umlxElement, @NonNull Element qvtrElement) { - Element oldQVTrElement = umlx2qvtr.put(umlxElement, qvtrElement); + Element oldQVTrElement = umlxElement2qvtrElement.put(umlxElement, qvtrElement); assert oldQVTrElement == null; for (@NonNull String comment : UMLXUtil.getComments(umlxElement)) { qvtrElement.getOwnedComments().add(createComment(comment)); } } + /** + * Create a new trace for the given list of generated objects for the given + * context. + * + protected void reinstall(@NonNull UMLXElement umlxElement, @NonNull Element qvtrElement) { + Element oldQVTrElement = umlx2qvtr.put(umlxElement, qvtrElement); + assert oldQVTrElement != null; + qvtrElement.getOwnedComments().addAll(oldQVTrElement.getOwnedComments()); + } */ + + /* protected @Nullable ExpressionInOCL parseContextualExpressionInOCL(@NonNull EObject eContainer, @NonNull String textExpression) { + // context.getEnvironmentFactory().getMetamodelManager().parseSpecification(specification); + ParserContext parserContext = new AbstractParserContext(environmentFactory, null) { + + @Override + public @Nullable ScopeView computeLookup(@NonNull EObject target, @NonNull EnvironmentView environmentView, @NonNull ScopeView scopeView) { + + EObject pivot = eContainer; + if ((pivot instanceof Element) && (pivot.eResource() != null) && !(pivot instanceof InvalidType)) { + environmentView.computeLookups((Element) pivot, null); //PivotUtil.getPivot(Element.class, scopeView.getChild()); + } + return scopeView.getParent(); + } + }; + // if (parserContext == null) { + // throw new ParserException(PivotMessagesInternal.UnknownContextType_ERROR_, NameUtil.qualifiedNameFor(contextElement), PivotUtilInternal.getSpecificationRole(specification)); + // } + parserContext.setRootElement((Element) eContainer); + try { + return parserContext.parse(eContainer, textExpression); + } catch (ParserException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + return null; + } + } */ + protected @Nullable OCLExpression parseContextualExpression(@NonNull EObject eContainer, @NonNull List<String> textExpression) { + // context.getEnvironmentFactory().getMetamodelManager().parseSpecification(specification); + ParserContext parserContext = new AbstractParserContext(environmentFactory, null) { + + @Override + public @Nullable ScopeView computeLookup(@NonNull EObject target, @NonNull EnvironmentView environmentView, @NonNull ScopeView scopeView) { + + EObject pivot = eContainer; + if ((pivot instanceof Element) && (pivot.eResource() != null) && !(pivot instanceof InvalidType)) { + environmentView.computeLookups((Element) pivot, null); //PivotUtil.getPivot(Element.class, scopeView.getChild()); + } + return scopeView.getParent(); + } + }; + // if (parserContext == null) { + // throw new ParserException(PivotMessagesInternal.UnknownContextType_ERROR_, NameUtil.qualifiedNameFor(contextElement), PivotUtilInternal.getSpecificationRole(specification)); + // } + parserContext.setRootElement((Element) eContainer); + try { + StringBuilder s = new StringBuilder(); + for (String line : textExpression) { + s.append(line); + s.append("\n"); + } + ExpressionInOCL asExpressionInOCL = parserContext.parse(eContainer, s.toString()); + OCLExpression asExpression = asExpressionInOCL.getOwnedBody(); + assert asExpression != null; + PivotUtilInternal.resetContainer(asExpression); + return asExpression; + } catch (ParserException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + return null; + } + } + + private void resolveTxQueryBody(@NonNull TxQueryNode txQueryNode) { + Function asFunction = getQVTrElement(Function.class, txQueryNode); + List<String> lines = txQueryNode.getInitExpressionLines(); + if (lines.size() > 0) { + OCLExpression qvtrExpression = parseContextualExpression(asFunction, lines); + asFunction.setQueryExpression(qvtrExpression); + } + } + public void transform() throws CompilerChainException { for (EObject eObject : umlxResource.getContents()) { if (eObject instanceof UMLXModel) { @@ -916,11 +405,11 @@ public class UMLX2QVTr extends QVTrelationHelper qvtrResource.getContents().add(qvtrModel); } } - if (!references.isEmpty()) { - ReferenceVisitor referenceVisitor = new ReferenceVisitor(this); - for (@NonNull UMLXElement element : references) { - element.accept(referenceVisitor); - } + for (@NonNull TxQueryNode txQueryNode : txQueryNodes) { + resolveTxQueryBody(txQueryNode); + } + for (@NonNull PatternForest patternForest : patternForests) { + patternForest.resolveExpressions(); // Pass 2: parse the OCL text } } } diff --git a/plugins/org.eclipse.qvtd.umlx/src/org/eclipse/qvtd/umlx/utilities/UMLXServices.java b/plugins/org.eclipse.qvtd.umlx/src/org/eclipse/qvtd/umlx/utilities/UMLXServices.java index 48094736e..1b93ca64d 100644 --- a/plugins/org.eclipse.qvtd.umlx/src/org/eclipse/qvtd/umlx/utilities/UMLXServices.java +++ b/plugins/org.eclipse.qvtd.umlx/src/org/eclipse/qvtd/umlx/utilities/UMLXServices.java @@ -16,18 +16,25 @@ import java.util.HashSet; import java.util.List; import java.util.Set; +import org.eclipse.emf.common.util.EMap; +import org.eclipse.emf.ecore.EAnnotation; import org.eclipse.emf.ecore.EAttribute; import org.eclipse.emf.ecore.EClassifier; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.EReference; import org.eclipse.emf.ecore.EStructuralFeature; -import org.eclipse.emf.ecore.ETypedElement; import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.emf.ecore.util.EcoreUtil; +import org.eclipse.emf.ecore.xmi.impl.EMOFExtendedMetaData; import org.eclipse.jdt.annotation.NonNull; +import org.eclipse.ocl.pivot.internal.ecore.es2as.Ecore2ASReferenceSwitch; +import org.eclipse.ocl.pivot.internal.utilities.PivotConstantsInternal; import org.eclipse.ocl.pivot.utilities.ClassUtil; import org.eclipse.ocl.pivot.utilities.LabelUtil; import org.eclipse.ocl.pivot.utilities.TreeIterable; +import org.eclipse.ocl.pivot.utilities.ValueUtil; +import org.eclipse.ocl.pivot.values.IntegerValue; +import org.eclipse.ocl.pivot.values.UnlimitedNaturalValue; import org.eclipse.qvtd.umlx.RelDiagram; import org.eclipse.qvtd.umlx.RelDomainNode; import org.eclipse.qvtd.umlx.RelInvocationEdge; @@ -43,6 +50,7 @@ import org.eclipse.qvtd.umlx.TxPackageNode; import org.eclipse.qvtd.umlx.TxPartNode; import org.eclipse.qvtd.umlx.TxTypedModelNode; import org.eclipse.qvtd.umlx.UMLXNamedElement; +import org.eclipse.qvtd.umlx.UMLXTypedElement; /** * Class owning methods used for service: umlx. The service methods @@ -52,13 +60,11 @@ public class UMLXServices { public UMLXServices() {} - protected void appendMultiplicity(@NonNull StringBuilder s, @NonNull ETypedElement eTypedElement) { - if (!eTypedElement.isMany()) { - s.append(eTypedElement.isRequired() ? "[1]" : "[?]"); + protected void appendMultiplicity(@NonNull StringBuilder s, int lower, int upper) { + if (upper == 1) { + s.append(lower == 1 ? "[1]" : "[?]"); } else { - int lower = eTypedElement.getLowerBound(); - int upper = eTypedElement.getUpperBound(); if (upper < 0) { if (lower == 0) { s.append("[*]"); @@ -79,6 +85,27 @@ public class UMLXServices } } + protected void appendTypedElement(StringBuilder s, @NonNull UMLXTypedElement umlxTypedElement) { + s.append(String.valueOf(umlxTypedElement.getName())); + s.append(" : "); + if (umlxTypedElement.isIsMany()) { + if (umlxTypedElement.isIsUnique()) { + s.append(umlxTypedElement.isIsOrdered() ? "OrderedSet" : "Set"); + } + else { + s.append(umlxTypedElement.isIsOrdered() ? "Sequence" : "Bag"); + } + s.append("("); + } + EClassifier eClassifier = umlxTypedElement.getReferredEClassifier(); + if (eClassifier != null) { + s.append(eClassifier.eIsProxy() ? EcoreUtil.getURI(eClassifier) : String.valueOf(eClassifier.getName())); + } + if (umlxTypedElement.isIsMany()) { + s.append(")"); + } + } + protected @NonNull String defaultName(@NonNull EObject context, @NonNull Class<? extends UMLXNamedElement> newClass, @NonNull String prefix) { Set<String> allNames = new HashSet<>(); Resource eResource = context.eResource(); @@ -96,6 +123,110 @@ public class UMLXServices } } + private int getEOppositeLower(@NonNull EReference eReference) { + EReference eOpposite = eReference.getEOpposite(); + if (eOpposite != null) { + return eOpposite.getLowerBound(); + } + EAnnotation oppositeRole = eReference.getEAnnotation(EMOFExtendedMetaData.EMOF_PACKAGE_NS_URI_2_0); + if (oppositeRole != null) { + EMap<String, String> details = oppositeRole.getDetails(); + String oppositeName = details.get(Ecore2ASReferenceSwitch.PROPERTY_OPPOSITE_ROLE_NAME_KEY); + if (oppositeName != null) { + String lowerValue = details.get(Ecore2ASReferenceSwitch.PROPERTY_OPPOSITE_ROLE_LOWER_KEY); + IntegerValue one = ValueUtil.ONE_VALUE; + IntegerValue lower = lowerValue != null ? ValueUtil.integerValueOf(lowerValue) : one; + if (lower.isInvalid()) { + // logger.error("Invalid " + Ecore2ASReferenceSwitch.PROPERTY_OPPOSITE_ROLE_LOWER_KEY + " " + lower); + lower = one; + } + return lower.intValue(); + } + } + else { + oppositeRole = eReference.getEAnnotation(EMOFExtendedMetaData.EMOF_PROPERTY_OPPOSITE_ROLE_NAME_ANNOTATION_SOURCE); + if (oppositeRole != null) { + EMap<String, String> details = oppositeRole.getDetails(); + String oppositeName = details.get(EMOFExtendedMetaData.EMOF_COMMENT_BODY); + if (oppositeName != null) { + String lowerValue = details.get("lower"); + IntegerValue lower = lowerValue != null ? ValueUtil.integerValueOf(lowerValue) : PivotConstantsInternal.ANNOTATED_IMPLICIT_OPPOSITE_LOWER_VALUE; + if (lower.isInvalid()) { + // logger.error("Invalid " + Ecore2ASReferenceSwitch.PROPERTY_OPPOSITE_ROLE_LOWER_KEY + " " + lower); + lower = PivotConstantsInternal.ANNOTATED_IMPLICIT_OPPOSITE_LOWER_VALUE; + } + return lower.intValue(); + } + } + } + return 0; + } + + private String getEOppositeName(@NonNull EReference eReference) { + EReference eOpposite = eReference.getEOpposite(); + if (eOpposite != null) { + return eOpposite.getName(); + } + EAnnotation oppositeRole = eReference.getEAnnotation(EMOFExtendedMetaData.EMOF_PACKAGE_NS_URI_2_0); + if (oppositeRole != null) { + EMap<String, String> details = oppositeRole.getDetails(); + String oppositeName = details.get(Ecore2ASReferenceSwitch.PROPERTY_OPPOSITE_ROLE_NAME_KEY); + if (oppositeName != null) { + return oppositeName; + } + } + else { + oppositeRole = eReference.getEAnnotation(EMOFExtendedMetaData.EMOF_PROPERTY_OPPOSITE_ROLE_NAME_ANNOTATION_SOURCE); + if (oppositeRole != null) { + EMap<String, String> details = oppositeRole.getDetails(); + String oppositeName = details.get(EMOFExtendedMetaData.EMOF_COMMENT_BODY); + if (oppositeName != null) { + return oppositeName; + } + } + } + return "«inferred»"; + } + + private int getEOppositeUpper(@NonNull EReference eReference) { + EReference eOpposite = eReference.getEOpposite(); + if (eOpposite != null) { + return eOpposite.getUpperBound(); + } + EAnnotation oppositeRole = eReference.getEAnnotation(EMOFExtendedMetaData.EMOF_PACKAGE_NS_URI_2_0); + if (oppositeRole != null) { + EMap<String, String> details = oppositeRole.getDetails(); + String oppositeName = details.get(Ecore2ASReferenceSwitch.PROPERTY_OPPOSITE_ROLE_NAME_KEY); + if (oppositeName != null) { + String upperValue = details.get(Ecore2ASReferenceSwitch.PROPERTY_OPPOSITE_ROLE_UPPER_KEY); + UnlimitedNaturalValue unlimitedOne = ValueUtil.UNLIMITED_ONE_VALUE; + UnlimitedNaturalValue upper = upperValue != null ? ValueUtil.unlimitedNaturalValueOf(upperValue) : unlimitedOne; + if (upper.isInvalid()) { + // logger.error("Invalid " + Ecore2ASReferenceSwitch.PROPERTY_OPPOSITE_ROLE_UPPER_KEY + " " + upper); + upper = unlimitedOne; + } + return upper.intValue(); + } + } + else { + oppositeRole = eReference.getEAnnotation(EMOFExtendedMetaData.EMOF_PROPERTY_OPPOSITE_ROLE_NAME_ANNOTATION_SOURCE); + if (oppositeRole != null) { + EMap<String, String> details = oppositeRole.getDetails(); + String oppositeName = details.get(EMOFExtendedMetaData.EMOF_COMMENT_BODY); + if (oppositeName != null) { + String upperValue = details.get("upper"); + UnlimitedNaturalValue upper = upperValue != null ? ValueUtil.unlimitedNaturalValueOf(upperValue) : PivotConstantsInternal.ANNOTATED_IMPLICIT_OPPOSITE_UPPER_VALUE; + if (upper.isInvalid()) { + // logger.error("Invalid " + Ecore2ASReferenceSwitch.PROPERTY_OPPOSITE_ROLE_UPPER_KEY + " " + upper); + upper = PivotConstantsInternal.ANNOTATED_IMPLICIT_OPPOSITE_UPPER_VALUE; + } + return upper.intValue(); + } + } + } + return 0; + } + public int umlxBorderSize(EObject context) { return 4; } @@ -178,31 +309,30 @@ public class UMLXServices } } else if (context instanceof RelPatternClassNode) { - RelPatternClassNode relPatternClassNode = (RelPatternClassNode)context; StringBuilder s = new StringBuilder(); - s.append(String.valueOf(relPatternClassNode.getName())); - s.append(" : "); - if (relPatternClassNode.isIsMany()) { - if (relPatternClassNode.isIsUnique()) { - s.append(relPatternClassNode.isIsOrdered() ? "OrderedSet" : "Set"); - } - else { - s.append(relPatternClassNode.isIsOrdered() ? "Sequence" : "Bag"); + RelPatternClassNode relPatternClassNode = (RelPatternClassNode)context; + appendTypedElement(s, relPatternClassNode); + List<String> initExpressionLines = relPatternClassNode.getInitExpressionLines(); + if (initExpressionLines.size() > 0) { + s.append(" :="); + for (String line : initExpressionLines) { + s.append("\n"); + s.append(line); } - s.append("("); - } - EClassifier eClassifier = relPatternClassNode.getReferredEClassifier(); - if (eClassifier != null) { - s.append(eClassifier.eIsProxy() ? EcoreUtil.getURI(eClassifier) : String.valueOf(eClassifier.getName())); - } - if (relPatternClassNode.isIsMany()) { - s.append(")"); } return s.toString(); } else if (context instanceof RelPatternExpressionNode) { - String expression = ((RelPatternExpressionNode)context).getExpression(); - return expression != null ? expression : "«null-expression»"; + StringBuilder s = new StringBuilder(); + boolean firstLine = true; + for (String line : ((RelPatternExpressionNode)context).getInitExpressionLines()) { + if (!firstLine) { + s.append("\n"); + s.append(line); + firstLine = false; + } + } + return s.toString(); } else if (context instanceof TxImportNode) { return String.valueOf(((TxImportNode)context).getName()); @@ -231,6 +361,11 @@ public class UMLXServices else if (context instanceof TxTypedModelNode) { return String.valueOf(((TxTypedModelNode)context).getName()); } + else if (context instanceof UMLXTypedElement) { + StringBuilder s = new StringBuilder(); + appendTypedElement(s, (UMLXTypedElement)context); + return s.toString(); + } return "«umlxLabel - " + context.getClass().getName() + " - " + context.eClass().getName() + "»"; } @@ -241,14 +376,11 @@ public class UMLXServices if (context instanceof RelPatternEdge) { EStructuralFeature eStructuralFeature = ((RelPatternEdge)context).getReferredEStructuralFeature(); if (eStructuralFeature instanceof EReference) { - EReference eOpposite = ((EReference)eStructuralFeature).getEOpposite(); - if (eOpposite == null) { - return "«inferred»"; - } + EReference eReference = (EReference)eStructuralFeature; StringBuilder s = new StringBuilder(); - s.append(String.valueOf(eOpposite.getName())); + s.append(getEOppositeName(eReference)); s.append(" "); - appendMultiplicity(s, eOpposite); + appendMultiplicity(s, getEOppositeLower(eReference), getEOppositeUpper(eReference)); return s.toString(); } } @@ -281,7 +413,7 @@ public class UMLXServices StringBuilder s = new StringBuilder(); s.append(String.valueOf(eStructuralFeature.getName())); s.append(" "); - appendMultiplicity(s, eStructuralFeature); + appendMultiplicity(s, eStructuralFeature.getLowerBound(), eStructuralFeature.getUpperBound()); return s.toString(); } } diff --git a/plugins/org.eclipse.qvtd.umlx/src/org/eclipse/qvtd/umlx/utilities/UMLXStandaloneSetup.java b/plugins/org.eclipse.qvtd.umlx/src/org/eclipse/qvtd/umlx/utilities/UMLXStandaloneSetup.java index 17c898712..85cabc702 100644 --- a/plugins/org.eclipse.qvtd.umlx/src/org/eclipse/qvtd/umlx/utilities/UMLXStandaloneSetup.java +++ b/plugins/org.eclipse.qvtd.umlx/src/org/eclipse/qvtd/umlx/utilities/UMLXStandaloneSetup.java @@ -21,6 +21,10 @@ import org.eclipse.emf.ecore.xmi.impl.XMIResourceFactoryImpl; import org.eclipse.ocl.pivot.labels.ILabelGenerator; import org.eclipse.qvtd.umlx.UMLXPackage; import org.eclipse.qvtd.umlx.labels.RelPatternEdgeLabelGenerator; +import org.eclipse.qvtd.umlx.labels.UMLXModelLabelGenerator; +import org.eclipse.qvtd.umlx.labels.UMLXNamedElementLabelGenerator; +import org.eclipse.qvtd.umlx.labels.RelDomainNodeLabelGenerator; +import org.eclipse.qvtd.umlx.labels.RelPatternClassNodeLabelGenerator; import org.eclipse.qvtd.umlx.resource.UMLXResourceFactoryImpl; import org.eclipse.qvtd.umlx.util.UMLXValidator; @@ -50,7 +54,11 @@ public class UMLXStandaloneSetup } EPackage.Registry.INSTANCE.put(UMLXPackage.eNS_URI, UMLXPackage.eINSTANCE); EValidator.Registry.INSTANCE.put(UMLXPackage.eINSTANCE, UMLXValidator.INSTANCE); + RelDomainNodeLabelGenerator.initialize(ILabelGenerator.Registry.INSTANCE); + RelPatternClassNodeLabelGenerator.initialize(ILabelGenerator.Registry.INSTANCE); RelPatternEdgeLabelGenerator.initialize(ILabelGenerator.Registry.INSTANCE); + UMLXModelLabelGenerator.initialize(ILabelGenerator.Registry.INSTANCE); + UMLXNamedElementLabelGenerator.initialize(ILabelGenerator.Registry.INSTANCE); } /** diff --git a/plugins/org.eclipse.qvtd.umlx/src/org/eclipse/qvtd/umlx/utilities/UMLXToStringVisitor.java b/plugins/org.eclipse.qvtd.umlx/src/org/eclipse/qvtd/umlx/utilities/UMLXToStringVisitor.java index 83a6ee72f..470c13c53 100644 --- a/plugins/org.eclipse.qvtd.umlx/src/org/eclipse/qvtd/umlx/utilities/UMLXToStringVisitor.java +++ b/plugins/org.eclipse.qvtd.umlx/src/org/eclipse/qvtd/umlx/utilities/UMLXToStringVisitor.java @@ -10,6 +10,8 @@ *******************************************************************************/ package org.eclipse.qvtd.umlx.utilities; +import java.util.List; + import org.eclipse.emf.ecore.EClassifier; import org.eclipse.emf.ecore.EPackage; import org.eclipse.emf.ecore.EStructuralFeature; @@ -17,6 +19,7 @@ import org.eclipse.jdt.annotation.NonNull; import org.eclipse.jdt.annotation.Nullable; import org.eclipse.ocl.pivot.utilities.LabelUtil; import org.eclipse.qvtd.umlx.RelPatternExpressionNode; +import org.eclipse.qvtd.umlx.TxImportNode; import org.eclipse.qvtd.umlx.RelDiagram; import org.eclipse.qvtd.umlx.RelDomainNode; import org.eclipse.qvtd.umlx.RelInvocationEdge; @@ -26,10 +29,12 @@ import org.eclipse.qvtd.umlx.RelPatternClassNode; import org.eclipse.qvtd.umlx.TxKeyNode; import org.eclipse.qvtd.umlx.TxPackageNode; 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.UMLXModel; import org.eclipse.qvtd.umlx.UMLXNamedElement; +import org.eclipse.qvtd.umlx.UMLXTypedElement; import org.eclipse.qvtd.umlx.util.AbstractExtendingUMLXVisitor; public class UMLXToStringVisitor extends AbstractExtendingUMLXVisitor<@Nullable Object, @NonNull StringBuilder> @@ -79,25 +84,19 @@ public class UMLXToStringVisitor extends AbstractExtendingUMLXVisitor<@Nullable @Override public @Nullable Object visitRelPatternClassNode(@NonNull RelPatternClassNode relPatternClassNode) { - EClassifier eClassifier = relPatternClassNode.getReferredEClassifier(); - append(relPatternClassNode.getName()); - append(" : "); - if (relPatternClassNode.isIsMany()) { - if (relPatternClassNode.isIsUnique()) { - append(relPatternClassNode.isIsOrdered() ? "OrderedSet" : "Set"); - } - else { - append(relPatternClassNode.isIsOrdered() ? "Sequence" : "Bag"); + visitUMLXTypedElement(relPatternClassNode); + List<String> lines = relPatternClassNode.getInitExpressionLines(); + if (lines.size() > 0) { + append(" = "); + boolean firstLine = true; + for (String line : lines) { + if (!firstLine) { + append("\n"); + } + append(line); + firstLine = false; } - append("("); - append(LabelUtil.getLabel(eClassifier)); - append(relPatternClassNode.isIsNullFree() ? "[*|1]" : "[*|?]"); - append(")"); } - else { - append(LabelUtil.getLabel(eClassifier)); - } - append(relPatternClassNode.isIsRequired() ? "[1]" : "[?]"); return null; } @@ -115,8 +114,23 @@ public class UMLXToStringVisitor extends AbstractExtendingUMLXVisitor<@Nullable @Override public @Nullable Object visitRelPatternExpressionNode(@NonNull RelPatternExpressionNode relPatternExpressionNode) { - String expression = relPatternExpressionNode.getExpression(); - append(expression); + List<String> lines = relPatternExpressionNode.getInitExpressionLines(); + if (lines.size() > 0) { + boolean firstLine = true; + for (String line : lines) { + if (!firstLine) { + append("\n"); + } + append(line); + firstLine = false; + } + } + return null; + } + + @Override + public @Nullable Object visitTxImportNode(@NonNull TxImportNode txImportNode) { + append(txImportNode.getName()); return null; } @@ -145,6 +159,31 @@ public class UMLXToStringVisitor extends AbstractExtendingUMLXVisitor<@Nullable } @Override + public @Nullable Object visitTxQueryNode(@NonNull TxQueryNode txQueryNode) { + visitUMLXTypedElement(txQueryNode); + // fixme parameters + List<String> lines = txQueryNode.getInitExpressionLines(); + if (lines.size() > 0) { + append(" = "); + boolean firstLine = true; + for (String line : lines) { + if (!firstLine) { + append("\n"); + } + append(line); + firstLine = false; + } + } + return null; + } + + @Override + public @Nullable Object visitTxTypedModelNode(@NonNull TxTypedModelNode txTypedModelNode) { + append(txTypedModelNode.getName()); + return null; + } + + @Override public @Nullable Object visitUMLXModel(@NonNull UMLXModel umlxModel) { return "UMLXModel"; } @@ -156,6 +195,30 @@ public class UMLXToStringVisitor extends AbstractExtendingUMLXVisitor<@Nullable } @Override + public @Nullable Object visitUMLXTypedElement(@NonNull UMLXTypedElement umlxTypedElement) { + EClassifier eClassifier = umlxTypedElement.getReferredEClassifier(); + append(umlxTypedElement.getName()); + append(" : "); + if (umlxTypedElement.isIsMany()) { + if (umlxTypedElement.isIsUnique()) { + append(umlxTypedElement.isIsOrdered() ? "OrderedSet" : "Set"); + } + else { + append(umlxTypedElement.isIsOrdered() ? "Sequence" : "Bag"); + } + append("("); + append(LabelUtil.getLabel(eClassifier)); + append(umlxTypedElement.isIsNullFree() ? "[*|1]" : "[*|?]"); + append(")"); + } + else { + append(LabelUtil.getLabel(eClassifier)); + } + append(umlxTypedElement.isIsRequired() ? "[1]" : "[?]"); + return null; + } + + @Override public @Nullable Object visiting(@NonNull UMLXElement umlxElement) { append("Unsupported " + getClass().getSimpleName() + " for " + umlxElement.eClass().getName()); return null; diff --git a/plugins/org.eclipse.qvtd.umlx/src/org/eclipse/qvtd/umlx/utilities/UMLXUtil.java b/plugins/org.eclipse.qvtd.umlx/src/org/eclipse/qvtd/umlx/utilities/UMLXUtil.java index ce634b591..11251f006 100644 --- a/plugins/org.eclipse.qvtd.umlx/src/org/eclipse/qvtd/umlx/utilities/UMLXUtil.java +++ b/plugins/org.eclipse.qvtd.umlx/src/org/eclipse/qvtd/umlx/utilities/UMLXUtil.java @@ -34,11 +34,14 @@ import org.eclipse.qvtd.umlx.TxDiagram; import org.eclipse.qvtd.umlx.TxImportNode; 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.UMLXModel; import org.eclipse.qvtd.umlx.UMLXNamedElement; +import org.eclipse.qvtd.umlx.UMLXTypedElement; import com.google.common.base.Predicate; import com.google.common.collect.Iterables; @@ -51,6 +54,10 @@ public class UMLXUtil public static @NonNull List<@NonNull RelPatternEdge> getIncomingList(@NonNull RelPatternNode relNode) { return ClassUtil.nullFree(relNode.getIncoming()); } + + public static @NonNull List<@NonNull RelPatternNode> getOwnedRelPatternNodesList(@NonNull RelDomainNode relDomainNode) { + return ClassUtil.nullFree(relDomainNode.getOwnedRelPatternNodes()); + } } public static final class IsRootPredicate implements Predicate<@NonNull RelPatternClassNode> @@ -93,18 +100,14 @@ public class UMLXUtil return ClassUtil.nullFree(umlxElement.getComments()); } - public static @NonNull String getExpression(@NonNull RelPatternExpressionNode relPatternExpressionNode) { - return ClassUtil.nonNullState(relPatternExpressionNode.getExpression()); - } - - // public static @NonNull RelDiagram getDiagram(@NonNull RelPatternNode relNode) { - // return ClassUtil.nonNullState(relNode.getDiagram()); - // } - public static @NonNull Iterable<@NonNull RelPatternEdge> getIncoming(@NonNull RelPatternNode relNode) { return ClassUtil.nullFree(relNode.getIncoming()); } + public static @NonNull List<@NonNull String> getInitExpressionLines(@NonNull RelPatternExpressionNode relPatternExpressionNode) { + return ClassUtil.nullFree(relPatternExpressionNode.getInitExpressionLines()); + } + public static @NonNull RelPatternNode getInvokingRelPatternNode(@NonNull RelInvocationEdge relInvocationEdge) { return ClassUtil.nonNullState(relInvocationEdge.getInvokingRelPatternNode()); } @@ -157,10 +160,18 @@ public class UMLXUtil return ClassUtil.nullFree(txTypedModelNode.getOwnedTxPackageNodes()); } + public static @NonNull Iterable<@NonNull TxParameterNode> getOwnedTxParameterNodes(@NonNull TxQueryNode txTypedModelNode) { + return ClassUtil.nullFree(txTypedModelNode.getOwnedTxParameterNodes()); + } + public static @NonNull Iterable<@NonNull TxPartNode> getOwnedTxPartNodes(@NonNull TxKeyNode txKeyNode) { return ClassUtil.nullFree(txKeyNode.getOwnedTxPartNodes()); } + public static @NonNull Iterable<@NonNull TxQueryNode> getOwnedTxQueryNodes(@NonNull TxDiagram txDiagram) { + return ClassUtil.nullFree(txDiagram.getOwnedTxQueryNodes()); + } + public static @NonNull Iterable<@NonNull TxTypedModelNode> getOwnedTxTypedModelNodes(@NonNull TxDiagram txDiagram) { return ClassUtil.nullFree(txDiagram.getOwnedTxTypedModelNodes()); } @@ -169,12 +180,16 @@ public class UMLXUtil return ClassUtil.nonNullState(relInvocationNode.getOwningRelDiagram()); } + public static @NonNull RelDomainNode getOwningRelDomainNode(@NonNull RelPatternNode relPatternNode) { + return ClassUtil.nonNullState(relPatternNode.getOwningRelDomainNode()); + } + public static @NonNull EClass getReferredEClass(@NonNull TxKeyNode txKeyNode) { return ClassUtil.nonNullState(txKeyNode.getReferredEClass()); } - public static @NonNull EClassifier getReferredEClassifier(@NonNull RelPatternClassNode relPatternNode) { - return ClassUtil.nonNullState(relPatternNode.getReferredEClassifier()); + public static @NonNull EClassifier getReferredEClassifier(@NonNull UMLXTypedElement umlxTypedElement) { + return ClassUtil.nonNullState(umlxTypedElement.getReferredEClassifier()); } public static @NonNull EPackage getReferredEPackage(@NonNull TxPackageNode txPackageNode) { diff --git a/tests/org.eclipse.qvtd.all.tests/src/org/eclipse/qvtd/all/tests/AllQVTdTests.java b/tests/org.eclipse.qvtd.all.tests/src/org/eclipse/qvtd/all/tests/AllQVTdTests.java index 96319c47d..ecd57f828 100644 --- a/tests/org.eclipse.qvtd.all.tests/src/org/eclipse/qvtd/all/tests/AllQVTdTests.java +++ b/tests/org.eclipse.qvtd.all.tests/src/org/eclipse/qvtd/all/tests/AllQVTdTests.java @@ -21,7 +21,7 @@ import org.eclipse.qvtd.doc.bigmde2016.tests.qvtc.BigMDE2016_QVTc_AutomatedTests import org.eclipse.qvtd.doc.exe2016.tests.qvtc.EXE2016_QVTc_AutomatedTests; import org.eclipse.qvtd.doc.exe2016.tests.qvtr.EXE2016_QVTr_AutomatedTests; import org.eclipse.qvtd.doc.minioclcs.xtext.tests.MiniOCLCSParsingTest; -import org.eclipse.qvtd.umlx.tests.UMLXTests; +import org.eclipse.qvtd.umlx.tests.AllUMLXTests; import org.eclipse.qvtd.xtext.qvtbase.tests.QVTbaseLibraryTests; import org.eclipse.qvtd.xtext.qvtcore.tests.AllQVTcoreTests; import org.eclipse.qvtd.xtext.qvtimperative.tests.AllQVTimperativeTests; @@ -61,7 +61,7 @@ public class AllQVTdTests extends TestCase if (!EMFPlugin.IS_ECLIPSE_RUNNING) { // FIXME should work as plugin test too result.addTestSuite(OCL2QVTiTestCases.class); } - result.addTestSuite(UMLXTests.class); + result.addTest(AllUMLXTests.suite()); result.addTestSuite(BigMDE2016_QVTc_AutomatedTests.class); // NB this is very slow since we are -ea result.addTestSuite(EXE2016_QVTc_AutomatedTests.class); // NB this is very slow since we are -ea result.addTestSuite(EXE2016_QVTr_AutomatedTests.class); // NB this is very slow since we are -ea diff --git a/tests/org.eclipse.qvtd.umlx.tests/META-INF/MANIFEST.MF b/tests/org.eclipse.qvtd.umlx.tests/META-INF/MANIFEST.MF index 8a148956d..308289feb 100644 --- a/tests/org.eclipse.qvtd.umlx.tests/META-INF/MANIFEST.MF +++ b/tests/org.eclipse.qvtd.umlx.tests/META-INF/MANIFEST.MF @@ -8,6 +8,7 @@ Bundle-RequiredExecutionEnvironment: JavaSE-1.8 Require-Bundle: org.eclipse.qvtd.xtext.qvtbase.tests, org.eclipse.qvtd.xtext.qvtrelation.tests, org.eclipse.qvtd.compiler, - org.eclipse.qvtd.umlx + org.eclipse.qvtd.umlx, + com.google.guava Bundle-Localization: plugin Export-Package: org.eclipse.qvtd.umlx.tests diff --git a/tests/org.eclipse.qvtd.umlx.tests/src-gen/.gitignore b/tests/org.eclipse.qvtd.umlx.tests/src-gen/.gitignore new file mode 100644 index 000000000..cf1db2eed --- /dev/null +++ b/tests/org.eclipse.qvtd.umlx.tests/src-gen/.gitignore @@ -0,0 +1 @@ +/org/ diff --git a/tests/org.eclipse.qvtd.umlx.tests/src/org/eclipse/qvtd/umlx/tests/AllUMLXTests.java b/tests/org.eclipse.qvtd.umlx.tests/src/org/eclipse/qvtd/umlx/tests/AllUMLXTests.java new file mode 100644 index 000000000..9281302ef --- /dev/null +++ b/tests/org.eclipse.qvtd.umlx.tests/src/org/eclipse/qvtd/umlx/tests/AllUMLXTests.java @@ -0,0 +1,42 @@ +/******************************************************************************* + * Copyright (c) 2016 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.qvtd.umlx.tests; + +import java.util.Arrays; + +import junit.framework.Test; +import junit.framework.TestCase; +import junit.framework.TestSuite; +import junit.textui.TestRunner; + +/** + * Tests for the UMLX support. + */ +public class AllUMLXTests extends TestCase +{ + public AllUMLXTests() { + super(""); + } + + public static Test suite() { + TestSuite result = new TestSuite("All UMLX Tests"); + result.addTestSuite(UMLXSerializeTests.class); + return result; + } + + public Object run(Object args) + throws Exception { + + TestRunner.run(suite()); + return Arrays + .asList(new String[] {"Please see raw test suite output for details."}); + } +} diff --git a/tests/org.eclipse.qvtd.umlx.tests/src/org/eclipse/qvtd/umlx/tests/UMLXTests.java b/tests/org.eclipse.qvtd.umlx.tests/src/org/eclipse/qvtd/umlx/tests/UMLXSerializeTests.java index 79991c65a..36103eb6f 100644 --- a/tests/org.eclipse.qvtd.umlx.tests/src/org/eclipse/qvtd/umlx/tests/UMLXTests.java +++ b/tests/org.eclipse.qvtd.umlx.tests/src/org/eclipse/qvtd/umlx/tests/UMLXSerializeTests.java @@ -10,14 +10,39 @@ *******************************************************************************/ package org.eclipse.qvtd.umlx.tests; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + import org.eclipse.emf.common.EMFPlugin; +import org.eclipse.emf.common.util.TreeIterator; import org.eclipse.emf.common.util.URI; +import org.eclipse.emf.ecore.EClassifier; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.EReference; import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.jdt.annotation.NonNull; +import org.eclipse.ocl.pivot.Element; import org.eclipse.ocl.pivot.Model; +import org.eclipse.ocl.pivot.PivotPackage; +import org.eclipse.ocl.pivot.Property; +import org.eclipse.ocl.pivot.VariableDeclaration; +import org.eclipse.ocl.pivot.VariableExp; import org.eclipse.ocl.pivot.utilities.OCL; import org.eclipse.ocl.pivot.utilities.PivotUtil; +import org.eclipse.ocl.pivot.utilities.TreeIterable; import org.eclipse.ocl.xtext.base.services.BaseLinkingService; +import org.eclipse.qvtd.pivot.qvtbase.utilities.QVTbaseUtil; +import org.eclipse.qvtd.pivot.qvtrelation.DomainPattern; +import org.eclipse.qvtd.pivot.qvtrelation.QVTrelationFactory; +import org.eclipse.qvtd.pivot.qvtrelation.Relation; +import org.eclipse.qvtd.pivot.qvtrelation.TemplateVariable; +import org.eclipse.qvtd.pivot.qvtrelation.utilities.QVTrelation; +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.qvtr2umlx.QVTr2UMLX; import org.eclipse.qvtd.umlx.umlx2qvtr.UMLX2QVTr; import org.eclipse.qvtd.umlx.utilities.UMLXStandaloneSetup; @@ -25,10 +50,12 @@ import org.eclipse.qvtd.xtext.qvtbase.tests.LoadTestCase; import org.eclipse.qvtd.xtext.qvtbase.tests.utilities.TestsXMLUtil; import org.eclipse.qvtd.xtext.qvtrelation.tests.QVTrTestUtil; +import com.google.common.collect.Lists; + /** * Tests that load a model and verify that there are no unresolved proxies as a result. */ -public class UMLXTests extends LoadTestCase +public class UMLXSerializeTests extends LoadTestCase { /* protected void doLoad_QVTr(URI inputURI, URI pivotURI) throws IOException { OCL ocl = OCL.newInstance(getProjectMap()); @@ -49,7 +76,7 @@ public class UMLXTests extends LoadTestCase ocl.dispose(); } - protected void doRoundTripTest(@NonNull URI inputURI1, @NonNull URI pivotURI1, @NonNull URI umlxURI, @NonNull URI pivotURI2) throws Exception { + protected void doRoundTripTest(@NonNull URI inputURI1, @NonNull URI pivotURI1, @NonNull URI umlxURI, @NonNull URI pivotURI2, boolean skipCompare) throws Exception { OCL ocl1 = OCL.newInstance(getProjectMap()); Resource qvtrResource1 = doLoad_Concrete(ocl1, inputURI1, pivotURI1, null); Resource umlxResource1 = qvtrResource1.getResourceSet().createResource(umlxURI); @@ -59,7 +86,7 @@ public class UMLXTests extends LoadTestCase // assertNoValidationErrors(umlxURI.toString(), umlxResource1); // - OCL ocl2 = OCL.newInstance(getProjectMap()); + QVTrelation ocl2 = QVTrelation.newInstance(getProjectMap()); Resource umlxResource2 = ocl2.getResourceSet().getResource(umlxURI, true); Resource qvtrResource2 = ocl2.getMetamodelManager().getASResourceSet().createResource(pivotURI2); UMLX2QVTr umlx2qvtr = new UMLX2QVTr(ocl2.getEnvironmentFactory(), umlxResource2, qvtrResource2); @@ -70,11 +97,135 @@ public class UMLXTests extends LoadTestCase Model asModel2 = PivotUtil.getModel(qvtrResource2); asModel2.setName(asModel1.getName()); asModel2.setExternalURI(asModel1.getExternalURI()); - assertSameModel(qvtrResource1, qvtrResource2); + TestsXMLUtil.resetTransients(qvtrResource1); + TestsXMLUtil.resetTransients(qvtrResource2); + normalize(qvtrResource1); + normalize(qvtrResource2); + if (!skipCompare) { // FIXME BUG 511230 + assertSameModel(qvtrResource1, qvtrResource2); + } ocl1.dispose(); ocl2.dispose(); } + private void normalize(@NonNull Resource qvtrResource) { + for (TreeIterator<EObject> tit = qvtrResource.getAllContents(); tit.hasNext(); ) { + EObject eObject = tit.next(); + if (eObject instanceof Relation) { + normalizeRelation((Relation)eObject); + tit.prune(); + } + } + } + + /** + * For non-composed leaf template elements there is a free choice to use a shared or template variable. Since there may be multiple + * candidate sites for the template variable, normalize by using a shared variable. + */ + private void normalizeRelation(@NonNull Relation asRelation) { + // + // Find all references to all variables within the Relation + // + Map<@NonNull VariableDeclaration, @NonNull List<@NonNull Element>> variable2reference = new HashMap<>(); + for (@NonNull EObject eObject : new TreeIterable(asRelation, true)) { + List<@NonNull VariableDeclaration> referredVariables = null; + if (eObject instanceof VariableExp) { + referredVariables = Lists.newArrayList(((VariableExp)eObject).getReferredVariable()); + } + else if (eObject instanceof TemplateExp) { + referredVariables = Lists.newArrayList(((TemplateExp)eObject).getBindsTo()); + if (eObject instanceof CollectionTemplateExp) { + referredVariables.add(((CollectionTemplateExp)eObject).getRest()); + } + } + else if (eObject instanceof DomainPattern) { + referredVariables = Lists.newArrayList(((DomainPattern)eObject).getBindsTo()); + } + if (referredVariables != null) { + for (@NonNull VariableDeclaration referredVariable : referredVariables) { + List<@NonNull Element> references = variable2reference.get(referredVariable); + if (references == null) { + references = new ArrayList<>(); + variable2reference.put(referredVariable, references); + } + references.add((Element)eObject); + } + } + } + // + // Replace leaf non-composite template variables + // + for (@NonNull VariableDeclaration variable : variable2reference.keySet()) { + List<@NonNull Element> references = variable2reference.get(variable); + assert references != null; + if (variable instanceof TemplateVariable) { + boolean canBeShared = true; + for (@NonNull Element reference : references) { + if (reference instanceof ObjectTemplateExp) { + ObjectTemplateExp objectTemplateExp = (ObjectTemplateExp)reference; + if (!objectTemplateExp.getPart().isEmpty()) { + canBeShared = false; + break; + } + EObject eContainer = objectTemplateExp.eContainer(); + if (eContainer instanceof PropertyTemplateItem) { + Property asProperty = ((PropertyTemplateItem)eContainer).getReferredProperty(); + if ((asProperty == null) || asProperty.isIsComposite()) { + canBeShared = false; + break; + } + } + else { + canBeShared = false; + break; + } + } + else if (reference instanceof CollectionTemplateExp) { + CollectionTemplateExp collectionTemplateExp = (CollectionTemplateExp)reference; + if (!collectionTemplateExp.getMember().isEmpty()) { + canBeShared = false; + break; + } + if (collectionTemplateExp.getRest() != null) { + canBeShared = false; + break; + } + } + EReference eContainmentFeature = reference.eContainmentFeature(); + EClassifier eType = eContainmentFeature.getEType(); + if (!eType.isInstance(PivotPackage.Literals.OCL_EXPRESSION)) { + canBeShared = false; + break; + } + } + if (canBeShared) { + VariableDeclaration sharedVariable = QVTrelationFactory.eINSTANCE.createSharedVariable(); + sharedVariable.setName(variable.getName()); + sharedVariable.setType(variable.getType()); + // sharedVariable.setIsImplicit(variable.isIsImplicit()); + sharedVariable.setIsRequired(variable.isIsRequired()); + // sharedVariable.setOwnedInit(variable.get); + QVTbaseUtil.replaceChild(variable, sharedVariable); + for (@NonNull Element reference : references) { + if (reference instanceof VariableExp) { + ((VariableExp)reference).setReferredVariable(sharedVariable); + } + else if (reference instanceof ObjectTemplateExp) { + QVTbaseUtil.replaceChild(reference, PivotUtil.createVariableExp(sharedVariable)); + } + else if (reference instanceof CollectionTemplateExp) { + QVTbaseUtil.replaceChild(reference, PivotUtil.createVariableExp(sharedVariable)); + } + else if (reference instanceof DomainPattern) { + ((DomainPattern)reference).getBindsTo().remove(variable); + } + } + } + } + } + } + + @Override protected void setUp() throws Exception { QVTrTestUtil.doQVTrelationSetup(); @@ -124,7 +275,7 @@ public class UMLXTests extends LoadTestCase URI pivotURI1 = getProjectFileURI("Forward2Reverse.qvtras"); URI umlxURI = getProjectFileURI("Forward2Reverse.umlx"); URI pivotURI2 = getProjectFileURI("Forward2Reverse.regenerated.qvtras"); - doRoundTripTest(inputURI1, pivotURI1, umlxURI, pivotURI2); + doRoundTripTest(inputURI1, pivotURI1, umlxURI, pivotURI2, false); } public void testUMLXRoundtrip_Keys_qvtr() throws Exception { @@ -132,7 +283,7 @@ public class UMLXTests extends LoadTestCase URI pivotURI1 = getProjectFileURI("Keys.qvtras"); URI umlxURI = getProjectFileURI("Keys.umlx"); URI pivotURI2 = getProjectFileURI("Keys.regenerated.qvtras"); - doRoundTripTest(inputURI1, pivotURI1, umlxURI, pivotURI2); + doRoundTripTest(inputURI1, pivotURI1, umlxURI, pivotURI2, false); } public void testUMLXRoundtrip_SeqToStm_qvtr() throws Exception { @@ -141,14 +292,14 @@ public class UMLXTests extends LoadTestCase URI pivotURI1 = getProjectFileURI("SeqToStm.qvtras"); URI umlxURI = getProjectFileURI("SeqToStm.umlx"); URI pivotURI2 = getProjectFileURI("SeqToStm.regenerated.qvtras"); - doRoundTripTest(inputURI1, pivotURI1, umlxURI, pivotURI2); + doRoundTripTest(inputURI1, pivotURI1, umlxURI, pivotURI2, false); } - /* public void testUMLXRoundtrip_SimplerRelToCore_qvtr() throws Exception { + public void testUMLXRoundtrip_SimplerRelToCore_qvtr() throws Exception { URI inputURI1 = URI.createPlatformResourceURI("/org.eclipse.qvtd.examples.qvtrelation.reltocore/qvtrsrc/SimplerRelToCore.qvtr", true); URI pivotURI1 = getProjectFileURI("SimplerRelToCore.qvtras"); URI umlxURI = getProjectFileURI("SimplerRelToCore.umlx"); URI pivotURI2 = getProjectFileURI("SimplerRelToCore.regenerated.qvtras"); - doRoundTripTest(inputURI1, pivotURI1, umlxURI, pivotURI2); - } */ + doRoundTripTest(inputURI1, pivotURI1, umlxURI, pivotURI2, true); // FIXME BUG 511230 + } } |