[464714] Added a new visitor to create the call graph
diff --git a/plugins/org.eclipse.qvtd.compiler/src/org/eclipse/qvtd/compiler/internal/etl/MtcBroker.java b/plugins/org.eclipse.qvtd.compiler/src/org/eclipse/qvtd/compiler/internal/etl/MtcBroker.java
index ba29eb6..40e1e1a 100644
--- a/plugins/org.eclipse.qvtd.compiler/src/org/eclipse/qvtd/compiler/internal/etl/MtcBroker.java
+++ b/plugins/org.eclipse.qvtd.compiler/src/org/eclipse/qvtd/compiler/internal/etl/MtcBroker.java
@@ -51,6 +51,7 @@
import org.eclipse.qvtd.pivot.qvtimperative.utilities.GraphMLBuilder;
import org.eclipse.qvtd.pivot.schedule.Schedule;
import org.eclipse.qvtd.pivot.schedule.SchedulePackage;
+import org.eclipse.qvtd.pivot.schedule.utilities.ScheduleToCallGraph;
import org.eclipse.qvtd.pivot.schedule.utilities.ScheduleToDependencyGraphVisitor;
// TODO: Auto-generated Javadoc
@@ -66,7 +67,7 @@
private static final String CONFIG_MODEL_NAME = "config";
/** The Constant CONFIG_MM. */
- private static final String CONFIG_MM = "platform:/resource/org.eclipse.qvtd.compiler/model/QVTcConfig.ecore";
+// private static final String CONFIG_MM = "platform:/resource/org.eclipse.qvtd.compiler/model/QVTcConfig.ecore";
/** The Constant CONFIG_URI. */
private static final String CONFIG_URI = QVTcConfigPackage.eNS_URI;
@@ -189,6 +190,8 @@
protected PivotModel oclStdLibModel;
private URI dependencyGraphUri;
+
+ private URI callGraphUri;
/** The r metamodel. */
@SuppressWarnings("unused")
@@ -230,6 +233,8 @@
/** The i model. */
protected PivotModel iModel;
+
+
/**
@@ -260,6 +265,7 @@
this.baseUri = baseURI;
this.debugUri = baseURI.appendSegment("debug");
String dgPath = this.debugUri.appendSegment(qvtcSource).trimFileExtension() + "Dependencies";
+ String cgPath = this.debugUri.appendSegment(qvtcSource).trimFileExtension() + "Calls";
System.out.println("Executing the QVTc to QVTi MTC for " + qvtcSource);
this.baseUri = baseURI;
URI qvtcURI = baseURI.appendSegment(qvtcSource);
@@ -272,6 +278,7 @@
this.configUri = URI.createURI(modelsBaseUri.toString() + "Config").appendFileExtension("xmi").toString();
this.scheduleUri = URI.createURI(modelsBaseUri.toString() + "Schedule").appendFileExtension("xmi").toString();
this.dependencyGraphUri = URI.createURI(dgPath).appendFileExtension("graphml");
+ this.callGraphUri = URI.createURI(cgPath).appendFileExtension("graphml");
candidateMetamodelContainmentTrees = new HashMap<String, List<PivotModel>>();
registerMetamodels(environmentFactory);
@@ -373,7 +380,8 @@
protected void qvtsToGraphML(PivotModel sModel) throws QvtMtcExecutionException {
- GraphBuilder builder = new GraphMLBuilder();
+ GraphBuilder depBuilder = new GraphMLBuilder();
+ GraphBuilder callBuilder = new GraphMLBuilder();
Schedule s = null;
try {
@@ -382,23 +390,38 @@
throw new QvtMtcExecutionException(e.getMessage(),e.getCause());
} finally {
if (s != null) {
- ScheduleToDependencyGraphVisitor visitor = new ScheduleToDependencyGraphVisitor(builder, this.darkTheme);
+ ScheduleToDependencyGraphVisitor depVisitor = new ScheduleToDependencyGraphVisitor(depBuilder, this.darkTheme);
+ ScheduleToCallGraph callVisitor = new ScheduleToCallGraph(callBuilder, this.darkTheme);
// GEt the source/middle/target info from the configuration
for (EObject eContent : configModel.getResource().getContents()) {
if (eContent instanceof Configuration) {
Configuration c = (Configuration) eContent;
- visitor.setInputDirection(c.getInputDirection().getName());
- visitor.setMiddleDirection("middle"); // Always middle? Should the configuration have this value?
+ depVisitor.setInputDirection(c.getInputDirection().getName());
+ depVisitor.setMiddleDirection("middle"); // Always middle? Should the configuration have this value?
for (Direction od : c.getOutputDirection()) {
- visitor.getOutputDirection().add(od.getName());
+ depVisitor.getOutputDirection().add(od.getName());
}
}
}
- s.accept(visitor);
+ s.accept(depVisitor);
// Save/print the builder
try (Writer writer = new BufferedWriter(new OutputStreamWriter(
URIConverter.INSTANCE.createOutputStream(this.dependencyGraphUri), "utf-8"))) {
- writer.write(builder.toString());
+ writer.write(depBuilder.toString());
+ } catch (UnsupportedEncodingException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ } catch (FileNotFoundException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ } catch (IOException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ s.accept(callVisitor);
+ try (Writer writer = new BufferedWriter(new OutputStreamWriter(
+ URIConverter.INSTANCE.createOutputStream(this.callGraphUri), "utf-8"))) {
+ writer.write(callBuilder.toString());
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
@@ -411,6 +434,7 @@
}
}
}
+ System.out.println("Graphs created.");
}
public void executeQvtcToQvtu() throws QvtMtcExecutionException {
diff --git a/plugins/org.eclipse.qvtd.pivot.qvtimperative/src/org/eclipse/qvtd/pivot/qvtimperative/utilities/GraphBuilder.java b/plugins/org.eclipse.qvtd.pivot.qvtimperative/src/org/eclipse/qvtd/pivot/qvtimperative/utilities/GraphBuilder.java
index 6bcb0e6..9a210f2 100644
--- a/plugins/org.eclipse.qvtd.pivot.qvtimperative/src/org/eclipse/qvtd/pivot/qvtimperative/utilities/GraphBuilder.java
+++ b/plugins/org.eclipse.qvtd.pivot.qvtimperative/src/org/eclipse/qvtd/pivot/qvtimperative/utilities/GraphBuilder.java
@@ -15,6 +15,9 @@
public interface GraphBuilder {
void appendEdge(@NonNull String sourceId, @NonNull String targetId, @NonNull String lineColor,
@NonNull String lineType, @NonNull String sourceArrowType, @NonNull String targetArrowType);
+ void appendEdge(@NonNull String sourceId, @NonNull String targetId, @NonNull String lineColor,
+ @NonNull String lineType, @NonNull String sourceArrowType, @NonNull String targetArrowType,
+ @NonNull String label);
void appendNode(@NonNull String id, @NonNull String shapeName,
@NonNull String fillColor, String label, @NonNull String labelColor);
void close();
diff --git a/plugins/org.eclipse.qvtd.pivot.qvtimperative/src/org/eclipse/qvtd/pivot/qvtimperative/utilities/GraphMLBuilder.java b/plugins/org.eclipse.qvtd.pivot.qvtimperative/src/org/eclipse/qvtd/pivot/qvtimperative/utilities/GraphMLBuilder.java
index 8a274a4..a87c1cc 100644
--- a/plugins/org.eclipse.qvtd.pivot.qvtimperative/src/org/eclipse/qvtd/pivot/qvtimperative/utilities/GraphMLBuilder.java
+++ b/plugins/org.eclipse.qvtd.pivot.qvtimperative/src/org/eclipse/qvtd/pivot/qvtimperative/utilities/GraphMLBuilder.java
@@ -200,6 +200,27 @@
s.popTag();
}
+ @Override
+ public void appendEdge(@NonNull String sourceId, @NonNull String targetId,
+ @NonNull String lineColor, @NonNull String lineType,
+ @NonNull String sourceArrowType, @NonNull String targetArrowType,
+ @NonNull String label) {
+ s.pushTag("edge");
+ s.appendElement("id", "e" + edgeCount++);
+ s.appendElement("source", "n" + sourceId);
+ s.appendElement("target", "n" + targetId);
+ s.pushTag("data");
+ s.appendElement("key", "d9");
+ s.pushTag("y:PolyLineEdge");
+ appendLineStyle(new LineStyle(lineColor, LineType.valueOf(lineType)));
+ appendArrows(sourceArrowType, targetArrowType);
+ appendEdgeLabel(label, lineColor);
+ s.popTag();
+ s.popTag();
+ s.popTag();
+ }
+
+
public void appendFill(@NonNull String fillColor) {
s.pushTag("y:Fill");
s.appendElement("color", fillColor);
@@ -217,7 +238,13 @@
s.popTag();
}
- protected void appendLabel(String label, String labelColor) {
+ protected void appendEdgeLabel(String label, String labelColor) {
+ s.pushTag("y:EdgeLabel");
+ s.appendElement("textColor", labelColor);
+ s.appendValueAndPopTag(label);
+ }
+
+ protected void appendNodeLabel(String label, String labelColor) {
s.pushTag("y:NodeLabel");
s.appendElement("textColor", labelColor);
s.appendValueAndPopTag(label);
@@ -245,7 +272,7 @@
appendGeometry(g);
appendFill(fillColor);
appendBorder(new BorderStyle(labelColor, LineType.line));
- appendLabel(label, labelColor);
+ appendNodeLabel(label, labelColor);
appendShape(shapeName);
s.popTag();
s.popTag();
@@ -305,4 +332,5 @@
}
+
}
diff --git a/plugins/org.eclipse.qvtd.pivot.schedule/src/org/eclipse/qvtd/pivot/schedule/utilities/ScheduleToCallGraph.java b/plugins/org.eclipse.qvtd.pivot.schedule/src/org/eclipse/qvtd/pivot/schedule/utilities/ScheduleToCallGraph.java
new file mode 100644
index 0000000..940313c
--- /dev/null
+++ b/plugins/org.eclipse.qvtd.pivot.schedule/src/org/eclipse/qvtd/pivot/schedule/utilities/ScheduleToCallGraph.java
@@ -0,0 +1,196 @@
+package org.eclipse.qvtd.pivot.schedule.utilities;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.ocl.pivot.NamedElement;
+import org.eclipse.qvtd.pivot.qvtimperative.utilities.GraphBuilder;
+import org.eclipse.qvtd.pivot.qvtimperative.utilities.GraphMLBuilder.ArrowType;
+import org.eclipse.qvtd.pivot.qvtimperative.utilities.GraphMLBuilder.LineType;
+import org.eclipse.qvtd.pivot.qvtimperative.utilities.GraphMLBuilder.ShapeType;
+import org.eclipse.qvtd.pivot.schedule.AbstractAction;
+import org.eclipse.qvtd.pivot.schedule.MappingAction;
+import org.eclipse.qvtd.pivot.schedule.ParameterDerivation;
+import org.eclipse.qvtd.pivot.schedule.Schedule;
+import org.eclipse.qvtd.pivot.schedule.ScheduleElement;
+import org.eclipse.qvtd.pivot.schedule.util.AbstractExtendingScheduleVisitor;
+
+public class ScheduleToCallGraph extends AbstractExtendingScheduleVisitor<String, GraphBuilder> {
+
+ private final List<String> SOL_BASE = Arrays.asList("#fdf6e3", "#eee8d5", "#93a1a1", "#839496", "#657b83", "#586e75", "#073642", "#002b36");
+ @NonNull private final int SOL_BACKROUND = 0;
+ @NonNull private final int SOL_BACKROUND_HL = 1;
+ @NonNull private final int SOL_SECONDARY = 2;
+ @NonNull private final int SOL_NONE = 3;
+ @NonNull private final int SOL_PRIMARY = 4;
+ @NonNull private final int SOL_OPTIONAL = 5;
+
+ @NonNull private final String SOL_YELLOW = "#b58900";
+ @NonNull private final String SOL_ORANGE = "#cb4b16";
+ @NonNull private final String SOL_RED = "#dc322f";
+ @NonNull private final String SOL_MAGENTA = "#d33682";
+ @NonNull private final String SOL_VIOLET = "#6c71c4";
+ @NonNull private final String SOL_BLUE = "#268bd2";
+ @NonNull private final String SOL_CYAN = "#2aa198";
+ @NonNull private final String SOL_GREEN = "#859900";
+
+ @NonNull private final String NODE_FILL_COLOR;
+
+ @NonNull private final String MAPPING_ACTION_COLOR = SOL_ORANGE;
+ @NonNull private final String MAPPING_ACTION_SHAPE = ShapeType.hexagon.name();
+ @NonNull private final String LOOP_SHAPE = ShapeType.rectangle.name();
+
+ @NonNull private final String SUPER_EDGE_COLOR;
+ @NonNull private final String PRODUCTION_EDGE_COLOR;
+ @NonNull private final String REQUISITE_EDGE_COLOR = SOL_GREEN;
+ @NonNull private final String REQUISITE_MULTIPLE_EDGE_COLOR = SOL_RED;
+ @NonNull private final String DEPENDENCY_ARROW_END = ArrowType.standard.name();
+ @NonNull private final String DEPENDENCY_LOOP_ARROW_END = ArrowType.transparent_circle.name();
+ @NonNull private final String SUPER_ARROW_END = ArrowType.delta.name();
+
+
+ private Map<MutiNamedElementKeyImpl, Integer> nodeOrder = new HashMap<MutiNamedElementKeyImpl, Integer>();
+ //private Map<CoreDomain, String> domainColor = new HashMap<CoreDomain, String>();
+ private List<String> outputDirection;
+ private boolean onlyClassDatums;
+// private int loopNodeId;
+
+ public ScheduleToCallGraph(GraphBuilder context) {
+ this(context, false);
+ }
+
+ public ScheduleToCallGraph(GraphBuilder context, boolean darkTheme) {
+ super(context);
+ if (darkTheme) {
+ Collections.reverse(SOL_BASE);
+ }
+ NODE_FILL_COLOR = SOL_BASE.get(SOL_BACKROUND_HL);
+ SUPER_EDGE_COLOR = SOL_BASE.get(SOL_SECONDARY);
+ PRODUCTION_EDGE_COLOR = SOL_BASE.get(SOL_PRIMARY);
+ }
+
+ protected @NonNull String getMappingLabel(@NonNull MappingAction object) {
+ String id = object.getMapping().getName() + "\n" + "(" + object.getOrder() + ")";
+ return id;
+ }
+
+ /**
+ * @param eo
+ * @return
+ */
+ private Integer getNodeOrder(@NonNull NamedElement... elements) {
+ MutiNamedElementKeyImpl key = new MutiNamedElementKeyImpl(elements);
+ Integer order;
+ if (nodeOrder.containsKey(key)) {
+ order = nodeOrder.get(key);
+ } else {
+ order = nodeOrder.size()+1;
+ nodeOrder.put(key, order);
+ }
+ return order;
+ }
+
+ public List<String> getOutputDirection() {
+ if (this.outputDirection == null)
+ this.outputDirection = new ArrayList<String>();
+ return this.outputDirection;
+ }
+
+// private String getPropertyId(PropertyDatum object) {
+// String id = //object.getDomain().getName() + "\n" +
+// object.getClassDatum().getType().getName() + "\n." + object.getProperty().getName();
+// return id;
+// }
+
+// private boolean nodeExists(@NonNull NamedElement... elements) {
+// MutiNamedElementKeyImpl key = new MutiNamedElementKeyImpl(elements);
+// return nodeOrder.containsKey(key);
+// }
+
+ @Override
+ @Nullable
+ public String visiting(ScheduleElement visitable) {
+ throw new IllegalArgumentException("Unsupported " + visitable.eClass().getName() + " for " + getClass().getSimpleName());
+ }
+
+ @Override
+ public @Nullable String visitMappingAction(MappingAction object) {
+
+ String mappingLabel;
+ String order;
+ if (object.getMapping() != null) {
+ mappingLabel = getMappingLabel(object);
+ order = getNodeOrder(object.getMapping()).toString();
+ }
+ else {
+ mappingLabel = "root";
+ order = "0";
+ }
+ context.appendNode(order, MAPPING_ACTION_SHAPE, NODE_FILL_COLOR, mappingLabel, MAPPING_ACTION_COLOR);
+// String lineType = LineType.line.name();
+ int childCount = 0;
+ for (AbstractAction mc : object.getChildren()) {
+ @SuppressWarnings("unused")
+ boolean allLoop = false;
+ StringBuilder loopVars = new StringBuilder();
+ String sep = "";
+ for (ParameterDerivation pd : mc.getParameterDerivations()) {
+ // Add nodes for loops
+ if (pd.getPrimaryParameter() == null) {
+ allLoop = true;
+ loopVars.append(pd.getSecondaryParameter().getDataParameter().getVariable().getName());
+ break;
+ } else {
+ //String pdOrder = String.valueOf(loopNodeId++);
+ //context.appendNode(pdOrder, LOOP_SHAPE, NODE_FILL_COLOR, mappingLabel, MAPPING_ACTION_COLOR);
+ loopVars.append(sep);
+ loopVars.append(pd.getSecondaryParameter().getDataParameter().getVariable().getName());
+ sep = ",";
+ }
+ }
+ String targetId = null;
+ targetId = getNodeOrder(((MappingAction) mc).getMapping()).toString();
+ assert targetId != null;
+ context.appendEdge(order,
+ targetId,
+ PRODUCTION_EDGE_COLOR,
+ LineType.line.name(),
+ ArrowType.none.name(),
+ DEPENDENCY_ARROW_END,
+ loopVars.toString() + "(" + String.valueOf(childCount++) + ")");
+ }
+ return null;
+ }
+
+ @Override
+ public @Nullable String visitSchedule(Schedule object) {
+
+ context.open();
+ // First the datums so the nodes exist
+// loopNodeId = object.getActions().size()+1;
+ for (AbstractAction aa : object.getActions()) {
+ if (aa instanceof MappingAction) {
+ MappingAction ma = (MappingAction) aa;
+ //if (ma.getMapping() != null)
+ visitMappingAction(ma);
+ }
+ }
+ context.close();
+ return null;
+ }
+
+ public boolean isOnlyClassDatums() {
+ return onlyClassDatums;
+ }
+
+ public void setOnlyClassDatums(boolean onlyClassDatums) {
+ this.onlyClassDatums = onlyClassDatums;
+ }
+
+}
diff --git a/tests/org.eclipse.qvtd.build.etl.tests/src/org/eclipse/qvtd/build/etl/tests/QVTdMtcTests.java b/tests/org.eclipse.qvtd.build.etl.tests/src/org/eclipse/qvtd/build/etl/tests/QVTdMtcTests.java
index b04155b..692ab4d 100644
--- a/tests/org.eclipse.qvtd.build.etl.tests/src/org/eclipse/qvtd/build/etl/tests/QVTdMtcTests.java
+++ b/tests/org.eclipse.qvtd.build.etl.tests/src/org/eclipse/qvtd/build/etl/tests/QVTdMtcTests.java
@@ -119,7 +119,7 @@
MyQVT myQVT = createQVT();
URI testBaseURI = TESTS_BASE_URI.appendSegment("UmlToRdbms");;
- URI samplesBaseUri = testBaseURI.appendSegment("samples");
+// URI samplesBaseUri = testBaseURI.appendSegment("samples");
MtcBroker mtc = new MtcBroker(testBaseURI, "UmlToRdbms.qvtcas", myQVT.getEnvironmentFactory(), TestsXMLUtil.defaultSavingOptions);
mtc.setCreateGraphml(true);
mtc.execute();