Browse Source

Semi-working transformation_execute and transformation_add

Yentl Van Tendeloo 4 years ago
parent
commit
daa9a291fe

+ 101 - 69
bootstrap/core_algorithm.alc

@@ -704,14 +704,10 @@ Element function execute_operation(operation_id : String, input_models : Element
 		while (get_entry_id(model_name) != ""):
 			model_name = ".tmp/" + random_string(20)
 		model_create(merged_model, model_name, merged_metamodel_id, "Model")
-		output("Operating on: " + cast_string(model_name))
+		log("Transforming...")
 		// We want to modify, so modify
-		if (modify(merged_model, True)):
-			// Overwrite the merged model
-			model_overwrite(merged_model, get_entry_id(model_name), merged_metamodel_id)
-		else:
-			// Reload the merged model
-			merged_model = get_full_model(get_entry_id(model_name), merged_metamodel_id)
+		do_spawn_modify(model_name, True)
+		merged_model = get_full_model(get_entry_id(model_name), merged_metamodel_id)
 		//model_delete(get_entry_id(model_name))
 		result = True
 	elif (exact_type == "ActionLanguage"):
@@ -949,9 +945,6 @@ Void function enact_PM(pm : Element, mapping : Element):
 				// Execute a transformation
 				// This the difficult part!
 
-				//result = enact_action(pm, element, mapping)
-				//output("Success")
-
 				Element args
 				String taskname
 				args = list_create()
@@ -1346,6 +1339,97 @@ String function cmd_model_render(model_name : String, mapper_name : String, rend
 	else:
 		return "Model not found: " + model_name!
 
+Boolean function do_spawn_modify(model_name : String, write : Boolean):
+	log("Spawned task for " + model_name)
+	log("Taskname: " + get_taskname())
+	output("Please edit this model before sending next input: " + model_name)
+	log("OK, waiting for input")
+	input()
+	log("SPAWN MODIFY ENDED")
+	return False!
+
+Boolean function do_spawn_activity(transformation_id : String, tracability_name : String, inputs : Element, outputs : Element, output_map : Element):
+	Element lst
+	Element returnvalue
+	String taskname
+
+	lst = list_create()
+	returnvalue = set_create()
+	list_append(lst, returnvalue)
+	list_append(lst, transformation_id)
+	list_append(lst, tracability_name)
+	list_append(lst, inputs)
+	list_append(lst, outputs)
+	list_append(lst, output_map)
+	taskname = spawn(spawn_activity, lst)
+
+	output("Spawned activity on task: " + taskname)
+	log("Spawned activity")
+
+	while (set_len(returnvalue) == 0):
+		sleep(0.1)
+
+	log("Activity terminated!")
+	output("Finished task: " + taskname)
+	return cast_boolean(set_pop(returnvalue))!
+
+Void function spawn_activity(returnvalue : Element, transformation_id : String, tracability_name : String, inputs : Element, outputs : Element, output_map : Element):
+	Element result
+	Element keys
+	String key
+
+	if (read_type(core, transformation_id) == "ActionLanguage"):
+		output("Success: ready for AL execution")
+	elif (read_type(core, transformation_id) == "ManualOperation"):
+		output("Success: ready for MANUAL execution")
+	else:
+		output("Success: ready for MT execution")
+
+	// Do tracability
+	Element tracability_model
+	if (tracability_name != ""):
+		// Check if exists
+		if (get_entry_id(tracability_name) == ""):
+			// No, so create
+			tracability_model = instantiate_model(get_full_model(get_entry_id("formalisms/Tracability"), get_entry_id("formalisms/SimpleClassDiagrams")))
+			model_create(tracability_model, tracability_name, get_entry_id("formalisms/Tracability"), "Model")
+		else:
+			// Yes, so read out
+			tracability_model = get_full_model(get_entry_id(tracability_name), get_entry_id("formalisms/Tracability"))
+	else:
+		tracability_model = read_root()
+
+	result = execute_operation(transformation_id, inputs, tracability_model)
+
+	// Flush tracability again, just to be sure
+	if (tracability_name != ""):
+		model_overwrite(tracability_model, get_entry_id(tracability_name), get_entry_id("formalisms/Tracability"))
+
+	// Now write out the models again
+	if (element_eq(result, read_root())):
+		// Something went wrong!
+		set_add(returnvalue, False)
+		output("Failure")
+	else:
+		keys = dict_keys(outputs)
+		while (set_len(keys) > 0):
+			key = set_pop(keys)
+			log("Writing away model with key " + cast_string(key))
+			log("Output map: " + dict_to_string(output_map))
+			log("Outputs: " + dict_to_string(outputs))
+			
+			if (get_entry_id(outputs[key]) == ""):
+				// New model
+				model_create(result[key], outputs[key], get_entry_id(output_map[key]), "Model")
+			else:
+				model_overwrite(result[key], get_entry_id(outputs[key]), get_entry_id(output_map[key]))
+
+		set_add(returnvalue, True)
+		output("Success")
+
+	sleep(5)
+	return!
+
 String function cmd_transformation_execute(transformation_name : String, source_models : Element, target_models : Element, tracability_name : String):
 	// Execute a transformation, whatever type it is
 	// First we detect the type, so we know how to prepare for invocation
@@ -1362,9 +1446,6 @@ String function cmd_transformation_execute(transformation_name : String, source_
 	String target_model_name
 	String source_model_name
 	String source_model_ID
-	Element result
-	Element keys
-	String key
 	String assoc_name
 
 	transformation_id = get_entry_id(transformation_name)
@@ -1421,54 +1502,10 @@ String function cmd_transformation_execute(transformation_name : String, source_
 							else:
 								return "Permission denied to model: " + target_model_name!
 
-				if (read_type(core, transformation_id) == "ActionLanguage"):
-					output("Success: ready for AL execution")
-				elif (read_type(core, transformation_id) == "ManualOperation"):
-					output("Success: ready for MANUAL execution")
-				else:
-					output("Success: ready for MT execution")
-
-				// Do tracability
-				Element tracability_model
-				if (tracability_name != ""):
-					// Check if exists
-					if (get_entry_id(tracability_name) == ""):
-						// No, so create
-						tracability_model = instantiate_model(get_full_model(get_entry_id("formalisms/Tracability"), get_entry_id("formalisms/SimpleClassDiagrams")))
-						model_create(tracability_model, tracability_name, get_entry_id("formalisms/Tracability"), "Model")
-					else:
-						// Yes, so read out
-						tracability_model = get_full_model(get_entry_id(tracability_name), get_entry_id("formalisms/Tracability"))
+				if (do_spawn_activity(transformation_id, tracability_name, inputs, outputs, output_map)):
+					return "Success"!
 				else:
-					tracability_model = read_root()
-
-				result = execute_operation(transformation_id, inputs, tracability_model)
-
-				// Flush tracability again, just to be sure
-				if (tracability_name != ""):
-					model_overwrite(tracability_model, get_entry_id(tracability_name), get_entry_id("formalisms/Tracability"))
-
-				// Now write out the models again
-				if (element_eq(result, read_root())):
-					// Something went wrong!
 					return "Failure"!
-				else:
-					keys = dict_keys(outputs)
-					while (set_len(keys) > 0):
-						key = set_pop(keys)
-						log("Writing away model with key " + cast_string(key))
-						log("Output map: " + dict_to_string(output_map))
-						log("Outputs: " + dict_to_string(outputs))
-						
-						if (get_entry_id(outputs[key]) == ""):
-							// New model
-							log("New model!")
-							model_create(result[key], outputs[key], get_entry_id(output_map[key]), "Model")
-						else:
-							log("Existing model!")
-							model_overwrite(result[key], get_entry_id(outputs[key]), get_entry_id(output_map[key]))
-
-					return "Success"!
 			else:
 				return "Model is not executable: " + transformation_name!
 		else:
@@ -1518,6 +1555,7 @@ String function cmd_model_overwrite(model_name : String, metamodel_name : String
 				if (element_eq(mm, read_root())):
 					return "Metamodel does not conform to formalisms/SimpleClassDiagrams: " + metamodel_name!
 
+				log("Overwriting...")
 				output("Waiting for model constructors...")
 				new_model = compile_model(input(), mm)
 
@@ -1730,11 +1768,8 @@ String function transformation_add(source_models : Element, target_models : Elem
 		if (dict_len(source_models) + dict_len(target_models) > 0):
 			merged_formalism = model_fuse(formalism_map)
 			model_create(merged_formalism, "merged/" + operation_name, get_entry_id("formalisms/SimpleClassDiagrams"), "Model")
-			output("Operating on: merged/" + operation_name)
-			if (modify(merged_formalism, True)):
-				model_overwrite(merged_formalism, get_entry_id("merged/" + operation_name), get_entry_id("formalisms/SimpleClassDiagrams"))
-			else:
-				merged_formalism = get_full_model(get_entry_id("merged/" + operation_name), get_entry_id("formalisms/SimpleClassDiagrams"))
+			do_spawn_modify("merged/" + operation_name, True)
+			merged_formalism = get_full_model(get_entry_id("merged/" + operation_name), get_entry_id("formalisms/SimpleClassDiagrams"))
 
 		if (operation_type == "manual"):
 			if (dict_len(source_models) + dict_len(target_models) == 0):
@@ -1880,11 +1915,8 @@ String function cmd_transformation_add_MT(source_models : Element, target_models
 
 	merged_formalism = model_fuse(to_ramify)
 	model_create(merged_formalism, "merged/" + operation_name, get_entry_id("formalisms/SimpleClassDiagrams"), "Model")
-	output("Operating on: merged/" + operation_name)
-	if (modify(merged_formalism, True)):
-		model_overwrite(merged_formalism, get_entry_id("merged/" + operation_name), get_entry_id("formalisms/SimpleClassDiagrams"))
-	else:
-		merged_formalism = get_full_model(get_entry_id("merged/" + operation_name), get_entry_id("formalisms/SimpleClassDiagrams"))
+	do_spawn_modify("merged/" + operation_name, True)
+	merged_formalism = get_full_model(get_entry_id("merged/" + operation_name), get_entry_id("formalisms/SimpleClassDiagrams"))
 	model_overwrite(merged_formalism, get_entry_id("merged/" + operation_name), get_entry_id("formalisms/SimpleClassDiagrams"))
 
 	ramified_metamodel = ramify(merged_formalism)

+ 0 - 1
bootstrap/random.alc

@@ -24,7 +24,6 @@ Integer function random_interval(a : Integer, b : Integer):
 	if (a == b):
 		return a!
 	else:
-		log("Random gives us: " + cast_value(random()))
 		return cast_integer(random() * cast_float(b - a + 1) + cast_float(a))!
 
 Element function random_choice(list : Element):

+ 1 - 0
scripts/run_local_modelverse.py

@@ -32,6 +32,7 @@ try:
     server = subprocess.Popen(program_to_execute)
 
     server.wait()
+
 finally:
     # Stop the server
     try:

+ 8 - 2
unit/log_output.py

@@ -1,7 +1,7 @@
 """
 Generated by Statechart compiler by Glenn De Jonghe, Joeri Exelmans, Simon Van Mierlo, and Yentl Van Tendeloo (for the inspiration)
 
-Date:   Fri Nov 10 08:52:06 2017
+Date:   Mon Nov 13 12:46:02 2017
 
 Model author: Yentl Van Tendeloo
 Model name:   Logging
@@ -65,6 +65,7 @@ class Logging(RuntimeClassBase):
         _init_1.setTrigger(Event("_0after"))
         self.states["/init"].addTransition(_init_1)
         _init_2 = Transition(self, self.states["/init"], [self.states["/finished"]])
+        _init_2.setAction(self._init_2_exec)
         _init_2.setTrigger(Event("terminate", "inp"))
         self.states["/init"].addTransition(_init_2)
     
@@ -77,6 +78,10 @@ class Logging(RuntimeClassBase):
     def _init_0_exec(self, parameters):
         value = parameters[0]
         self.log.append(value)
+        print("Logging " + str(value))
+    
+    def _init_2_exec(self, parameters):
+        print("Got terminate")
     
     def initializeStatechart(self):
         # enter default state
@@ -102,4 +107,5 @@ class Controller(ThreadsControllerBase):
         ThreadsControllerBase.__init__(self, ObjectManager(self), keep_running, behind_schedule_callback)
         self.addInputPort("inp")
         self.addOutputPort("outp")
-        self.object_manager.createInstance("Logging", [log])
+        self.object_manager.createInstance("Logging", [log])
+        print("Start SC at " + str(self))

+ 7 - 1
unit/log_output.xml

@@ -14,18 +14,24 @@
                 self.log = log
             </body>
         </constructor>
+
         <scxml initial="init">
             <state id="init">
                 <transition event="input" port="inp" target=".">
                     <parameter name="value"/>
                     <script>
+                        print("Logging " + str(value))
                         self.log.append(value)
                     </script>
                 </transition>
 
                 <transition after="0.1" target="."/>
 
-                <transition event="terminate" port="inp" target="../finished"/>
+                <transition event="terminate" port="inp" target="../finished">
+                    <script>
+                        print("Got terminate")
+                    </script>
+                </transition>
             </state>
 
             <state id="finished"/>

+ 29 - 27
unit/test_all.py

@@ -173,38 +173,39 @@ class TestModelverse(unittest.TestCase):
     def test_operations(self):
         log = []
 
-        def manual_callback(context):
-            p1 = instantiate(None, "PetriNet_Runtime/Place", context=context)
-            attr_assign(None, p1, "tokens", 1, context=context)
-            attr_assign(None, p1, "name", "p1", context=context)
-            p2 = instantiate(None, "PetriNet_Runtime/Place", context=context)
-            attr_assign(None, p2, "tokens", 2, context=context)
-            attr_assign(None, p2, "name", "p2", context=context)
-            p3 = instantiate(None, "PetriNet_Runtime/Place", context=context)
-            attr_assign(None, p3, "tokens", 3, context=context)
-            attr_assign(None, p3, "name", "p3", context=context)
-            t1 = instantiate(None, "PetriNet_Runtime/Transition", context=context)
-            attr_assign(None, t1, "name", "t1", context=context)
-            attr_assign(None, t1, "executing", False, context=context)
-            p2t1 = instantiate(None, "PetriNet_Runtime/P2T", (p1, t1), context=context)
-            attr_assign(None, p2t1, "weight", 1, context=context)
-            p2t2 = instantiate(None, "PetriNet_Runtime/P2T", (p2, t1), context=context)
-            attr_assign(None, p2t2, "weight", 1, context=context)
-            t2p1 = instantiate(None, "PetriNet_Runtime/T2P", (t1, p3), context=context)
-            attr_assign(None, t2p1, "weight", 2, context=context)
+        def manual_callback(model):
+            print("Got in manual callback")
+            p1 = instantiate(model, "PetriNet_Runtime/Place")
+            p2 = instantiate(model, "PetriNet_Runtime/Place")
+            p3 = instantiate(model, "PetriNet_Runtime/Place")
+            t1 = instantiate(model, "PetriNet_Runtime/Transition")
+            p2t1 = instantiate(model, "PetriNet_Runtime/P2T", (p1, t1))
+            p2t2 = instantiate(model, "PetriNet_Runtime/P2T", (p2, t1))
+            t2p1 = instantiate(model, "PetriNet_Runtime/T2P", (t1, p3))
+            attr_assign(model, p1, "tokens", 1)
+            attr_assign(model, p1, "name", "p1")
+            attr_assign(model, p2, "tokens", 2)
+            attr_assign(model, p2, "name", "p2")
+            attr_assign(model, p3, "tokens", 3)
+            attr_assign(model, p3, "name", "p3")
+            attr_assign(model, t1, "name", "t1")
+            attr_assign(model, t1, "executing", False)
+            attr_assign(model, p2t1, "weight", 1)
+            attr_assign(model, p2t2, "weight", 1)
+            attr_assign(model, t2p1, "weight", 2)
 
         model_add("test/PetriNet", "formalisms/SimpleClassDiagrams", open("integration/code/pn_design.mvc", "r").read())
         model_add("test/PetriNet_Runtime", "formalisms/SimpleClassDiagrams", open("integration/code/pn_runtime.mvc", "r").read())
 
         model_add("test/my_pn", "test/PetriNet", open("integration/code/pn_design_model.mvc", "r").read())
 
-        def add_tracability_D2R(context):
-            instantiate(None, "Association", ("PetriNet/Place", "PetriNet_Runtime/Place"), ID="D2R_PlaceLink", context=context)
-            instantiate(None, "Association", ("PetriNet/Transition", "PetriNet_Runtime/Transition"), ID="D2R_TransitionLink", context=context)
+        def add_tracability_D2R(model):
+            instantiate(model, "Association", ("PetriNet/Place", "PetriNet_Runtime/Place"), ID="D2R_PlaceLink")
+            instantiate(model, "Association", ("PetriNet/Transition", "PetriNet_Runtime/Transition"), ID="D2R_TransitionLink")
 
-        def add_tracability_R2D(context):
-            instantiate(None, "Association", ("PetriNet_Runtime/Place", "PetriNet/Place"), ID="R2D_PlaceLink", context=context)
-            instantiate(None, "Association", ("PetriNet_Runtime/Transition", "PetriNet/Transition"), ID="R2D_TransitionLink", context=context)
+        def add_tracability_R2D(model):
+            instantiate(model, "Association", ("PetriNet_Runtime/Place", "PetriNet/Place"), ID="R2D_PlaceLink")
+            instantiate(model, "Association", ("PetriNet_Runtime/Transition", "PetriNet/Transition"), ID="R2D_TransitionLink")
 
         transformation_add_MT({"PetriNet": "test/PetriNet"}, {}, "test/print_pn", open("integration/code/pn_print.mvc").read())
         transformation_add_MANUAL({"PetriNet": "test/PetriNet"}, {"PetriNet_Runtime": "test/PetriNet_Runtime"}, "test/pn_design_to_runtime", add_tracability_D2R)
@@ -218,10 +219,11 @@ class TestModelverse(unittest.TestCase):
         thrd.daemon = True
         thrd.start()
 
-        assert transformation_execute_MT("test/print_pn", {"PetriNet": "test/my_pn"}, {}, (ctrl, "inp", "outp")) == None
+        assert transformation_execute_MT("test/print_pn", {"PetriNet": "test/my_pn"}, {}, (ctrl, "inp", "outp")) == True
         print("Joining")
         thrd.join()
         print("Joined")
+        print("Got log: " + str(log))
         assert set(log) == set(['"p1" --> 1',
                                 '"p2" --> 2',
                                 '"p3" --> 3'])
@@ -239,7 +241,7 @@ class TestModelverse(unittest.TestCase):
         thrd.daemon = True
         thrd.start()
 
-        assert transformation_execute_MT("test/print_pn", {"PetriNet": "test/my_pn"}, {}, (ctrl, "inp", "outp")) == None
+        assert transformation_execute_MT("test/print_pn", {"PetriNet": "test/my_pn"}, {}, (ctrl, "inp", "outp")) == True
         thrd.join()
         assert set(log) == set(['"p1" --> 0',
                                 '"p2" --> 1',

+ 1 - 0
unit/utils.py

@@ -78,5 +78,6 @@ def flush_data(address, data):
 def start_mvc():
     port = getFreePort()
     address = "127.0.0.1:%s" % port
+    print("Execute run local MV")
     proc = execute("run_local_modelverse", [str(port)], wait=False)
     return proc, address

+ 147 - 141
wrappers/classes/modelverse.xml

@@ -9,6 +9,7 @@
             action = self.actions[context].pop(0)
             self.parameters = action["parameters"]
             self.current_ID = action["ID"]
+            self.action_name = action["name"]
         </body>
     </method>
 
@@ -76,6 +77,8 @@
         <parameter name="context"/>
         <parameter name="expected"/>
         <body>
+            if context not in self.inputs:
+                return False
             if isinstance(expected, list):
                 return self.inputs[context] and self.inputs[context][0]["name"] in expected
             else:
@@ -84,8 +87,9 @@
     </method>
 
     <constructor>
+        <parameter name="taskname" default="None"/>
         <body>
-            self.controller.taskname = None
+            self.controller.taskname = taskname
             self.actions = {None: []}
             self.responses = []
             self.http_clients = []
@@ -168,7 +172,7 @@
                         </raise>
                         <script>
                             self.responses.append(json.loads(data))
-                            #print("Got data: " + str(json.loads(data)))
+                            print("Got data at %s: %s" % (self.controller.taskname, str(json.loads(data))))
                         </script>
                     </transition>
 
@@ -196,7 +200,14 @@
                             self.address = (self.address[0], int(self.address[1]))
 
                             self.i = 0
-                            self.controller.taskname = self.taskname = str(uuid.uuid4())
+                            taskname = self.controller.taskname
+                            if taskname is None:
+                                taskname = str(uuid.uuid4())
+                                self.skip_init = False
+                            else:
+                                self.skip_init = True
+                            
+                            self.controller.taskname = self.taskname = taskname
                         </script>
                     </onentry>
 
@@ -223,7 +234,13 @@
                     </state>
 
                     <state id="waiting_http_client">
-                        <transition event="http_client_ready" target="../wait_for_taskname_ack">
+                        <transition event="http_client_ready" cond="self.skip_init" target="../connect_http_client">
+                            <script>
+                                self.i += 1
+                            </script>
+                        </transition>
+
+                        <transition event="http_client_ready" cond="not self.skip_init" target="../wait_for_taskname_ack">
                             <!-- Request the task to be created -->
                             <raise event="request_raw">
                                 <parameter expr="self.taskname"/>
@@ -577,119 +594,51 @@
                         </transition>
                     </state>
 
-                    <state id="store_on_scripted" initial="transformation_add_MT">
-                        <state id="transformation_add_MT" initial="send_metadata">
+                    <state id="store_on_scripted" initial="transformation_add">
+                        <state id="transformation_add" initial="send_metadata">
                             <state id="send_metadata">
                                 <onentry>
                                     <raise event="request">
-                                        <parameter expr="['transformation_add_MT'] + self.dict_to_list(self.parameters[0]) + self.dict_to_list(self.parameters[1]) + [self.parameters[2]]"/>
+                                        <parameter expr="[self.action_name] + self.dict_to_list(self.parameters[0]) + self.dict_to_list(self.parameters[1]) + [self.parameters[2]]"/>
                                     </raise>
+                                </onentry>
 
+                                <transition cond="self.expect_response_partial('Please edit this model before sending next input: ', pop=False)" target="../wait_for_user">
                                     <script>
-                                        self.context = str(uuid.uuid4())
-                                        self.actions[self.context] = []
-                                        self.code = self.parameters[3]
+                                        model = self.responses.pop(0).split(": ", 1)[1]
+                                        print("Got model to edit: " + str(model))
                                     </script>
-
-                                </onentry>
-
-                                <transition cond="self.expect_response_partial('Operating on: ')" target="../edit_metamodel">
-                                    <raise event="result">
-                                        <parameter expr="[self.context, self.responses.pop(0).split(': ', 1)[1]]"/>
-                                    </raise>
-                                </transition>
-                            </state>
-
-                            <state id="edit_metamodel">
-                                <transition cond="self.expect_response('Model loaded, ready for commands!')" target="../../../../going_scripted"/>
-                                <transition cond="self.expect_response('Waiting for model constructors...')" target="../send_model"/>
-                            </state>
-
-                            <state id="send_model">
-                                <onentry>
-                                    <raise event="request">
-                                        <parameter expr="self.code"/>
-                                    </raise>
-                                </onentry>
-
-                                <transition cond="self.expect_response('Success')" target="../../../../wait_for_action/megamodelling">
                                     <raise event="result">
-                                        <parameter expr="None"/>
+                                        <parameter expr="model"/>
                                     </raise>
                                 </transition>
                             </state>
 
-                            <transition cond="self.expect_response_partial('', pop=False)" target="../../../wait_for_action/history">
-                                <script>
-                                    print("UNKNOWN RESPONSE received: " + str(self.responses.pop(0)))
-                                </script>
-                            </transition>
-                        </state>
-
-                        <state id="transformation_add_AL" initial="send_metadata">
-                            <state id="send_metadata">
-                                <onentry>
-                                    <raise event="request">
-                                        <parameter expr="['transformation_add_AL'] + self.dict_to_list(self.parameters[0]) + self.dict_to_list(self.parameters[1]) + [self.parameters[2]]"/>
-                                    </raise>
-
+                            <state id="wait_for_user">
+                                <transition cond="None in self.inputs and self.inputs[None]" target="../upload_changes">
                                     <script>
-                                        self.context = str(uuid.uuid4())
-                                        self.actions[self.context] = []
-                                        self.code = self.parameters[3]
+                                        self.inputs[None].pop(0)
+                                        print("POP input indicating readyness")
                                     </script>
-                                </onentry>
-
-                                <transition cond="self.expect_response_partial('Operating on: ')" target="../edit_metamodel">
-                                    <raise event="result">
-                                        <parameter expr="[self.context, self.responses.pop(0).split(': ', 1)[1]]"/>
+                                    <raise event="request">
+                                        <parameter expr="True"/>
                                     </raise>
                                 </transition>
                             </state>
 
-                            <state id="edit_metamodel">
-                                <transition cond="self.expect_response('Model loaded, ready for commands!')" target="../../../../going_scripted"/>
-                            </state>
-                               
-                            <state id="send_model">
-                                <onentry>
+                            <state id="upload_changes">
+                                <transition cond="self.expect_response('Waiting for code constructors...')" target=".">
                                     <raise event="request">
-                                        <parameter expr="self.code"/>
-                                    </raise>
-                                </onentry>
-
-                                <transition cond="self.expect_response('Success')" target="../../../../wait_for_action/megamodelling">
-                                    <raise event="result">
-                                        <parameter expr="None"/>
+                                        <parameter expr="self.parameters[3]"/>
                                     </raise>
                                 </transition>
-                            </state>
-
-                            <transition cond="self.expect_response('Waiting for code constructors...')" target="send_model"/>
-                        </state>
 
-                        <state id="transformation_add_MANUAL" initial="send_metadata">
-                            <state id="send_metadata">
-                                <onentry>
+                                <transition cond="self.expect_response('Waiting for model constructors...')" target=".">
                                     <raise event="request">
-                                        <parameter expr="['transformation_add_MANUAL'] + self.dict_to_list(self.parameters[0]) + self.dict_to_list(self.parameters[1]) + [self.parameters[2]]"/>
-                                    </raise>
-
-                                    <script>
-                                        self.context = str(uuid.uuid4())
-                                        self.actions[self.context] = []
-                                    </script>
-                                </onentry>
-
-                                <transition cond="self.expect_response_partial('Operating on: ')" target="../edit_metamodel">
-                                    <raise event="result">
-                                        <parameter expr="[self.context, self.responses.pop(0).split(': ', 1)[1]]"/>
+                                        <parameter expr="self.parameters[3]"/>
                                     </raise>
                                 </transition>
-                            </state>
 
-                            <state id="edit_metamodel">
-                                <transition cond="self.expect_response('Model loaded, ready for commands!')" target="../../../../going_scripted"/>
                                 <transition cond="self.expect_response('Success')" target="../../../../wait_for_action/megamodelling">
                                     <raise event="result">
                                         <parameter expr="None"/>
@@ -711,58 +660,31 @@
                                     </script>
                                 </onentry>
 
-                                <transition cond="self.expect_response('Success: ready for MANUAL execution', pop=True)" target="../edit_model">
+                                <transition cond="self.expect_response_partial('Spawned activity on task: ', pop=False)" target="../waiting">
                                     <script>
-                                        self.context = str(uuid.uuid4())
-                                        self.actions[self.context] = []
+                                        self.sub_sc_taskname = self.responses.pop(0).split(": ", 1)[1]
                                     </script>
-                                </transition>
-                                <transition cond="self.expect_response('Success: ready for AL execution', pop=True) or self.expect_response('Success: ready for MT execution', pop=True)" target="../dialog">
-                                    <script>
-                                        self.input_context = str(uuid.uuid4())
-                                        self.inputs[self.input_context] = []
-                                    </script>
-                                    <raise event="result">
-                                        <parameter expr="['SC', self.parameters[0], self.input_context]"/>
-                                    </raise>
-                                </transition>
-                            </state>
-
-                            <state id="dialog">
-                                <transition cond="self.expect_response('Success', pop=False) or self.expect_response('Failure', pop=False)" target="../../../../wait_for_action/history">
                                     <raise event="result">
-                                        <parameter expr="True if self.responses.pop(0) == 'Success' else False"/>
-                                    </raise>
-                                </transition>
-
-                                <transition cond="not (self.expect_response('Success', pop=False) or self.expect_response('Failure', pop=False)) and self.expect_response_partial('', pop=False)" target=".">
-                                    <raise event="data_output">
-                                        <parameter expr="self.responses.pop(0)"/>
-                                    </raise>
-                                </transition>
-
-                                <transition cond="self.expect_input(self.input_context, 'data_input')" target=".">
-                                    <raise event="request">
-                                        <parameter expr="self.inputs[self.input_context].pop(0)['parameters']"/>
+                                        <parameter expr="self.sub_sc_taskname"/>
                                     </raise>
                                 </transition>
                             </state>
 
-                            <state id="edit_model">
-                                <transition cond="self.expect_response_partial('Please perform manual operation ', pop=True)" target="."/>
-                                <transition cond="self.expect_response_partial('Operating on: ', pop=False)" target=".">
+                            <state id="waiting">
+                                <onentry>
                                     <script>
-                                        model = self.responses.pop(0).split(": ", 1)[1]
+                                        print("Waiting on task " + self.sub_sc_taskname)
                                     </script>
+                                </onentry>
+
+                                <transition cond="self.expect_response('Finished task: ' + self.sub_sc_taskname)" target="."/>
+                                <transition cond="self.expect_response('Success', pop=False) or self.expect_response('Failure', pop=False)" target="../../../../wait_for_action/megamodelling">
                                     <raise event="result">
-                                        <parameter expr="['OP', self.parameters[0], self.context, model]"/>
-                                    </raise>
-                                </transition>
-                                <transition cond="self.expect_response('Model loaded, ready for commands!')" target="../../../../going_scripted"/>
-                                <transition cond="self.expect_response('Success')" target="../../../../wait_for_action/megamodelling">
-                                    <raise event="result">
-                                        <parameter expr="True"/>
+                                        <parameter expr="self.responses.pop(0) == 'Success'"/>
                                     </raise>
+                                    <script>
+                                        print("FINISHED")
+                                    </script>
                                 </transition>
                             </state>
                         </state>
@@ -1434,15 +1356,18 @@
                         </transition>
                     </state>
 
-                    <state id="save">
+                    <state id="exit_save">
                         <onentry>
                             <raise event="request">
-                                <parameter expr="['exit', 'model_modify', self.current_model]"/>
+                                <parameter expr="['exit']"/>
                             </raise>
                         </onentry>
 
-                        <transition cond="self.expect_response('Success')" target="."/>
-                        <transition cond="self.expect_response('Model loaded, ready for commands!')" target="../../wait_for_action/modelling/recognized/manual"/>
+                        <transition cond="self.expect_response('Success')" target="../../wait_for_action/megamodelling">
+                            <raise event="result">
+                                <parameter expr="None"/>
+                            </raise>
+                        </transition>
                     </state>
 
                     <state id="service_register">
@@ -1524,6 +1449,86 @@
                                 self.load_action(None)
                             </script>
                         </transition>
+
+                        <transition cond="self.expect_response('Success: ready for AL execution')" target="../activity/SC"/>
+                        <transition cond="self.expect_response('Success: ready for MT execution')" target="../activity/SC"/>
+                        <transition cond="self.expect_response('Success: ready for MANUAL execution')" target="../activity/OP"/>
+                    </state>
+
+                    <state id="activity" initial="SC">
+                        <state id="SC">
+                            <onentry>
+                                <script>
+                                    print("SC EXEC!")
+                                </script>
+                                <raise event="result">
+                                    <parameter expr="'SC'"/>
+                                </raise>
+                            </onentry>
+
+                            <state id="forwarding">
+                                <transition cond="self.expect_response('Success', pop=False) or self.expect_response('Failure', pop=False)" target="../../../history">
+                                    <raise event="result">
+                                        <parameter expr="True if self.responses.pop(0) == 'Success' else False"/>
+                                    </raise>
+                                    <script>
+                                        print("FINISHED")
+                                    </script>
+                                </transition>
+
+                                <transition cond="not (self.expect_response('Success', pop=False) or self.expect_response('Failure', pop=False)) and self.expect_response_partial('', pop=False)" target=".">
+                                    <raise event="data_output">
+                                        <parameter expr="self.responses.pop(0)"/>
+                                    </raise>
+                                </transition>
+
+                                <transition cond="self.expect_input(None, 'data_input')" target=".">
+                                    <raise event="request">
+                                        <parameter expr="self.inputs[None].pop(0)['parameters']"/>
+                                    </raise>
+                                </transition>
+                            </state>
+                        </state>
+
+                        <state id="OP">
+                            <onentry>
+                                <script>
+                                    print("OP EXEC on " + str(self.controller.taskname))
+                                </script>
+                                <raise event="result">
+                                    <parameter expr="'OP'"/>
+                                </raise>
+                            </onentry>
+
+                            <onexit>
+                                <script>
+                                    print("LEAVING")
+                                </script>
+                            </onexit>
+
+                            <state id="forwarding">
+                                <transition cond="self.expect_response_partial('Please perform manual operation ', pop=True)" target="."/>
+
+                                <transition cond="self.expect_response_partial('Please edit this model before sending next input: ', pop=False)" target=".">
+                                    <raise event="result">
+                                        <parameter expr="self.responses.pop(0).split(': ')[1]"/>
+                                    </raise>
+                                    <script>
+                                        print("EDITING...")
+                                    </script>
+                                </transition>
+
+                                <transition cond="None in self.inputs and self.inputs[None]" target="../../../history">
+                                    <script>
+                                        print("GOT DATA INPUT")
+                                        self.inputs[None].pop(0)
+                                    </script>
+                                    <raise event="request">
+                                        <parameter expr="0"/>
+                                    </raise>
+                                </transition>
+                            </state>
+                        </state>
                     </state>
 
                     <state id="megamodelling">
@@ -1617,19 +1622,19 @@
                             </script>
                         </transition>
 
-                        <transition cond="self.expect_action(None, 'transformation_add_MT')" target="../../operations/store_on_scripted/transformation_add_MT">
+                        <transition cond="self.expect_action(None, 'transformation_add_MT')" target="../../operations/store_on_scripted/transformation_add">
                             <script>
                                 self.load_action(None)
                             </script>
                         </transition>
 
-                        <transition cond="self.expect_action(None, 'transformation_add_AL')" target="../../operations/store_on_scripted/transformation_add_AL">
+                        <transition cond="self.expect_action(None, 'transformation_add_AL')" target="../../operations/store_on_scripted/transformation_add">
                             <script>
                                 self.load_action(None)
                             </script>
                         </transition>
 
-                        <transition cond="self.expect_action(None, 'transformation_add_MANUAL')" target="../../operations/store_on_scripted/transformation_add_MANUAL">
+                        <transition cond="self.expect_action(None, 'transformation_add_MANUAL')" target="../../operations/store_on_scripted/transformation_add">
                             <script>
                                 self.load_action(None)
                             </script>
@@ -1937,7 +1942,7 @@
                                 </script>
                             </transition>
 
-                            <transition cond="self.expect_action(self.context, 'save')" target="../../../operations/save">
+                            <transition cond="self.expect_action(self.context, 'exit_save')" target="../../../operations/exit_save">
                                 <script>
                                     self.load_action(self.context)
                                 </script>
@@ -2117,7 +2122,8 @@
                         <parameter name="value"/>
                         <parameter name="context_ID"/>
                         <script>
-                            self.inputs[context_ID].append({"name": "data_input", "parameters": value})
+                            print("Got data_input in MV")
+                            self.inputs.setdefault(context_ID, []).append({"name": "data_input", "parameters": value})
                         </script>
                     </transition>
                 </state>

+ 124 - 44
wrappers/modelverse.py

@@ -52,38 +52,108 @@ def _next_ID():
     ID += 1
     return ID
 
-def _process_SC(statechart, port_sc, context):
-    print("Context: " + str(context))
+def __run_new_modelverse(address, username, password, callback, model):
+    print("RUN NEW")
+    init(address)
+    login(username, password)
+    print("LOGIN OK")
+    if callback is not None:
+        callback(model)
+    exit_save(model)
+    print("CALLBACK DONE")
+
+def __run_new_modelverse_activity(address, username, password, taskname, pipe, callback):
+    print("Run MV activity")
+    init(address, taskname=taskname)
+    controller.username = username
+    controller.password = password
+    print("INIT OK")
+    t = OUTPUT()
+    print("Got type: " + str(t))
+
+    if t == "OP":
+        print("Requesting model...")
+        model = OUTPUT()
+        print("Do manual operations on " + str(model))
+        __invoke(callback, model)
+        print("Invocation OK")
+        controller.addInput(Event("data_input", "action_in", [None, None]))
+        print("Waiting on output")
+        # TODO fix this to something using OUTPUT or so
+        time.sleep(5)
+    elif t == "SC":
+        while 1:
+            empty = True
+
+            # Fetch output from the MV
+            response = responses.fetch(0)
+            if response is not None:
+                print("Output of MV to SC: " + str(response))
+                if response.name == "data_output":
+                    # Got output of MV, so forward to SCCD
+                    pipe.send(("input", response.parameters))
+                elif response.name == "result":
+                    # Finished execution, so continue and return result
+                    pipe.send(("terminate", []))
+                    pipe.close()
+                    return response.parameters[1]
+                else:
+                    raise Exception("Unknown data from MV to SC: " + str(response))
+                empty = False
+
+            # Fetch output from the SC
+            if pipe.poll():
+                response = pipe.recv()
+
+                if response.name == "output":
+                    controller.addInput(Event("data_input", "action_in", [response.parameters, context]))
+                else:
+                    raise Exception("Unknown data from SC to MV: " + str(response))
+                empty = False
+
+            if empty:
+                time.sleep(0.05)
+
+def __invoke(callback, model):
+    import multiprocessing
+    print("Invoked action!")
+    p = multiprocessing.Process(target=__run_new_modelverse, args=[controller.address, controller.username, controller.password, callback, model])
+    p.start()
+    p.join()
+    print("Invocation done")
+
+def _process_SC(statechart, port_sc, taskname):
+    import multiprocessing
+    p2c_pipe, c2p_pipe = multiprocessing.Pipe()
+    p = multiprocessing.Process(target=__run_new_modelverse_activity, args=[controller.address, controller.username, controller.password, taskname, c2p_pipe, None])
+    p.start()
     while 1:
         empty = True
 
-        # Fetch output from the MV
-        response = responses.fetch(0)
-        if response is not None:
-            print("Output of MV to SC")
-            if response.name == "data_output":
-                # Got output of MV, so forward to SCCD
-                statechart[0].addInput(Event("input", statechart[1], response.parameters))
-            elif response.name == "result":
-                # Finished execution, so continue and return result
-                statechart[0].addInput(Event("terminate", statechart[1], []))
-                return response.parameters[1]
-            else:
-                raise Exception("Unknown data from MV to SC: " + str(response))
+        if p2c_pipe.poll():
+            response = p2c_pipe.recv()
+            statechart[0].addInput(Event(response[0], statechart[1], response[1]))
+            
+            if response[0] == "terminate":
+                p2c_pipe.close()
+                break
             empty = False
 
-        # Fetch output from the SC
         response = port_sc.fetch(0)
         if response is not None:
-            print("Output of SC to MV")
-            if response.name == "output":
-                controller.addInput(Event("data_input", "action_in", [response.parameters, context]))
-            else:
-                raise Exception("Unknown data from SC to MV: " + str(response))
+            p2c_pipe.send(response)
             empty = False
 
         if empty:
-            time.sleep(0.5)
+            time.sleep(0.05)
+    p.join()
+
+def _process_OP(callback, taskname):
+    import multiprocessing
+    print("Running remote operation for taskname " + taskname)
+    p = multiprocessing.Process(target=__run_new_modelverse_activity, args=[controller.address, controller.username, controller.password, taskname, None, callback])
+    p.start()
+    p.join()
 
 def INPUT(action, context, parameters):
     controller.addInput(Event("action", "action_in", [action, _next_ID(), context, parameters]))
@@ -102,12 +172,12 @@ def OUTPUT():
                 print("Unknown error: " + str(response.parameters))
                 raise UnknownError()
 
-def init(address_param="127.0.0.1:8001", timeout=20.0):
+def init(address_param="127.0.0.1:8001", timeout=20.0, taskname=None):
     global controller
     global ID
     global responses
 
-    controller = modelverse_SCCD.Controller()
+    controller = modelverse_SCCD.Controller(taskname)
     socket2event.boot_translation_service(controller)
 
     ID = 0
@@ -124,6 +194,8 @@ def init(address_param="127.0.0.1:8001", timeout=20.0):
     return OUTPUT()
 
 def login(username, password):
+    controller.username = username
+    controller.password = password
     INPUT("login", None, [username, password])
     return OUTPUT()
 
@@ -173,31 +245,36 @@ def transformation_between(sources, targets):
 
 def transformation_add_MT(source_metamodels, target_metamodels, operation_name, code, callback=None):
     INPUT("transformation_add_MT", None, [source_metamodels, target_metamodels, operation_name, code, True])
-    context, model = OUTPUT()
+    model = OUTPUT()
+
     if callback is not None:
-        callback(context)
-    INPUT("exit", context, [])
+        __invoke(callback, model)
+    controller.addInput(Event("data_input", "action_in", [None, None]))
+
     return OUTPUT()
 
 def transformation_add_AL(source_metamodels, target_metamodels, operation_name, code, callback=None):
     INPUT("transformation_add_AL", None, [source_metamodels, target_metamodels, operation_name, code, True])
-    context, model = OUTPUT()
+    model = OUTPUT()
 
-    if context is None:
+    if model is None:
         # In case the source and target metamodels are empty, the context will be None, indicating that we are finished already (no callbacks allowed)
         return
 
     if callback is not None:
-        callback(context)
-    INPUT("exit", context, [])
+        __invoke(callback, model)
+    controller.addInput(Event("data_input", "action_in", [None, None]))
+
     return OUTPUT()
 
 def transformation_add_MANUAL(source_metamodels, target_metamodels, operation_name, callback=None):
     INPUT("transformation_add_MANUAL", None, [source_metamodels, target_metamodels, operation_name, True])
-    context, model = OUTPUT()
+    model = OUTPUT()
+
     if callback is not None:
-        callback(context)
-    INPUT("exit", context, [])
+        __invoke(callback, model)
+    controller.addInput(Event("data_input", "action_in", [None, None]))
+
     return OUTPUT()
 
 def __transformation_execute(operation_name, input_models_dict, output_models_dict, statechart, tracability_model, fetch_output):
@@ -205,13 +282,10 @@ def __transformation_execute(operation_name, input_models_dict, output_models_di
         port_sc = statechart[0].addOutputListener(statechart[2])
 
     INPUT("transformation_execute", None, [operation_name, input_models_dict, output_models_dict, tracability_model, fetch_output])
-    op, name, context = OUTPUT()
+    taskname = OUTPUT()
     if statechart is not None:
-        threading.Thread(target=_process_SC, args=[statechart, port_sc, context]).start()
-    else:
-        val = OUTPUT()
-        print("Transformation result: " + str(val))
-        return val
+        threading.Thread(target=_process_SC, args=[statechart, port_sc, taskname]).start()
+    return OUTPUT()
 
 def transformation_execute_MT(operation_name, input_models_dict, output_models_dict, statechart=None, tracability_model="", fetch_output=True):
     return __transformation_execute(operation_name, input_models_dict, output_models_dict, statechart, tracability_model, fetch_output)
@@ -221,10 +295,12 @@ def transformation_execute_AL(operation_name, input_models_dict, output_models_d
 
 def transformation_execute_MANUAL(operation_name, input_models_dict, output_models_dict, callback=None, tracability_model=""):
     INPUT("transformation_execute", None, [operation_name, input_models_dict, output_models_dict, tracability_model])
-    op, name, context, model = OUTPUT()
-    if callback is not None:
-        callback(context)
-    INPUT("exit", context, [])
+    taskname = OUTPUT()
+
+    print("Running manual task at " + str(taskname))
+    _process_OP(callback, taskname)
+    print("Process OP called")
+
     return OUTPUT()
 
 def transformation_signature(operation_name):
@@ -439,6 +515,10 @@ def get_taskname():
     """Fetch the taskname of the current connection."""
     return controller.taskname
 
+def exit_save(model_name):
+    INPUT("exit_save", None, [model_name])
+    return OUTPUT()
+
 """ Some hardcoded functions... Way easier to express them with code than with statecharts!"""
 import json
 import urllib

File diff suppressed because it is too large
+ 364 - 397
wrappers/modelverse_SCCD.py


+ 1 - 1
wrappers/poll_print.xml

@@ -35,7 +35,7 @@
 
             <state id="finished">
                 <script>
-                    print("FINISHED")
+                    print("FINISHED SC")
                 </script>
             </state>
         </scxml>