Browse Source

Working communication (mostly)

Yentl Van Tendeloo 8 years ago
parent
commit
2a684b6a48

+ 74 - 33
bootstrap/core_algorithm.alc

@@ -354,6 +354,22 @@ String function get_model_id(name : String):
 	
 	return ""!
 
+String function get_service_id(name : String):
+	Element services
+	String service
+
+	services = allInstances(core, "Service")
+
+	log("Search " + name)
+	while (read_nr_out(services) > 0):
+		service = set_pop(services)
+		log("Check " + cast_v2s(read_attribute(core, service, "name")))
+		if (value_eq(read_attribute(core, service, "name"), name)):
+			log("Match!")
+			return service!
+	
+	return ""!
+
 String function get_user_id(name : String):
 	Element users
 	String user
@@ -503,6 +519,8 @@ Element function execute_operation(operation_id : String, input_models : Element
 		if (bool_and(read_nr_out(input_models) == 1, read_nr_out(output_models) == 0)):
 			// Just skip the merge...
 			merged_model = model_copy(get_full_model(get_model_id(read_edge_dst(read_out(input_models, 0)))))
+		elif (bool_and(read_nr_out(input_models) == 0, read_nr_out(output_models) == 0)):
+			merged_model = read_root()
 		else:
 			log("Could not resolve intermediate merged metamodel")
 			output("Could not resolve intermediate merged metamodel")
@@ -1173,9 +1191,6 @@ String function transformation_add(user_id : String, source_models : Element, ta
 	type_id = ""
 	old_type_id = ""
 
-	if (bool_and(read_nr_out(source_models) == 0, read_nr_out(target_models) == 0)):
-		return "Cannot create transformation without input or output"!
-
 	keys = dict_keys(source_models)
 	while (read_nr_out(keys) > 0):
 		key = set_pop(keys)
@@ -1229,8 +1244,9 @@ String function transformation_add(user_id : String, source_models : Element, ta
 	if (get_model_id(operation_name) == ""):
 		// Write out a merged metamodel containing all these models: this is the MM for the manual operation
 		// New location is available, so write
-		merged_formalism = model_fuse(set_copy(formalism_map))
-		modify(merged_formalism, True)
+		if (bool_not(bool_and(read_nr_out(source_models) == 0, read_nr_out(target_models) == 0))):
+			merged_formalism = model_fuse(set_copy(formalism_map))
+			modify(merged_formalism, True)
 
 		if (operation_type == "manual"):
 			// Finished with all information, now create the model itself!
@@ -1244,34 +1260,35 @@ String function transformation_add(user_id : String, source_models : Element, ta
 			model_create(import_node("AL/" + operation_name), operation_name, user_id, get_model_id("ActionLanguage"), "ActionLanguage")
 			model_id = get_model_id(operation_name)
 
-		model_create(merged_formalism, "__merged_" + operation_name, user_id, type_id, "Model")
-		merged_formalism_id = get_model_id("__merged_" + operation_name)
-
-		// Add tracability links at this level
-		while (read_nr_out(all_formalisms) > 0):
-			source_formalism_id = set_pop(all_formalisms)
-			tracability_link = instantiate_link(core, "tracability", "", merged_formalism_id, source_formalism_id)
-			instantiate_attribute(core, tracability_link, "type", "merged")
-
-		tracability_link = instantiate_link(core, "tracability", "", model_id, merged_formalism_id)
-		instantiate_attribute(core, tracability_link, "type", "operatesOn")
-
-		// Extend metadata with info on source and target
-		String link
-		String dst
-
-		keys = dict_keys(source)
-		while (read_nr_out(keys) > 0):
-			key = set_pop(keys)
-			link = instantiate_link(core, "transformInput", "", model_id, source[key])
-			instantiate_attribute(core, link, "name", key)
-
-		keys = dict_keys(target)
-		while (read_nr_out(keys) > 0):
-			key = set_pop(keys)
-			link = instantiate_link(core, "transformOutput", "", model_id, target[key])
-			instantiate_attribute(core, link, "name", key)
-			
+		if (bool_not(bool_and(read_nr_out(source_models) == 0, read_nr_out(target_models) == 0))):
+			model_create(merged_formalism, "__merged_" + operation_name, user_id, type_id, "Model")
+			merged_formalism_id = get_model_id("__merged_" + operation_name)
+
+			// Add tracability links at this level
+			while (read_nr_out(all_formalisms) > 0):
+				source_formalism_id = set_pop(all_formalisms)
+				tracability_link = instantiate_link(core, "tracability", "", merged_formalism_id, source_formalism_id)
+				instantiate_attribute(core, tracability_link, "type", "merged")
+
+			tracability_link = instantiate_link(core, "tracability", "", model_id, merged_formalism_id)
+			instantiate_attribute(core, tracability_link, "type", "operatesOn")
+
+			// Extend metadata with info on source and target
+			String link
+			String dst
+
+			keys = dict_keys(source)
+			while (read_nr_out(keys) > 0):
+				key = set_pop(keys)
+				link = instantiate_link(core, "transformInput", "", model_id, source[key])
+				instantiate_attribute(core, link, "name", key)
+
+			keys = dict_keys(target)
+			while (read_nr_out(keys) > 0):
+				key = set_pop(keys)
+				link = instantiate_link(core, "transformOutput", "", model_id, target[key])
+				instantiate_attribute(core, link, "name", key)
+				
 		return "Success"!
 	else:
 		return "Model exists: " + operation_name!
@@ -1705,6 +1722,28 @@ String function cmd_admin_demote(user_id : String, other_user_name : String):
 	else:
 		return "Permission denied to administrate: " + other_user_name!
 
+String function cmd_service_register(user_id : String, service_name : String):
+	// Active a service for this specific user
+	if (get_service_id(service_name) == ""):
+		String service
+		service = instantiate_node(core, "Service", "")
+		instantiate_attribute(core, service, "name", service_name)
+		instantiate_attribute(core, service, "port", get_taskname())
+		output("Success: " + get_taskname())
+
+		// Wait until we can stop the service
+		log("Waiting for service_stop")
+		while (cast_v2s(input()) != "\"service_stop\""):
+			output("Service is running on this task: stop it by sending 'service_stop'")
+		log("Finished")
+
+		model_delete_element(core, service)
+
+		// Service terminated
+		return "Success"!
+	else:
+		return "Service already exists: " + service_name!
+
 Void function user_function_skip_init(user_id : String):
 	String cmd
 	String result
@@ -1774,6 +1813,8 @@ Void function user_function_skip_init(user_id : String):
 			output(cmd_admin_promote(user_id, single_input("User name?")))
 		elif (cmd == "admin_demote"):
 			output(cmd_admin_demote(user_id, single_input("User name?")))
+		elif (cmd == "service_register"):
+			output(cmd_service_register(user_id, single_input("Service name?")))
 		elif (cmd == "verbose"):
 			set_verbose(True)
 		elif (cmd == "quiet"):

+ 1 - 0
bootstrap/core_formalism.mvc

@@ -131,6 +131,7 @@ SimpleClassDiagrams CoreFormalism {
 
     Class Service {
         name : String
+        port : String
     }
 }
 

+ 1 - 0
bootstrap/initial_code_task.alc

@@ -18,5 +18,6 @@ Void mutable function __main():
 	exec(root["bootstrap/conformance_scd.alc"]["initializers"])
 	exec(root["bootstrap/random.alc"]["initializers"])
 	exec(root["bootstrap/utils.alc"]["initializers"])
+	exec(root["bootstrap/services.alc"]["initializers"])
 	new_task()
 	return!

+ 19 - 1
bootstrap/services.alc

@@ -1,5 +1,8 @@
 include "primitives.alh"
 include "utils.alh"
+include "core_algorithm.alh"
+include "modelling.alh"
+include "object_operations.alh"
 
 Integer services = 0
 
@@ -13,7 +16,7 @@ String function comm_newPort():
 	String attempt
 	attempt = "__hierarchy"
 	while (dict_in(root, attempt)):
-		attempt = "__" + cast_v2s(get_taskname()) + "_" + cast_v2s(services)
+		attempt = (("__" + get_taskname()) + "_") + cast_v2s(services)
 		services = services + 1
 
 	// Create queues
@@ -59,3 +62,18 @@ Element function comm_get(comm : String):
 	dict_overwrite(root, "input", root["input"]["next"])
 
 	return value!
+
+String function comm_connect(service : String):
+	// Connect to an existing service
+	log("Resolving service location for " + cast_e2s(service))
+	service = get_service_id(service)
+	log("Resolved service ID: " + service)
+	service = read_attribute(core, service, "port")
+	log("Resolved port: " + service)
+
+	String port
+	port = comm_newPort()
+	log("Request new port: " + port)
+	comm_set(service, port)
+	log("Communication OK")
+	return port!

+ 1 - 0
bootstrap/utils.alc

@@ -123,4 +123,5 @@ Void function set_difference(set1 : Element, set2 : Element):
 	return!
 
 String function get_taskname():
+	log("Taskname is: " + reverseKeyLookup(read_root(), read_taskroot()))
 	return reverseKeyLookup(read_root(), read_taskroot())!

+ 2 - 0
interface/HUTN/includes/core_algorithm.alh

@@ -1,2 +1,4 @@
 Void function initialize_core()
 Void function new_task()
+String function get_service_id(name : String)
+Element core

+ 1 - 0
interface/HUTN/includes/services.alh

@@ -2,3 +2,4 @@ String function comm_newPort()
 Boolean function comm_hasInput(comm : String)
 Void function comm_set(comm : String, value : Element)
 Element function comm_get(comm : String)
+String function comm_connect(service : String)

+ 72 - 24
wrappers/modelverse.py

@@ -5,6 +5,7 @@ import random
 from urllib2 import URLError
 import sys
 import time
+import threading
 
 COMPILER_PATH = "interface/HUTN"
 
@@ -14,6 +15,7 @@ MODE_MODELLING = 2
 MODE_MODIFY = 3
 MODE_DIALOG = 4
 MODE_MANUAL = 5
+MODE_SERVICE = 6
 
 # Bind to the compiler (might have to update path manually!)
 sys.path.append(COMPILER_PATH)
@@ -99,16 +101,18 @@ def _goto_mode(new_mode, model_name=None):
         # Go to a mode that we have no automatic transfer to: raise exception
         raise InvalidMode("Required mode: %s, current mode: %s" % (new_mode, mode))
 
-def _input(value):
+def _input(value, port=None):
     # Ugly json encoding of primitives
     #print("[IN] %s" % value)
+    if port is None:
+        port = taskname
     if isinstance(value, type([])):
         value = json.dumps(value)
-        urllib2.urlopen(urllib2.Request(address, urllib.urlencode({"op": "set_input", "data": value, "taskname": taskname}))).read()
+        urllib2.urlopen(urllib2.Request(address, urllib.urlencode({"op": "set_input", "data": value, "taskname": port}))).read()
     else:
         value = json.dumps(value)
         #print("Set input: " + str(value))
-        urllib2.urlopen(urllib2.Request(address, urllib.urlencode({"op": "set_input", "value": value, "taskname": taskname}))).read()
+        urllib2.urlopen(urllib2.Request(address, urllib.urlencode({"op": "set_input", "value": value, "taskname": port}))).read()
 
 def _input_raw(value, taskname):
     # Ugly json encoding of primitives
@@ -147,10 +151,12 @@ def _compile_model(code):
 
     return do_compile(".model.mvc", COMPILER_PATH + "/grammars/modelling.g", "M") + ["exit"]
 
-def _output(expected=None):
+def _output(expected=None,port=None):
+    if port is None:
+        port = taskname
     try:
         global last_output
-        last_output = json.loads(urllib2.urlopen(urllib2.Request(address, urllib.urlencode({"op": "get_output", "taskname": taskname}))).read())
+        last_output = json.loads(urllib2.urlopen(urllib2.Request(address, urllib.urlencode({"op": "get_output", "taskname": port}))).read())
         #print("[OUT] %s" % last_output)
     except:
         raise UnknownError()
@@ -447,11 +453,12 @@ def transformation_add_MT(source_metamodels, target_metamodels, operation_name,
     _input(["transformation_add_MT"] + mv_dict_rep + [operation_name])
 
     # Possibly modify the merged metamodel first (add tracability links)
-    mode = MODE_MANUAL
-    _output() # Model loaded, ready for commands
-    callback()
-    _input("exit")
-    mode = MODE_MODELLING
+    if len(source_metamodels) + len(target_metamodels) > 0:
+        mode = MODE_MANUAL
+        _output("Model loaded, ready for commands!")
+        callback()
+        _input("exit")
+        mode = MODE_MODELLING
 
     # Done, so RAMify and upload the model
     _handle_output("Waiting for model constructors...")
@@ -472,11 +479,12 @@ def transformation_add_AL(source_metamodels, target_metamodels, operation_name,
     _input(["transformation_add_AL"] + mv_dict_rep + [operation_name])
 
     # Possibly modify the merged metamodel first (add tracability links)
-    mode = MODE_MANUAL
-    _output() # Model loaded, ready for commands
-    callback()
-    _input("exit")
-    mode = MODE_MODELLING
+    if len(source_metamodels) + len(target_metamodels) > 0:
+        mode = MODE_MANUAL
+        _output("Model loaded, ready for commands!")
+        callback()
+        _input("exit")
+        mode = MODE_MODELLING
 
     _handle_output("Waiting for code constructors...")
     _input(compiled)
@@ -491,11 +499,12 @@ def transformation_add_MANUAL(source_metamodels, target_metamodels, operation_na
     _input(["transformation_add_MANUAL"] + mv_dict_rep + [operation_name])
 
     # Possibly modify the merged metamodel first (add tracability links)
-    mode = MODE_MANUAL
-    _output() # Model loaded, ready for commands
-    callback()
-    _input("exit")
-    mode = MODE_MODELLING
+    if len(source_metamodels) + len(target_metamodels) > 0:
+        mode = MODE_MANUAL
+        _output("Model loaded, ready for commands!")
+        callback()
+        _input("exit")
+        mode = MODE_MODELLING
 
     _handle_output("Success")
 
@@ -534,8 +543,8 @@ def transformation_execute_MANUAL(operation_name, input_models_dict, output_mode
     _handle_output("Success: ready for MANUAL execution")
 
     # Skip over the begin of mini_modify
-    _output() # Please perform manual operation X
-    _output() # Model loaded, ready for commands
+    _handle_output("Please perform manual operation ")
+    _output("Model loaded, ready for commands!")
 
     # We are now executing, so everything we get is part of the dialog, except if it is the string for transformation termination
     mode = MODE_MANUAL
@@ -617,8 +626,8 @@ def process_execute(process_name, prefix, callbacks):
                         if reply is not None:
                             _input(reply)
                 elif t == "ManualOperation":
-                    _output() # Please perform manual operation X
-                    _output() # Model loaded, ready for commands
+                    _handle_output("Please perform manual operation ")
+                    _output("Model loaded, ready for commands!")
                     mode = MODE_MANUAL
                     callback()
                     _input("exit")
@@ -935,3 +944,42 @@ def model_exit():
     _input("exit")
     _output("Success")
     mode = MODE_MODELLING
+
+def service_register(name, function):
+    """Register a function as a service with a specific name."""
+
+    def service_process(port):
+        while 1:
+            thrd = threading.Thread(target=function, args=[service_get(port)])
+            thrd.daemon = True
+            thrd.start()
+
+    global mode
+    _goto_mode(MODE_MODELLING)
+
+    # return None
+    _input(["service_register", name])
+
+    # Now we are in service-mode
+    mode = MODE_SERVICE
+    port = _handle_output("Success: ", split=" ")
+
+    # Process events in the background!
+    threading.Thread(target=service_process, args=[port]).start()
+
+def service_stop():
+    """Stop the currently executing process."""
+    _goto_mode(MODE_SERVICE)
+    _input("service_stop")
+    _handle_output("Success")
+
+    global mode
+    mode = MODE_MODELLING
+
+def service_get(port):
+    """Get the values on the specified port."""
+    return _output(port=port)
+
+def service_set(port, value):
+    """Set a value on a specified port."""
+    _input(value, port=port)