diff --git a/uk.ac.kcl.inf.gts_morpher.examples/src/pls.ecore b/uk.ac.kcl.inf.gts_morpher.examples/src/pls.ecore
index f86ade37..844e7690 100644
--- a/uk.ac.kcl.inf.gts_morpher.examples/src/pls.ecore
+++ b/uk.ac.kcl.inf.gts_morpher.examples/src/pls.ecore
@@ -22,4 +22,10 @@
+
+
+
+
diff --git a/uk.ac.kcl.inf.gts_morpher.examples/src/pls.henshin_diagram b/uk.ac.kcl.inf.gts_morpher.examples/src/pls.henshin_diagram
index 32314fee..052b9126 100644
--- a/uk.ac.kcl.inf.gts_morpher.examples/src/pls.henshin_diagram
+++ b/uk.ac.kcl.inf.gts_morpher.examples/src/pls.henshin_diagram
@@ -1,5 +1,5 @@
-
+
diff --git a/uk.ac.kcl.inf.gts_morpher.examples/src/server.ecore b/uk.ac.kcl.inf.gts_morpher.examples/src/server.ecore
index 6b4f0fa4..a7ec6067 100644
--- a/uk.ac.kcl.inf.gts_morpher.examples/src/server.ecore
+++ b/uk.ac.kcl.inf.gts_morpher.examples/src/server.ecore
@@ -26,4 +26,15 @@
+
+
+
+
+
+
+
+
+
diff --git a/uk.ac.kcl.inf.gts_morpher.examples/src/server_polish.gts b/uk.ac.kcl.inf.gts_morpher.examples/src/server_polish.gts
index a8a8d09d..29f72b2f 100644
--- a/uk.ac.kcl.inf.gts_morpher.examples/src/server_polish.gts
+++ b/uk.ac.kcl.inf.gts_morpher.examples/src/server_polish.gts
@@ -34,6 +34,7 @@ auto-complete unique map Server2PLS {
class server.Server => pls.Polisher
class server.InputQueue => pls.Tray
class server.OutputQueue => pls.Conveyor
+ reference server.ServerModel.servers => pls.PLSModel.machines
}
}
diff --git a/uk.ac.kcl.inf.gts_morpher.tests/.classpath b/uk.ac.kcl.inf.gts_morpher.tests/.classpath
index 6f6caf47..e0272a87 100644
--- a/uk.ac.kcl.inf.gts_morpher.tests/.classpath
+++ b/uk.ac.kcl.inf.gts_morpher.tests/.classpath
@@ -15,12 +15,12 @@
-
+
-
+
-
+
diff --git a/uk.ac.kcl.inf.gts_morpher.tests/src/uk/ac/kcl/inf/gts_morpher/tests/HasSize.java b/uk.ac.kcl.inf.gts_morpher.tests/src/uk/ac/kcl/inf/gts_morpher/tests/HasSize.java
new file mode 100644
index 00000000..a9e8d8a4
--- /dev/null
+++ b/uk.ac.kcl.inf.gts_morpher.tests/src/uk/ac/kcl/inf/gts_morpher/tests/HasSize.java
@@ -0,0 +1,36 @@
+package uk.ac.kcl.inf.gts_morpher.tests;
+
+import java.lang.reflect.InvocationTargetException;
+
+import org.hamcrest.Description;
+import org.hamcrest.Factory;
+import org.hamcrest.Matcher;
+import org.hamcrest.TypeSafeMatcher;
+
+/* Matches any class that has a size() method
+ * that returns an int */
+public class HasSize extends TypeSafeMatcher
+{
+ @Factory
+ public static Matcher hasSize(int val)
+ {
+ return new HasSize(val);
+ }
+
+ private int val;
+
+ private HasSize(int val) {
+ this.val = val;
+ }
+
+ @Override
+ protected boolean matchesSafely(final T item)
+ {
+ try { return ((int) item.getClass().getMethod("size", (Class>[]) null).invoke(item) == val); }
+ catch (final NoSuchMethodException e) { return false; }
+ catch (final InvocationTargetException | IllegalAccessException e) { throw new RuntimeException(e); }
+ }
+
+ @Override
+ public void describeTo(final Description description) { description.appendText("is of size " + val); }
+}
\ No newline at end of file
diff --git a/uk.ac.kcl.inf.gts_morpher.tests/src/uk/ac/kcl/inf/gts_morpher/tests/IsEmpty.java b/uk.ac.kcl.inf.gts_morpher.tests/src/uk/ac/kcl/inf/gts_morpher/tests/IsEmpty.java
new file mode 100644
index 00000000..7395facf
--- /dev/null
+++ b/uk.ac.kcl.inf.gts_morpher.tests/src/uk/ac/kcl/inf/gts_morpher/tests/IsEmpty.java
@@ -0,0 +1,30 @@
+package uk.ac.kcl.inf.gts_morpher.tests;
+
+import java.lang.reflect.InvocationTargetException;
+
+import org.hamcrest.Description;
+import org.hamcrest.Factory;
+import org.hamcrest.Matcher;
+import org.hamcrest.TypeSafeMatcher;
+
+/* Matches any class that has an isEmpty() method
+ * that returns a boolean */
+public class IsEmpty extends TypeSafeMatcher
+{
+ @Factory
+ public static Matcher empty()
+ {
+ return new IsEmpty();
+ }
+
+ @Override
+ protected boolean matchesSafely(final T item)
+ {
+ try { return (boolean) item.getClass().getMethod("isEmpty", (Class>[]) null).invoke(item); }
+ catch (final NoSuchMethodException e) { return false; }
+ catch (final InvocationTargetException | IllegalAccessException e) { throw new RuntimeException(e); }
+ }
+
+ @Override
+ public void describeTo(final Description description) { description.appendText("is empty"); }
+}
\ No newline at end of file
diff --git a/uk.ac.kcl.inf.gts_morpher.tests/src/uk/ac/kcl/inf/gts_morpher/tests/IsTraceWith.java b/uk.ac.kcl.inf.gts_morpher.tests/src/uk/ac/kcl/inf/gts_morpher/tests/IsTraceWith.java
new file mode 100644
index 00000000..b8729c6b
--- /dev/null
+++ b/uk.ac.kcl.inf.gts_morpher.tests/src/uk/ac/kcl/inf/gts_morpher/tests/IsTraceWith.java
@@ -0,0 +1,44 @@
+package uk.ac.kcl.inf.gts_morpher.tests;
+
+import org.hamcrest.Description;
+import org.hamcrest.Factory;
+import org.hamcrest.Matcher;
+import org.hamcrest.TypeSafeMatcher;
+
+import uk.ac.kcl.inf.gts_morpher.gtsMorpher.GTSTraceMember;
+import uk.ac.kcl.inf.gts_morpher.modelcaster.GTSTrace;
+
+/* Checks trace equality */
+public class IsTraceWith extends TypeSafeMatcher
+{
+ @Factory
+ public static Matcher isTraceWith(GTSTraceMember... members)
+ {
+ return new IsTraceWith(members);
+ }
+
+ private GTSTraceMember[] members;
+
+ private IsTraceWith(GTSTraceMember... members) {
+ this.members = members;
+ }
+
+ @Override
+ protected boolean matchesSafely(final GTSTrace item)
+ {
+ if (item.size() == members.length) {
+ for (int i = 0; i < item.size(); i++) {
+ if (item.get(i) != members[i]) {
+ return false;
+ }
+ }
+
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public void describeTo(final Description description) { description.appendText("is trae of " + members); }
+}
\ No newline at end of file
diff --git a/uk.ac.kcl.inf.gts_morpher.tests/src/uk/ac/kcl/inf/gts_morpher/tests/modelcaster/DEVSMM.ecore b/uk.ac.kcl.inf.gts_morpher.tests/src/uk/ac/kcl/inf/gts_morpher/tests/modelcaster/DEVSMM.ecore
new file mode 100644
index 00000000..e3faf515
--- /dev/null
+++ b/uk.ac.kcl.inf.gts_morpher.tests/src/uk/ac/kcl/inf/gts_morpher/tests/modelcaster/DEVSMM.ecore
@@ -0,0 +1,47 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/uk.ac.kcl.inf.gts_morpher.tests/src/uk/ac/kcl/inf/gts_morpher/tests/modelcaster/DEVSModel.xmi b/uk.ac.kcl.inf.gts_morpher.tests/src/uk/ac/kcl/inf/gts_morpher/tests/modelcaster/DEVSModel.xmi
new file mode 100644
index 00000000..4aebf663
--- /dev/null
+++ b/uk.ac.kcl.inf.gts_morpher.tests/src/uk/ac/kcl/inf/gts_morpher/tests/modelcaster/DEVSModel.xmi
@@ -0,0 +1,17 @@
+
+
+
+
+
+
diff --git a/uk.ac.kcl.inf.gts_morpher.tests/src/uk/ac/kcl/inf/gts_morpher/tests/modelcaster/ModelcasterTest.xtend b/uk.ac.kcl.inf.gts_morpher.tests/src/uk/ac/kcl/inf/gts_morpher/tests/modelcaster/ModelcasterTest.xtend
new file mode 100644
index 00000000..8ec69fea
--- /dev/null
+++ b/uk.ac.kcl.inf.gts_morpher.tests/src/uk/ac/kcl/inf/gts_morpher/tests/modelcaster/ModelcasterTest.xtend
@@ -0,0 +1,190 @@
+package uk.ac.kcl.inf.gts_morpher.tests.modelcaster
+
+import com.google.inject.Inject
+import org.eclipse.xtext.testing.InjectWith
+import org.eclipse.xtext.testing.XtextRunner
+import org.eclipse.xtext.testing.util.ParseHelper
+import org.junit.Test
+import org.junit.runner.RunWith
+import uk.ac.kcl.inf.gts_morpher.gtsMorpher.GTSSpecificationModule
+import uk.ac.kcl.inf.gts_morpher.tests.AbstractTest
+import uk.ac.kcl.inf.gts_morpher.tests.GTSMorpherInjectorProvider
+
+import static org.hamcrest.CoreMatchers.*
+import static org.hamcrest.MatcherAssert.*
+import static uk.ac.kcl.inf.gts_morpher.tests.HasSize.*
+import static uk.ac.kcl.inf.gts_morpher.tests.IsEmpty.*
+import static uk.ac.kcl.inf.gts_morpher.tests.IsTraceWith.*
+
+import static extension uk.ac.kcl.inf.gts_morpher.modelcaster.GTSTrace.*
+import static extension uk.ac.kcl.inf.gts_morpher.util.GTSSpecificationHelper.*
+
+@RunWith(XtextRunner)
+@InjectWith(GTSMorpherInjectorProvider)
+class ModelcasterTest extends AbstractTest {
+ @Inject
+ ParseHelper parseHelper
+
+ private def createModelResourceSet() {
+ #["storing_server.ecore",
+ "DEVSMM.ecore",
+ "DEVSModel.xmi",
+ "storing_server.henshin",
+ "devsmm.henshin",
+ "pls.ecore",
+ "pls.henshin",
+ "server.ecore",
+ "server.henshin",
+ "transformers.henshin"].createResourceSet
+ }
+
+ /**
+ * Test trace generation
+ */
+ @Test
+ def void validationBasicTrace() {
+ // TODO At some point may want to change this so it works with actual URLs rather than relying on Xtext/Ecore to pick up and search all the available ecore files
+ // Then would use «serverURI.toString» etc. below
+ val rs = createModelResourceSet
+ val result = parseHelper.parse('''
+ gts ServerSystem {
+ metamodel: "storing_server"
+ behaviour: "storing_serverRules"
+ }
+
+ gts ServerInterface interface_of { ServerSystem }
+
+ gts DEVSMMSystem {
+ metamodel: "devsmm"
+ behaviour: "devsmmRules"
+ }
+
+ map ServerToDEVSMM {
+ from ServerInterface
+ to DEVSMMSystem
+
+ type_mapping {
+ class server.Server => devsmm.Machine
+ reference server.Server.Out => devsmm.Machine.out
+ }
+
+ behaviour_mapping {
+ rule process to process {
+ object input => in_part
+ link [in_queue->input:elts] => [tray->in_part:parts]
+ }
+ }
+ }
+
+ gts DEVSMMWithServer {
+ weave: {
+ map1: interface_of (ServerSystem)
+ map2: ServerToDEVSMM
+ }
+ }
+
+ model derivedModel = "«class.getResource("DEVSModel.xmi").path»" (instance of DEVSMMSystem) as DEVSMMWithServer
+ ''', rs)
+ assertThat ("Did not produce parse result", result, is(notNullValue))
+ assertThat("Found parse errors: " + result.eResource.errors, result.eResource.errors, is(empty))
+
+ val derivedModel = result.modelCasts.head
+ val traces = derivedModel.srcGTS.findTracesTo(derivedModel.tgtGTS)
+ assertThat("Too many traces found", traces, hasSize(1))
+
+ assertThat("Trace too long", traces.head, hasSize(4))
+ assertThat("Incorrect trace", traces.head, isTraceWith(
+ result.gtss.get(2),
+ result.mappings.head,
+ result.gtss.get(3).gts,
+ result.gtss.get(3)
+ ))
+
+ val wovenGTS = result.gtss.last
+ val wovenMetamodel = wovenGTS.metamodel
+
+ val transformedModel = traces.head.transformModel(rs.getResource("DEVSModel.xmi".createFileURI, true).contents.head)
+ assertThat("No transformed model", transformedModel, is(notNullValue))
+ assertThat("Incorrect metamodel of transformed model", transformedModel.eClass.EPackage, is(sameInstance(wovenMetamodel)))
+ }
+
+ /**
+ * Test trace generation
+ */
+ @Test
+ def void validationBasicModelTransform() {
+ // TODO At some point may want to change this so it works with actual URLs rather than relying on Xtext/Ecore to pick up and search all the available ecore files
+ // Then would use «serverURI.toString» etc. below
+ val rs = createModelResourceSet
+ val result = parseHelper.parse('''
+ gts_family ServerFamily {
+ {
+ metamodel: "server"
+ behaviour: "serverRules"
+ }
+
+ transformers: "transformerRules"
+ }
+
+ export gts AdaptedServer {
+ family: ServerFamily
+
+ using [
+ addSubClass (server.Queue, "InputQueue"),
+ addSubClass (server.Queue, "OutputQueue"),
+ reTypeToSubClass (serverRules.process, server.Queue, server.InputQueue, "iq"),
+ reTypeToSubClass (serverRules.process, server.Queue, server.OutputQueue, "oq"),
+ mvAssocDown (server.Server.in, server.InputQueue),
+ mvAssocDown (server.Server.out, server.OutputQueue)
+ ]
+ }
+
+ auto-complete unique map Server2PLS {
+ from interface_of {
+ AdaptedServer
+ }
+
+ to gts pls {
+ metamodel: "pls"
+ behaviour: "plsRules"
+ }
+
+ type_mapping {
+ class server.Server => pls.Polisher
+ class server.InputQueue => pls.Tray
+ class server.OutputQueue => pls.Conveyor
+ }
+ }
+
+ export gts ServerPLS {
+ weave(dontLabelNonKernelElements,preferMap2TargetNames): {
+ map1: interface_of(AdaptedServer)
+ map2: Server2PLS
+ }
+ }
+
+ model derivedModel = "«class.getResource("DEVSModel.xmi").path»" (instance of pls) as ServerPLS
+ ''', rs)
+ assertThat ("Did not produce parse result", result, is(notNullValue))
+ assertThat("Found parse errors: " + result.eResource.errors, result.eResource.errors, is(empty))
+
+ val derivedModel = result.modelCasts.head
+ val traces = derivedModel.srcGTS.findTracesTo(derivedModel.tgtGTS)
+ assertThat("Too many traces found", traces, hasSize(1))
+
+ assertThat("Trace too long", traces.head, hasSize(4))
+ assertThat("Incorrect trace", traces.head, isTraceWith(
+ result.gtss.get(2),
+ result.mappings.head,
+ result.gtss.get(3).gts,
+ result.gtss.get(3)
+ ))
+
+ val wovenGTS = result.gtss.last
+ val wovenMetamodel = wovenGTS.metamodel
+
+ val transformedModel = traces.head.transformModel(rs.getResource("DEVSModel.xmi".createFileURI, true).contents.head)
+ assertThat("No transformed model", transformedModel, is(notNullValue))
+ assertThat("Incorrect metamodel of transformed model", transformedModel.eClass.EPackage, is(sameInstance(wovenMetamodel)))
+ }
+}
diff --git a/uk.ac.kcl.inf.gts_morpher.tests/src/uk/ac/kcl/inf/gts_morpher/tests/modelcaster/devsmm.henshin b/uk.ac.kcl.inf.gts_morpher.tests/src/uk/ac/kcl/inf/gts_morpher/tests/modelcaster/devsmm.henshin
new file mode 100644
index 00000000..bc420ed2
--- /dev/null
+++ b/uk.ac.kcl.inf.gts_morpher.tests/src/uk/ac/kcl/inf/gts_morpher/tests/modelcaster/devsmm.henshin
@@ -0,0 +1,87 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/uk.ac.kcl.inf.gts_morpher.tests/src/uk/ac/kcl/inf/gts_morpher/tests/modelcaster/devsmm.henshin_diagram b/uk.ac.kcl.inf.gts_morpher.tests/src/uk/ac/kcl/inf/gts_morpher/tests/modelcaster/devsmm.henshin_diagram
new file mode 100644
index 00000000..0305e778
--- /dev/null
+++ b/uk.ac.kcl.inf.gts_morpher.tests/src/uk/ac/kcl/inf/gts_morpher/tests/modelcaster/devsmm.henshin_diagram
@@ -0,0 +1,175 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/uk.ac.kcl.inf.gts_morpher.tests/src/uk/ac/kcl/inf/gts_morpher/tests/modelcaster/pls.ecore b/uk.ac.kcl.inf.gts_morpher.tests/src/uk/ac/kcl/inf/gts_morpher/tests/modelcaster/pls.ecore
new file mode 100644
index 00000000..b8003066
--- /dev/null
+++ b/uk.ac.kcl.inf.gts_morpher.tests/src/uk/ac/kcl/inf/gts_morpher/tests/modelcaster/pls.ecore
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/uk.ac.kcl.inf.gts_morpher.tests/src/uk/ac/kcl/inf/gts_morpher/tests/modelcaster/pls.emf b/uk.ac.kcl.inf.gts_morpher.tests/src/uk/ac/kcl/inf/gts_morpher/tests/modelcaster/pls.emf
new file mode 100644
index 00000000..ef306c91
--- /dev/null
+++ b/uk.ac.kcl.inf.gts_morpher.tests/src/uk/ac/kcl/inf/gts_morpher/tests/modelcaster/pls.emf
@@ -0,0 +1,55 @@
+@namespace(uri="http://pls/1.0", prefix="pls")
+package pls;
+
+class Machine {
+ ref Conveyor out;
+ ref Tray in;
+}
+
+class Conveyor extends Container {
+ ref Tray out;
+}
+
+class Tray extends Container {
+
+}
+
+class Container {
+ ref Part[*] parts;
+}
+
+class Polisher extends Machine {
+
+}
+
+class Assemble extends Machine {
+
+}
+
+class Generator extends Machine {
+
+}
+
+class GenHead extends Generator {
+
+}
+
+class GenHandle extends Generator {
+
+}
+
+class Part {
+
+}
+
+class Hammer extends Part {
+
+}
+
+class Head extends Part {
+
+}
+
+class Handle extends Part {
+
+}
\ No newline at end of file
diff --git a/uk.ac.kcl.inf.gts_morpher.tests/src/uk/ac/kcl/inf/gts_morpher/tests/modelcaster/pls.henshin b/uk.ac.kcl.inf.gts_morpher.tests/src/uk/ac/kcl/inf/gts_morpher/tests/modelcaster/pls.henshin
new file mode 100644
index 00000000..e8a469b8
--- /dev/null
+++ b/uk.ac.kcl.inf.gts_morpher.tests/src/uk/ac/kcl/inf/gts_morpher/tests/modelcaster/pls.henshin
@@ -0,0 +1,55 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/uk.ac.kcl.inf.gts_morpher.tests/src/uk/ac/kcl/inf/gts_morpher/tests/modelcaster/pls.henshin_diagram b/uk.ac.kcl.inf.gts_morpher.tests/src/uk/ac/kcl/inf/gts_morpher/tests/modelcaster/pls.henshin_diagram
new file mode 100644
index 00000000..2251c0f8
--- /dev/null
+++ b/uk.ac.kcl.inf.gts_morpher.tests/src/uk/ac/kcl/inf/gts_morpher/tests/modelcaster/pls.henshin_diagram
@@ -0,0 +1,113 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/uk.ac.kcl.inf.gts_morpher.tests/src/uk/ac/kcl/inf/gts_morpher/tests/modelcaster/server.ecore b/uk.ac.kcl.inf.gts_morpher.tests/src/uk/ac/kcl/inf/gts_morpher/tests/modelcaster/server.ecore
new file mode 100644
index 00000000..99bcef8d
--- /dev/null
+++ b/uk.ac.kcl.inf.gts_morpher.tests/src/uk/ac/kcl/inf/gts_morpher/tests/modelcaster/server.ecore
@@ -0,0 +1,29 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/uk.ac.kcl.inf.gts_morpher.tests/src/uk/ac/kcl/inf/gts_morpher/tests/modelcaster/server.emf b/uk.ac.kcl.inf.gts_morpher.tests/src/uk/ac/kcl/inf/gts_morpher/tests/modelcaster/server.emf
new file mode 100644
index 00000000..0364b9fa
--- /dev/null
+++ b/uk.ac.kcl.inf.gts_morpher.tests/src/uk/ac/kcl/inf/gts_morpher/tests/modelcaster/server.emf
@@ -0,0 +1,32 @@
+@namespace(uri="http://server/1.0", prefix="server")
+package server;
+
+@Interface
+class Server {
+ @Interface
+ ref Queue in;
+ @Interface
+ ref Queue out;
+ ref Output made;
+}
+
+@Interface
+class Queue {
+ @Interface
+ ref Element[*] elts;
+}
+
+@Interface
+abstract class Element {
+
+}
+
+@Interface
+class Input extends Element {
+
+}
+
+@Interface
+class Output extends Element {
+
+}
\ No newline at end of file
diff --git a/uk.ac.kcl.inf.gts_morpher.tests/src/uk/ac/kcl/inf/gts_morpher/tests/modelcaster/server.henshin b/uk.ac.kcl.inf.gts_morpher.tests/src/uk/ac/kcl/inf/gts_morpher/tests/modelcaster/server.henshin
new file mode 100644
index 00000000..04e50369
--- /dev/null
+++ b/uk.ac.kcl.inf.gts_morpher.tests/src/uk/ac/kcl/inf/gts_morpher/tests/modelcaster/server.henshin
@@ -0,0 +1,58 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/uk.ac.kcl.inf.gts_morpher.tests/src/uk/ac/kcl/inf/gts_morpher/tests/modelcaster/server.henshin_diagram b/uk.ac.kcl.inf.gts_morpher.tests/src/uk/ac/kcl/inf/gts_morpher/tests/modelcaster/server.henshin_diagram
new file mode 100644
index 00000000..8649607c
--- /dev/null
+++ b/uk.ac.kcl.inf.gts_morpher.tests/src/uk/ac/kcl/inf/gts_morpher/tests/modelcaster/server.henshin_diagram
@@ -0,0 +1,123 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/uk.ac.kcl.inf.gts_morpher.tests/src/uk/ac/kcl/inf/gts_morpher/tests/modelcaster/server_polish.gts b/uk.ac.kcl.inf.gts_morpher.tests/src/uk/ac/kcl/inf/gts_morpher/tests/modelcaster/server_polish.gts
new file mode 100644
index 00000000..47b89c3c
--- /dev/null
+++ b/uk.ac.kcl.inf.gts_morpher.tests/src/uk/ac/kcl/inf/gts_morpher/tests/modelcaster/server_polish.gts
@@ -0,0 +1,46 @@
+gts_family ServerFamily {
+ {
+ metamodel: "server"
+ behaviour: "serverRules"
+ }
+
+ transformers: "transformerRules"
+}
+
+export gts AdaptedServer {
+ family: ServerFamily
+
+ using [
+ addSubClass (server.Queue, "InputQueue"),
+ addSubClass (server.Queue, "OutputQueue"),
+ reTypeToSubClass (serverRules.process, server.Queue, server.InputQueue, "iq"),
+ reTypeToSubClass (serverRules.process, server.Queue, server.OutputQueue, "oq"),
+ mvAssocDown (server.Server.in, server.InputQueue),
+ mvAssocDown (server.Server.out, server.OutputQueue)
+ ]
+}
+
+auto-complete unique map Server2PLS {
+ from interface_of {
+ AdaptedServer
+ }
+
+ to {
+ metamodel: "pls"
+ behaviour: "plsRules"
+ }
+
+ type_mapping {
+ class server.Server => pls.Polisher
+ class server.InputQueue => pls.Tray
+ class server.OutputQueue => pls.Conveyor
+ }
+}
+
+export gts ServerPLS {
+ weave(dontLabelNonKernelElements,preferMap2TargetNames): {
+ map1: interface_of(AdaptedServer)
+ map2: Server2PLS
+ }
+}
+
diff --git a/uk.ac.kcl.inf.gts_morpher.tests/src/uk/ac/kcl/inf/gts_morpher/tests/modelcaster/storing_server.ecore b/uk.ac.kcl.inf.gts_morpher.tests/src/uk/ac/kcl/inf/gts_morpher/tests/modelcaster/storing_server.ecore
new file mode 100644
index 00000000..ec3bb874
--- /dev/null
+++ b/uk.ac.kcl.inf.gts_morpher.tests/src/uk/ac/kcl/inf/gts_morpher/tests/modelcaster/storing_server.ecore
@@ -0,0 +1,38 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/uk.ac.kcl.inf.gts_morpher.tests/src/uk/ac/kcl/inf/gts_morpher/tests/modelcaster/storing_server.emf b/uk.ac.kcl.inf.gts_morpher.tests/src/uk/ac/kcl/inf/gts_morpher/tests/modelcaster/storing_server.emf
new file mode 100644
index 00000000..4324c58f
--- /dev/null
+++ b/uk.ac.kcl.inf.gts_morpher.tests/src/uk/ac/kcl/inf/gts_morpher/tests/modelcaster/storing_server.emf
@@ -0,0 +1,37 @@
+@namespace(uri="http://storing_server/1.0", prefix="storing_server")
+package storing_server;
+
+@Interface
+class Server {
+ @Interface
+ ref Queue[*] Out;
+ @Interface
+ ref Queue[*] In;
+}
+
+@Interface
+class Queue {
+ @Interface
+ ref Element[*] elts;
+ @Interface
+ attr EInt count1;
+ attr EInt count2;
+}
+
+@Interface
+class Element {
+}
+
+@Interface
+class Input extends Element {
+}
+
+@Interface
+class Output extends Element {
+}
+
+class ServerObserver {
+ ref Server[1] server;
+ ref Element[*] produced;
+}
+
diff --git a/uk.ac.kcl.inf.gts_morpher.tests/src/uk/ac/kcl/inf/gts_morpher/tests/modelcaster/storing_server.henshin b/uk.ac.kcl.inf.gts_morpher.tests/src/uk/ac/kcl/inf/gts_morpher/tests/modelcaster/storing_server.henshin
new file mode 100644
index 00000000..85f9a3f5
--- /dev/null
+++ b/uk.ac.kcl.inf.gts_morpher.tests/src/uk/ac/kcl/inf/gts_morpher/tests/modelcaster/storing_server.henshin
@@ -0,0 +1,185 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/uk.ac.kcl.inf.gts_morpher.tests/src/uk/ac/kcl/inf/gts_morpher/tests/modelcaster/storing_server.henshin_diagram b/uk.ac.kcl.inf.gts_morpher.tests/src/uk/ac/kcl/inf/gts_morpher/tests/modelcaster/storing_server.henshin_diagram
new file mode 100644
index 00000000..836f8a21
--- /dev/null
+++ b/uk.ac.kcl.inf.gts_morpher.tests/src/uk/ac/kcl/inf/gts_morpher/tests/modelcaster/storing_server.henshin_diagram
@@ -0,0 +1,352 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/uk.ac.kcl.inf.gts_morpher.tests/src/uk/ac/kcl/inf/gts_morpher/tests/modelcaster/transformers.henshin b/uk.ac.kcl.inf.gts_morpher.tests/src/uk/ac/kcl/inf/gts_morpher/tests/modelcaster/transformers.henshin
new file mode 100644
index 00000000..d605542a
--- /dev/null
+++ b/uk.ac.kcl.inf.gts_morpher.tests/src/uk/ac/kcl/inf/gts_morpher/tests/modelcaster/transformers.henshin
@@ -0,0 +1,493 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/uk.ac.kcl.inf.gts_morpher.tests/src/uk/ac/kcl/inf/gts_morpher/tests/modelcaster/transformers.henshin_diagram b/uk.ac.kcl.inf.gts_morpher.tests/src/uk/ac/kcl/inf/gts_morpher/tests/modelcaster/transformers.henshin_diagram
new file mode 100644
index 00000000..1774e931
--- /dev/null
+++ b/uk.ac.kcl.inf.gts_morpher.tests/src/uk/ac/kcl/inf/gts_morpher/tests/modelcaster/transformers.henshin_diagram
@@ -0,0 +1,474 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/uk.ac.kcl.inf.gts_morpher.tests/src/uk/ac/kcl/inf/gts_morpher/tests/syntax/DEVSMM.ecore b/uk.ac.kcl.inf.gts_morpher.tests/src/uk/ac/kcl/inf/gts_morpher/tests/syntax/DEVSMM.ecore
index 48f61001..e3faf515 100644
--- a/uk.ac.kcl.inf.gts_morpher.tests/src/uk/ac/kcl/inf/gts_morpher/tests/syntax/DEVSMM.ecore
+++ b/uk.ac.kcl.inf.gts_morpher.tests/src/uk/ac/kcl/inf/gts_morpher/tests/syntax/DEVSMM.ecore
@@ -37,4 +37,11 @@
+
+
+
+
+
diff --git a/uk.ac.kcl.inf.gts_morpher.tests/src/uk/ac/kcl/inf/gts_morpher/tests/syntax/DEVSModel.xmi b/uk.ac.kcl.inf.gts_morpher.tests/src/uk/ac/kcl/inf/gts_morpher/tests/syntax/DEVSModel.xmi
new file mode 100644
index 00000000..4aebf663
--- /dev/null
+++ b/uk.ac.kcl.inf.gts_morpher.tests/src/uk/ac/kcl/inf/gts_morpher/tests/syntax/DEVSModel.xmi
@@ -0,0 +1,17 @@
+
+
+
+
+
+
diff --git a/uk.ac.kcl.inf.gts_morpher.tests/src/uk/ac/kcl/inf/gts_morpher/tests/syntax/ParsingAndValidationTests.xtend b/uk.ac.kcl.inf.gts_morpher.tests/src/uk/ac/kcl/inf/gts_morpher/tests/syntax/ParsingAndValidationTests.xtend
index 44cd8252..6e766de8 100644
--- a/uk.ac.kcl.inf.gts_morpher.tests/src/uk/ac/kcl/inf/gts_morpher/tests/syntax/ParsingAndValidationTests.xtend
+++ b/uk.ac.kcl.inf.gts_morpher.tests/src/uk/ac/kcl/inf/gts_morpher/tests/syntax/ParsingAndValidationTests.xtend
@@ -75,6 +75,11 @@ class ParsingAndValidationTests extends AbstractTest {
private def createInterfaceResourceSet() {
#["storing_server.ecore", "DEVSMM.ecore", "storing_server.henshin", "devsmm.henshin"].createResourceSet
}
+
+ private def createModelResourceSet() {
+ #["storing_server.ecore", "DEVSMM.ecore", "DEVSModel.xmi", "storing_server.henshin", "devsmm.henshin"].createResourceSet
+ }
+
/**
* Tests basic parsing and linking for a sunshine case
@@ -3102,4 +3107,218 @@ class ParsingAndValidationTests extends AbstractTest {
result.assertError(GtsMorpherPackage.Literals.STRING_PARAMETER,
GTSMorpherValidator.INVALID_UNIT_CALL_PARAMETER_TYPE)
}
+
+ /**
+ * Tests basic parsing of model casting
+ */
+ @Test
+ def void parsingBasicModelCasting() {
+ // TODO At some point may want to change this so it works with actual URLs rather than relying on Xtext/Ecore to pick up and search all the available ecore files
+ // Then would use «serverURI.toString» etc. below
+ val result = parseHelper.parse('''
+ gts ServerSystem {
+ metamodel: "server"
+ behaviour: "serverRules"
+ }
+
+ gts ServerInterface interface_of { ServerSystem }
+
+ gts DEVSMMSystem {
+ metamodel: "devsmm"
+ behaviour: "devsmmRules"
+ }
+
+ map ServerToDEVSMM {
+ from ServerInterface
+ to DEVSMMSystem
+
+ type_mapping {
+ class server.Server => devsmm.Machine
+ reference server.Server.Out => devsmm.Machine.out
+ }
+
+ behaviour_mapping {
+ rule process to process {
+ object input => in_part
+ link [in_queue->input:elts] => [tray->in_part:parts]
+ }
+ }
+ }
+
+ gts DEVSMMWithServer {
+ weave: {
+ map1: interface_of (ServerSystem)
+ map2: ServerToDEVSMM
+ }
+ }
+
+ model derivedModel = "DEVSModel.xmi" (instance of DEVSMMSystem) as DEVSMMWithServer
+ ''', createModelResourceSet)
+ assertNotNull("Did not produce parse result", result)
+ assertTrue("Found parse errors: " + result.eResource.errors, result.eResource.errors.isEmpty)
+
+ assertNotNull("Did not resolve src GTS of model cast", result.modelCasts.head.srcGTS)
+ assertNotNull("Did not resolve tgt GTS of model cast", result.modelCasts.head.tgtGTS)
+
+ assertTrue("Found linking errors: " + result.eResource.errors, result.eResource.errors.isEmpty)
+
+ result.assertNoError(GTSMorpherValidator.WEAVE_WITH_DIFFERENT_SOURCES)
+ }
+
+ /**
+ * Tests validation of model casting
+ */
+ @Test
+ def void validationBasicModelCasting() {
+ // TODO At some point may want to change this so it works with actual URLs rather than relying on Xtext/Ecore to pick up and search all the available ecore files
+ // Then would use «serverURI.toString» etc. below
+ val result = parseHelper.parse('''
+ gts ServerSystem {
+ metamodel: "server"
+ behaviour: "serverRules"
+ }
+
+ gts ServerInterface interface_of { ServerSystem }
+
+ gts DEVSMMSystem {
+ metamodel: "devsmm"
+ behaviour: "devsmmRules"
+ }
+
+ map ServerToDEVSMM {
+ from ServerInterface
+ to DEVSMMSystem
+
+ type_mapping {
+ class server.Server => devsmm.Machine
+ reference server.Server.Out => devsmm.Machine.out
+ }
+
+ behaviour_mapping {
+ rule process to process {
+ object input => in_part
+ link [in_queue->input:elts] => [tray->in_part:parts]
+ }
+ }
+ }
+
+ gts DEVSMMWithServer {
+ weave: {
+ map1: interface_of (ServerSystem)
+ map2: ServerToDEVSMM
+ }
+ }
+
+ model derivedModel = "«class.getResource("DEVSModel.xmi").path»" (instance of DEVSMMSystem) as DEVSMMWithServer
+ ''', createModelResourceSet)
+ assertNotNull("Did not produce parse result", result)
+ assertTrue("Found parse errors: " + result.eResource.errors, result.eResource.errors.isEmpty)
+
+ result.assertNoError(GTSMorpherValidator.MODEL_CAST_INVALID_SOURCE_TYPE)
+ result.assertNoError(GTSMorpherValidator.MODEL_CAST_INVALID_TARGET_TYPE)
+ }
+
+ /**
+ * Tests validation of model casting
+ */
+ @Test
+ def void validationBasicModelCastingWithSourceError() {
+ // TODO At some point may want to change this so it works with actual URLs rather than relying on Xtext/Ecore to pick up and search all the available ecore files
+ // Then would use «serverURI.toString» etc. below
+ val result = parseHelper.parse('''
+ gts ServerSystem {
+ metamodel: "server"
+ behaviour: "serverRules"
+ }
+
+ gts ServerInterface interface_of { ServerSystem }
+
+ gts DEVSMMSystem {
+ metamodel: "devsmm"
+ behaviour: "devsmmRules"
+ }
+
+ map ServerToDEVSMM {
+ from ServerInterface
+ to DEVSMMSystem
+
+ type_mapping {
+ class server.Server => devsmm.Machine
+ reference server.Server.Out => devsmm.Machine.out
+ }
+
+ behaviour_mapping {
+ rule process to process {
+ object input => in_part
+ link [in_queue->input:elts] => [tray->in_part:parts]
+ }
+ }
+ }
+
+ gts DEVSMMWithServer {
+ weave: {
+ map1: interface_of (ServerSystem)
+ map2: ServerToDEVSMM
+ }
+ }
+
+ model derivedModel = "«class.getResource("DEVSModel.xmi").path»" (instance of ServerSystem) as DEVSMMWithServer
+ ''', createModelResourceSet)
+ assertNotNull("Did not produce parse result", result)
+ assertTrue("Found parse errors: " + result.eResource.errors, result.eResource.errors.isEmpty)
+
+ result.eContents.head.assertError(GtsMorpherPackage.Literals.MODEL_CAST, GTSMorpherValidator.MODEL_CAST_INVALID_SOURCE_TYPE)
+ }
+
+ /**
+ * Tests validation of model casting
+ */
+ @Test
+ def void validationBasicModelCastingTargetTypeError() {
+ // TODO At some point may want to change this so it works with actual URLs rather than relying on Xtext/Ecore to pick up and search all the available ecore files
+ // Then would use «serverURI.toString» etc. below
+ val result = parseHelper.parse('''
+ gts ServerSystem {
+ metamodel: "server"
+ behaviour: "serverRules"
+ }
+
+ gts ServerInterface interface_of { ServerSystem }
+
+ gts DEVSMMSystem {
+ metamodel: "devsmm"
+ behaviour: "devsmmRules"
+ }
+
+ map ServerToDEVSMM {
+ from ServerInterface
+ to DEVSMMSystem
+
+ type_mapping {
+ class server.Server => devsmm.Machine
+ reference server.Server.Out => devsmm.Machine.out
+ }
+
+ behaviour_mapping {
+ rule process to process {
+ object input => in_part
+ link [in_queue->input:elts] => [tray->in_part:parts]
+ }
+ }
+ }
+
+ gts DEVSMMWithServer {
+ weave: {
+ map1: interface_of (ServerSystem)
+ map2: ServerToDEVSMM
+ }
+ }
+
+ model derivedModel = "«class.getResource("DEVSModel.xmi").path»" (instance of DEVSMMSystem) as ServerSystem
+ ''', createModelResourceSet)
+ assertNotNull("Did not produce parse result", result)
+ assertTrue("Found parse errors: " + result.eResource.errors, result.eResource.errors.isEmpty)
+
+ result.eContents.head.assertError(GtsMorpherPackage.Literals.MODEL_CAST, GTSMorpherValidator.MODEL_CAST_INVALID_TARGET_TYPE)
+ }
}
diff --git a/uk.ac.kcl.inf.gts_morpher.ui/plugin.xml_gen b/uk.ac.kcl.inf.gts_morpher.ui/plugin.xml_gen
index 671395dc..180998f9 100644
--- a/uk.ac.kcl.inf.gts_morpher.ui/plugin.xml_gen
+++ b/uk.ac.kcl.inf.gts_morpher.ui/plugin.xml_gen
@@ -26,11 +26,11 @@
-
-
+
-
-
+
+
-
-
-
-
+
+
-
-
+
-
+
-
-
-
-
-
-
+
+
+
+
+
+
@@ -309,7 +309,7 @@
-
@@ -369,7 +369,7 @@
-
diff --git a/uk.ac.kcl.inf.gts_morpher/.launch/Launch Runtime Eclipse.launch b/uk.ac.kcl.inf.gts_morpher/.launch/Launch Runtime Eclipse.launch
index aa1d84ac..cf949c80 100644
--- a/uk.ac.kcl.inf.gts_morpher/.launch/Launch Runtime Eclipse.launch
+++ b/uk.ac.kcl.inf.gts_morpher/.launch/Launch Runtime Eclipse.launch
@@ -1,35 +1,36 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/uk.ac.kcl.inf.gts_morpher/META-INF/MANIFEST.MF b/uk.ac.kcl.inf.gts_morpher/META-INF/MANIFEST.MF
index 6bc07339..af6941cd 100644
--- a/uk.ac.kcl.inf.gts_morpher/META-INF/MANIFEST.MF
+++ b/uk.ac.kcl.inf.gts_morpher/META-INF/MANIFEST.MF
@@ -34,5 +34,6 @@ Export-Package: uk.ac.kcl.inf.gts_morpher,
uk.ac.kcl.inf.gts_morpher.serializer,
uk.ac.kcl.inf.gts_morpher.services,
uk.ac.kcl.inf.gts_morpher.util,
- uk.ac.kcl.inf.gts_morpher.validation
+ uk.ac.kcl.inf.gts_morpher.validation,
+ uk.ac.kcl.inf.gts_morpher.modelcaster
Import-Package: org.apache.log4j
diff --git a/uk.ac.kcl.inf.gts_morpher/model/generated/GTSMorpher.ecore b/uk.ac.kcl.inf.gts_morpher/model/generated/GTSMorpher.ecore
index 28380713..d73eaf75 100644
--- a/uk.ac.kcl.inf.gts_morpher/model/generated/GTSMorpher.ecore
+++ b/uk.ac.kcl.inf.gts_morpher/model/generated/GTSMorpher.ecore
@@ -8,7 +8,7 @@
-
+
@@ -33,13 +33,13 @@
-
+
-
+
@@ -72,9 +72,10 @@
-
+
+
@@ -145,4 +146,9 @@
+
+
+
+
+
diff --git a/uk.ac.kcl.inf.gts_morpher/model/generated/GTSMorpher.genmodel b/uk.ac.kcl.inf.gts_morpher/model/generated/GTSMorpher.genmodel
index e1ded47c..a81508b8 100644
--- a/uk.ac.kcl.inf.gts_morpher/model/generated/GTSMorpher.genmodel
+++ b/uk.ac.kcl.inf.gts_morpher/model/generated/GTSMorpher.genmodel
@@ -1,9 +1,9 @@
+ complianceLevel="8.0" copyrightFields="false" runtimeVersion="2.20" usedGenPackages="platform:/resource/org.eclipse.emf.henshin.model/model/henshin.genmodel#//henshin">
@@ -68,6 +68,7 @@
+
@@ -132,5 +133,10 @@
+
+
+
+
+
diff --git a/uk.ac.kcl.inf.gts_morpher/plugin.xml_gen b/uk.ac.kcl.inf.gts_morpher/plugin.xml_gen
new file mode 100644
index 00000000..d1e6f042
--- /dev/null
+++ b/uk.ac.kcl.inf.gts_morpher/plugin.xml_gen
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
diff --git a/uk.ac.kcl.inf.gts_morpher/src/uk/ac/kcl/inf/gts_morpher/GTSMorpher.xtext b/uk.ac.kcl.inf.gts_morpher/src/uk/ac/kcl/inf/gts_morpher/GTSMorpher.xtext
index b85ff522..746f59ba 100644
--- a/uk.ac.kcl.inf.gts_morpher/src/uk/ac/kcl/inf/gts_morpher/GTSMorpher.xtext
+++ b/uk.ac.kcl.inf.gts_morpher/src/uk/ac/kcl/inf/gts_morpher/GTSMorpher.xtext
@@ -12,7 +12,8 @@ GTSSpecificationModule:
GTSSpecificationModuleMember:
GTSSpecification |
GTSFamilySpecification |
- GTSMapping
+ GTSMapping |
+ ModelCast
;
GTSMapping:
@@ -110,6 +111,14 @@ GTSMappingInterfaceSpec:
"interface_of" "(" gts_ref=[GTSSpecification] ")"
;
+// Helper not used in grammar, but constructing a meta-model interface so we can access all of these in a GTS trace
+GTSTraceMember:
+ GTSSpecification |
+ GTSMapping |
+ GTSSelection |
+ GTSMappingInterfaceSpec
+;
+
UnitCallList:
steps += UnitCall ("," steps += UnitCall)*
;
@@ -197,6 +206,10 @@ RuleParameterMapping:
"param" source = [gts::Parameter | ID] "=>" target = [gts::Parameter | ID]
;
+ModelCast:
+ "model" name=ID "=" modelFile=STRING ("(" "instance" "of" srcGTS = [GTSSpecification] ")")? "as" tgtGTS = [GTSSpecification]
+;
+
LinkName :
"[" ID "->" ID ":" ID "]"
;
diff --git a/uk.ac.kcl.inf.gts_morpher/src/uk/ac/kcl/inf/gts_morpher/modelcaster/GTSTrace.xtend b/uk.ac.kcl.inf.gts_morpher/src/uk/ac/kcl/inf/gts_morpher/modelcaster/GTSTrace.xtend
new file mode 100644
index 00000000..9276aacb
--- /dev/null
+++ b/uk.ac.kcl.inf.gts_morpher/src/uk/ac/kcl/inf/gts_morpher/modelcaster/GTSTrace.xtend
@@ -0,0 +1,162 @@
+package uk.ac.kcl.inf.gts_morpher.modelcaster
+
+import java.util.ArrayList
+import java.util.HashMap
+import java.util.HashSet
+import java.util.Set
+import org.eclipse.emf.ecore.EObject
+import org.eclipse.xtext.util.OnChangeEvictingCache
+import uk.ac.kcl.inf.gts_morpher.gtsMorpher.GTSFamilyChoice
+import uk.ac.kcl.inf.gts_morpher.gtsMorpher.GTSFamilyReference
+import uk.ac.kcl.inf.gts_morpher.gtsMorpher.GTSFamilySpecification
+import uk.ac.kcl.inf.gts_morpher.gtsMorpher.GTSFamilySpecificationOrReference
+import uk.ac.kcl.inf.gts_morpher.gtsMorpher.GTSLiteral
+import uk.ac.kcl.inf.gts_morpher.gtsMorpher.GTSMapping
+import uk.ac.kcl.inf.gts_morpher.gtsMorpher.GTSMappingInterfaceSpec
+import uk.ac.kcl.inf.gts_morpher.gtsMorpher.GTSMappingRef
+import uk.ac.kcl.inf.gts_morpher.gtsMorpher.GTSMappingRefOrInterfaceSpec
+import uk.ac.kcl.inf.gts_morpher.gtsMorpher.GTSReference
+import uk.ac.kcl.inf.gts_morpher.gtsMorpher.GTSSpecification
+import uk.ac.kcl.inf.gts_morpher.gtsMorpher.GTSSpecificationOrReference
+import uk.ac.kcl.inf.gts_morpher.gtsMorpher.GTSTraceMember
+import uk.ac.kcl.inf.gts_morpher.gtsMorpher.GTSWeave
+
+/**
+ * A GTS trace is a path that connects a source and a target GTS through a number of transformations in a GTSMorpher specification.
+ * For example, the source GTS might be the root of a family specification, from which a member gets picked, that is then mapped
+ * and woven to construct the target GTS.
+ *
+ * The source GTS is always the first member of the GTSTrace and the target GTS is always the last member of the GTSTrace.
+ */
+class GTSTrace extends ArrayList {
+
+ static val traceCache = new OnChangeEvictingCache
+
+ /**
+ * Constructs the set of traces through which source can be transformed into target.
+ */
+ static def Set findTracesTo(GTSSpecification source, GTSSpecification target) {
+ val key = source -> target
+
+ traceCache.get(key, source.eResource) [
+ traceCache.get(key, target.eResource) [
+ new GTSTraceHelper().findTraces(source, target)
+ ]
+ ]
+ }
+
+ private new(GTSTraceMember... trace) {
+ super()
+ this += trace
+ }
+
+ def getSource() { head as GTSSpecification }
+
+ def getTarget() { last as GTSSpecification }
+
+ def EObject transformModel(EObject srcModel) {
+ new GTSTraceEvaluator(srcModel, this).get(srcModel)
+ }
+
+ /*
+ * FIXME: This is wrong: I really need something that will collapse a trace into a mapping from source meta-model elements into target
+ * meta-model elements and then I use this to transform source models
+ */
+ private static class GTSTraceEvaluator extends HashMap {
+ var EObject srcModel
+ var GTSTrace trace
+
+ new(EObject srcModel, GTSTrace trace) {
+ this.srcModel = srcModel
+ this.trace = trace
+
+ doTransform
+ }
+
+ private def doTransform() {
+ trace.drop(1) // Forget the source GTS
+ .forEach[doOneTransform]
+ }
+
+// private dispatch def doOneTransform (GTSTraceMember step) { }
+ private dispatch def doOneTransform (GTSMapping step) { }
+ private dispatch def doOneTransform (GTSSpecification step) { }
+ private dispatch def doOneTransform (GTSLiteral step) { }
+ private dispatch def doOneTransform (GTSFamilyChoice step) { }
+ private dispatch def doOneTransform (GTSReference step) { }
+ private dispatch def doOneTransform (GTSWeave step) { }
+ }
+
+ private static class GTSTraceHelper extends HashMap> {
+ def Set findTraces(GTSSpecification source, GTSSpecification target) {
+ val Set visited = new HashSet
+
+ collectTraces(source, target, visited)
+ }
+
+ private def Set collectTraces(GTSSpecification source, GTSTraceMember target,
+ Set visited) {
+ if (visited.contains(target)) {
+ if (get(target) !== null) {
+ return get(target)
+ } else {
+ return emptySet
+ }
+ }
+
+ visited += target
+
+ val traces = if (source === target) {
+ #{new GTSTrace(source)}
+ } else {
+ expandAll(target.stepDown.flatMap[source.collectTraces(it, visited)].toSet, target)
+ }
+
+ put(target, traces)
+
+ traces
+ }
+
+ private def expandAll(Set traces, GTSTraceMember newTarget) {
+ traces.map[new GTSTrace(it + #{newTarget})].toSet
+ }
+
+ private dispatch def Iterable stepDown(GTSTraceMember node) { #[] }
+
+ private dispatch def Iterable stepDown(GTSSpecification node) { #[node.gts] }
+
+ private dispatch def Iterable stepDown(GTSMapping node) {
+ #[node.source.resolve, node.target.resolve]
+ }
+
+ private dispatch def Iterable stepDown(GTSLiteral node) { #[] }
+
+ private dispatch def Iterable stepDown(GTSFamilyChoice node) { #[node.family.resolve] }
+
+ private dispatch def Iterable stepDown(GTSReference node) { #[node.ref] }
+
+ private dispatch def Iterable stepDown(GTSWeave node) {
+ #[node.mapping1.resolve, node.mapping2.resolve]
+ }
+
+ private dispatch def Iterable stepDown(GTSMappingInterfaceSpec node) { #[node.gts_ref] }
+
+ private dispatch def GTSTraceMember resolve(GTSSpecificationOrReference ref) { null }
+
+ private dispatch def GTSTraceMember resolve(GTSSpecification ref) { ref }
+
+ private dispatch def GTSTraceMember resolve(GTSReference ref) { ref.ref }
+
+ private dispatch def GTSTraceMember resolve(GTSFamilySpecificationOrReference ref) { null }
+
+ private dispatch def GTSTraceMember resolve(GTSFamilySpecification ref) { ref.root_gts.resolve }
+
+ private dispatch def GTSTraceMember resolve(GTSFamilyReference ref) { ref.ref.resolve }
+
+ private dispatch def GTSTraceMember resolve(GTSMappingRefOrInterfaceSpec ref) { null }
+
+ private dispatch def GTSTraceMember resolve(GTSMappingRef ref) { ref.ref }
+
+ private dispatch def GTSTraceMember resolve(GTSMappingInterfaceSpec ref) { ref.gts_ref }
+ }
+}
diff --git a/uk.ac.kcl.inf.gts_morpher/src/uk/ac/kcl/inf/gts_morpher/util/EMFHelper.xtend b/uk.ac.kcl.inf.gts_morpher/src/uk/ac/kcl/inf/gts_morpher/util/EMFHelper.xtend
index 67d15977..6fa300a2 100644
--- a/uk.ac.kcl.inf.gts_morpher/src/uk/ac/kcl/inf/gts_morpher/util/EMFHelper.xtend
+++ b/uk.ac.kcl.inf.gts_morpher/src/uk/ac/kcl/inf/gts_morpher/util/EMFHelper.xtend
@@ -64,6 +64,10 @@ class EMFHelper {
}
}
+ static dispatch def boolean isInterfaceElement(Void v) {
+ false
+ }
+
static dispatch def boolean isInterfaceElement(EObject eo) {
true
}
diff --git a/uk.ac.kcl.inf.gts_morpher/src/uk/ac/kcl/inf/gts_morpher/util/GTSSpecificationHelper.xtend b/uk.ac.kcl.inf.gts_morpher/src/uk/ac/kcl/inf/gts_morpher/util/GTSSpecificationHelper.xtend
index 0d57340a..16595ab9 100644
--- a/uk.ac.kcl.inf.gts_morpher/src/uk/ac/kcl/inf/gts_morpher/util/GTSSpecificationHelper.xtend
+++ b/uk.ac.kcl.inf.gts_morpher/src/uk/ac/kcl/inf/gts_morpher/util/GTSSpecificationHelper.xtend
@@ -43,10 +43,12 @@ import uk.ac.kcl.inf.gts_morpher.gtsMorpher.UnitParameter
import uk.ac.kcl.inf.gts_morpher.util.MultiResourceOnChangeEvictingCache.IClearableItem
import static extension uk.ac.kcl.inf.gts_morpher.util.EMFHelper.*
+import uk.ac.kcl.inf.gts_morpher.gtsMorpher.ModelCast
class GTSSpecificationHelper {
static def getGtss (GTSSpecificationModule module) { module.members.filter(GTSSpecification) }
+ static def getModelCasts (GTSSpecificationModule module) { module.members.filter(ModelCast) }
static def getGts_families (GTSSpecificationModule module) { module.members.filter(GTSFamilySpecification) }
diff --git a/uk.ac.kcl.inf.gts_morpher/src/uk/ac/kcl/inf/gts_morpher/validation/GTSMorpherValidator.xtend b/uk.ac.kcl.inf.gts_morpher/src/uk/ac/kcl/inf/gts_morpher/validation/GTSMorpherValidator.xtend
index e4c549fd..6b24af2b 100644
--- a/uk.ac.kcl.inf.gts_morpher/src/uk/ac/kcl/inf/gts_morpher/validation/GTSMorpherValidator.xtend
+++ b/uk.ac.kcl.inf.gts_morpher/src/uk/ac/kcl/inf/gts_morpher/validation/GTSMorpherValidator.xtend
@@ -8,12 +8,16 @@ import java.util.HashSet
import java.util.Map
import java.util.Map.Entry
import java.util.Set
+import org.eclipse.emf.common.util.URI
+import org.eclipse.emf.common.util.WrappedException
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.EcorePackage
+import org.eclipse.emf.henshin.model.Attribute
import org.eclipse.emf.henshin.model.Edge
import org.eclipse.emf.henshin.model.HenshinPackage
import org.eclipse.emf.henshin.model.Node
@@ -35,11 +39,13 @@ import uk.ac.kcl.inf.gts_morpher.gtsMorpher.GTSSpecification
import uk.ac.kcl.inf.gts_morpher.gtsMorpher.GTSWeave
import uk.ac.kcl.inf.gts_morpher.gtsMorpher.GtsMorpherPackage
import uk.ac.kcl.inf.gts_morpher.gtsMorpher.LinkMapping
+import uk.ac.kcl.inf.gts_morpher.gtsMorpher.ModelCast
import uk.ac.kcl.inf.gts_morpher.gtsMorpher.NumericParameter
import uk.ac.kcl.inf.gts_morpher.gtsMorpher.ObjectMapping
import uk.ac.kcl.inf.gts_morpher.gtsMorpher.ReferenceMapping
import uk.ac.kcl.inf.gts_morpher.gtsMorpher.RuleMapping
import uk.ac.kcl.inf.gts_morpher.gtsMorpher.RuleParameterMapping
+import uk.ac.kcl.inf.gts_morpher.gtsMorpher.SlotMapping
import uk.ac.kcl.inf.gts_morpher.gtsMorpher.StringParameter
import uk.ac.kcl.inf.gts_morpher.gtsMorpher.TypeGraphMapping
import uk.ac.kcl.inf.gts_morpher.gtsMorpher.UnitCall
@@ -52,20 +58,19 @@ import uk.ac.kcl.inf.gts_morpher.util.ValueHolder
import static uk.ac.kcl.inf.gts_morpher.util.MappingConverter.*
import static uk.ac.kcl.inf.gts_morpher.util.MorphismChecker.*
+import static extension uk.ac.kcl.inf.gts_morpher.modelcaster.GTSTrace.*
import static extension uk.ac.kcl.inf.gts_morpher.util.EMFHelper.*
import static extension uk.ac.kcl.inf.gts_morpher.util.GTSSpecificationHelper.*
import static extension uk.ac.kcl.inf.gts_morpher.util.HenshinChecker.isIdentityRule
import static extension uk.ac.kcl.inf.gts_morpher.util.MorphismCompleter.*
import static extension uk.ac.kcl.inf.gts_morpher.validation.GTSMorpherValidatorHelper.*
-import org.eclipse.emf.henshin.model.Attribute
-import uk.ac.kcl.inf.gts_morpher.gtsMorpher.SlotMapping
/**
* This class contains custom validation rules.
*
* See https://www.eclipse.org/Xtext/documentation/303_runtime_concepts.html#validation
*/
-class GTSMorpherValidator extends AbstractGTSMorpherValidator implements GTSMorpherValidatorHelper.IssueAcceptor{
+class GTSMorpherValidator extends AbstractGTSMorpherValidator implements GTSMorpherValidatorHelper.IssueAcceptor {
public static val DUPLICATE_CLASS_MAPPING = MappingConverter.DUPLICATE_CLASS_MAPPING
public static val DUPLICATE_REFERENCE_MAPPING = MappingConverter.DUPLICATE_REFERENCE_MAPPING
public static val DUPLICATE_ATTRIBUTE_MAPPING = MappingConverter.DUPLICATE_ATTRIBUTE_MAPPING
@@ -102,6 +107,8 @@ class GTSMorpherValidator extends AbstractGTSMorpherValidator implements GTSMorp
public static val INCLUSION_CANNOT_BE_WITHOUT_TO_VIRTUAL = 'uk.ac.kcl.inf.gts_morpher.xdsml_compose.INCLUSION_CANNOT_BE_WITHOUT_TO_VIRTUAL'
public static val INCLUSION_CANNOT_BE_ALLOW_FROM_EMPTY = 'uk.ac.kcl.inf.gts_morpher.xdsml_compose.INCLUSION_CANNOT_BE_ALLOW_FROM_EMPTY'
public static val INCLUSION_MUST_HAVE_SAME_SOURCE_AND_TARGET = 'uk.ac.kcl.inf.gts_morpher.xdsml_compose.INCLUSION_MUST_HAVE_SAME_SOURCE_AND_TARGET'
+ public static val MODEL_CAST_INVALID_SOURCE_TYPE = 'uk.ac.kcl.inf.gts_morpher.xdsml_compose.MODEL_CAST_INVALID_SOURCE_TYPE'
+ public static val MODEL_CAST_INVALID_TARGET_TYPE = 'uk.ac.kcl.inf.gts_morpher.xdsml_compose.MODEL_CAST_INVALID_TARGET_TYPE'
/**
* Check that the rules in a GTS specification refer to the metamodel package
@@ -490,6 +497,51 @@ class GTSMorpherValidator extends AbstractGTSMorpherValidator implements GTSMorp
]
}
+ @Check
+ def checkModelCast(ModelCast modelCast) {
+ modelCast.checkModelSourceType
+ modelCast.checkModelTargetType
+ }
+
+ private def checkModelSourceType(ModelCast modelCast) {
+ if ((modelCast.modelFile !== null) && (!modelCast.modelFile.empty) && (modelCast.srcGTS !== null) &&
+ (modelCast.srcGTS.metamodel !== null)) {
+ try {
+ val modelResource = modelCast.eResource.resourceSet.getResource(URI.createFileURI(modelCast.modelFile),
+ true)
+ val metaModel = modelResource.contents.head.eClass.eResource.contents.head as EPackage
+
+ if (metaModel !== modelCast.srcGTS.metamodel) {
+ error("The meta-model of the source model must correspond to the meta-model of the source GTS.",
+ GtsMorpherPackage.Literals.MODEL_CAST__MODEL_FILE, MODEL_CAST_INVALID_SOURCE_TYPE)
+ }
+ } catch (WrappedException we) {
+ error('''Could not load model file «we.exception.message».''',
+ GtsMorpherPackage.Literals.MODEL_CAST__MODEL_FILE, MODEL_CAST_INVALID_SOURCE_TYPE)
+ } catch (Exception e) {
+ error('''Could not load model file «e.message».''', GtsMorpherPackage.Literals.MODEL_CAST__MODEL_FILE,
+ MODEL_CAST_INVALID_SOURCE_TYPE)
+ }
+ }
+ }
+
+ private def checkModelTargetType(ModelCast modelCast) {
+ if (modelCast.tgtGTS !== null) {
+ if (modelCast.srcGTS !== null) {
+ if (!modelCast.tgtGTS.canBeDerivedFrom(modelCast.srcGTS)) {
+ error('''Target GTS cannot be uniquely derived from source GTS.''',
+ GtsMorpherPackage.Literals.MODEL_CAST__TGT_GTS, MODEL_CAST_INVALID_TARGET_TYPE)
+ }
+ } else {
+ // TODO: add validation for case where the source GTS must be inferred
+ }
+ }
+ }
+
+ private def canBeDerivedFrom(GTSSpecification target, GTSSpecification source) {
+ source.findTracesTo(target).size == 1
+ }
+
private dispatch def checkIsValidMapping(Void spec) {}
private dispatch def checkIsValidMapping(GTSMappingRefOrInterfaceSpec spec) {
@@ -533,14 +585,13 @@ class GTSMorpherValidator extends AbstractGTSMorpherValidator implements GTSMorp
private def mapMessage(Entry> mappingChoices) {
var message = '''«if (mappingChoices.key instanceof EClass) {'''class'''} else {'''reference'''}» «mappingChoices.key.qualifiedName» to any of [«mappingChoices.value.map[eo | eo.qualifiedName].join(', ')»]'''
-
+
if (message.length > 150) {
message = message.substring(1, 147) + '...'
}
-
+
message
}
-
private def issueData(EObject source,
EObject target) '''«if (source instanceof EClass) {'''class'''} else {'''reference'''}»:«source.qualifiedName»=>«target.qualifiedName»'''
@@ -598,7 +649,7 @@ class GTSMorpherValidator extends AbstractGTSMorpherValidator implements GTSMorp
val _mapping = mapping.extractMapping
mapping.isInCompleteMapping(_mapping)
}
-
+
override warning(String message, EObject source, EStructuralFeature feature, String code) {
super.warning(message, source, feature, code)
}