|
@@ -1,13 +1,13 @@
|
|
|
import urllib
|
|
|
+import urllib2
|
|
|
import json
|
|
|
import random
|
|
|
+from urllib2 import URLError
|
|
|
import sys
|
|
|
import time
|
|
|
import threading
|
|
|
-import uuid
|
|
|
|
|
|
-import sccd.runtime.socket2event as socket2event
|
|
|
-from sccd.runtime.statecharts_core import Event
|
|
|
+COMPILER_PATH = "interface/HUTN"
|
|
|
|
|
|
MODE_UNCONNECTED = 0
|
|
|
MODE_UNAUTHORIZED = 1
|
|
@@ -17,6 +17,10 @@ MODE_DIALOG = 4
|
|
|
MODE_MANUAL = 5
|
|
|
MODE_SERVICE = 6
|
|
|
|
|
|
+# Bind to the compiler (might have to update path manually!)
|
|
|
+sys.path.append(COMPILER_PATH)
|
|
|
+from hutn_compiler.compiler import main as do_compile
|
|
|
+
|
|
|
# Exceptions
|
|
|
class ModelverseException(Exception):
|
|
|
pass
|
|
@@ -56,60 +60,12 @@ class UnknownMetamodellingHierarchy(ModelverseException):
|
|
|
|
|
|
# Helper functions and configuration: do not use yourself!
|
|
|
taskname = None
|
|
|
+address = None
|
|
|
+last_output = None
|
|
|
mode = MODE_UNCONNECTED
|
|
|
prev_mode = None
|
|
|
current_model = None
|
|
|
registered_metamodels = {}
|
|
|
-outputs = {}
|
|
|
-ctrl_input = None
|
|
|
-ctrl_output = None
|
|
|
-
|
|
|
-def _output_thread(controller, outp, task):
|
|
|
- req_out = controller.addOutputListener("request_out")
|
|
|
- my_id = str(uuid.uuid4())
|
|
|
-
|
|
|
- try:
|
|
|
- while 1:
|
|
|
- controller.addInput(Event("HTTP_input", "request_in", [urllib.urlencode({"op": "get_output", "taskname": task}), my_id]))
|
|
|
- event = req_out.fetch(-1)
|
|
|
-
|
|
|
- print("Got event in coded: " + str(event))
|
|
|
- if event.parameters[1] == my_id:
|
|
|
- outp[task].append(json.loads(event.parameters[0]))
|
|
|
- except:
|
|
|
- raise
|
|
|
-
|
|
|
-def _exec_on_statechart(statechart):
|
|
|
- def _exec_sc(controller, inport, outport):
|
|
|
- global taskname
|
|
|
- op = controller.addOutputListener(outport)
|
|
|
-
|
|
|
- while 1:
|
|
|
- if len(outputs[taskname]) > 1:
|
|
|
- # Is an output message of the Mv, so put it in the SC
|
|
|
- del outputs[taskname][0]
|
|
|
- output_event = outputs[taskname][0]
|
|
|
-
|
|
|
- if output_event == "Success" or output_event == "Failure":
|
|
|
- # Is a stop event!
|
|
|
- controller.addInput(Event("terminate", inport, []))
|
|
|
- break
|
|
|
- else:
|
|
|
- # Is just a normal event!
|
|
|
- controller.addInput(Event("input", inport, [output_event]))
|
|
|
-
|
|
|
- input_event = op.fetch(0)
|
|
|
- if input_event is not None:
|
|
|
- # Expand the event and make it HTTP input
|
|
|
- _input(input_event.parameters)
|
|
|
-
|
|
|
- time.sleep(0.02)
|
|
|
-
|
|
|
- thrd = threading.Thread(target=_exec_sc, args=statechart)
|
|
|
- thrd.daemon = True
|
|
|
- thrd.start()
|
|
|
-
|
|
|
- return None
|
|
|
|
|
|
def _get_metamodel(model):
|
|
|
global registered_metamodels
|
|
@@ -158,47 +114,77 @@ 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, task=None):
|
|
|
+def _input(value, port=None):
|
|
|
# Ugly json encoding of primitives
|
|
|
#print("[IN] %s" % value)
|
|
|
- if task is None:
|
|
|
- task = taskname
|
|
|
+ if port is None:
|
|
|
+ port = taskname
|
|
|
if isinstance(value, type([])):
|
|
|
value = json.dumps(value)
|
|
|
- ctrl_input.addInput(Event("HTTP_input", "request_in", [urllib.urlencode({"op": "set_input", "taskname": task, "data": value}), None]))
|
|
|
+ urllib2.urlopen(urllib2.Request(address, urllib.urlencode({"op": "set_input", "data": value, "taskname": port}))).read()
|
|
|
else:
|
|
|
value = json.dumps(value)
|
|
|
- ctrl_input.addInput(Event("HTTP_input", "request_in", [urllib.urlencode({"op": "set_input", "taskname": task, "value": value}), None]))
|
|
|
+ #print("Set input: " + str(value))
|
|
|
+ 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
|
|
|
- ctrl_input.addInput(Event("HTTP_input", "request_in", [urllib.urlencode({"op": "set_input", "taskname": taskname, "value": value}), None]))
|
|
|
-
|
|
|
-def _output(expected=None, task=None):
|
|
|
- if task is None:
|
|
|
- task = taskname
|
|
|
-
|
|
|
+ urllib2.urlopen(urllib2.Request(address, urllib.urlencode({"op": "set_input", "value": value, "taskname": taskname}))).read()
|
|
|
+
|
|
|
+ #TODO check that this is actually a Modelverse!
|
|
|
+
|
|
|
+def _compile_AL(code):
|
|
|
+ # Compile an action language file and send the compiled code
|
|
|
+ code_fragments = code.split("\n")
|
|
|
+ code_fragments = [i for i in code_fragments if i.strip() != ""]
|
|
|
+ code_fragments = [i.replace(" ", "\t") for i in code_fragments]
|
|
|
+ initial_tabs = min([len(i) - len(i.lstrip("\t")) for i in code_fragments])
|
|
|
+ code_fragments = [i[initial_tabs:] for i in code_fragments]
|
|
|
+ code_fragments.append("")
|
|
|
+ code = "\n".join(code_fragments)
|
|
|
+
|
|
|
+ with open(".code.alc", "w") as f:
|
|
|
+ f.write(code)
|
|
|
+ f.flush()
|
|
|
+
|
|
|
+ compiled = do_compile(".code.alc", COMPILER_PATH + "/grammars/actionlanguage.g", "CS")
|
|
|
+ return compiled
|
|
|
+
|
|
|
+def _compile_model(code):
|
|
|
+ # Compile a model and send the compiled graph
|
|
|
+ # First change multiple spaces to a tab
|
|
|
+ code_fragments = code.split("\n")
|
|
|
+ code_fragments = [i for i in code_fragments if i.strip() != ""]
|
|
|
+ code_fragments = [i.replace(" ", "\t") for i in code_fragments]
|
|
|
+ initial_tabs = min([len(i) - len(i.lstrip("\t")) for i in code_fragments])
|
|
|
+ code_fragments = [i[initial_tabs:] for i in code_fragments]
|
|
|
+ code_fragments.append("")
|
|
|
+ code = "\n".join(code_fragments)
|
|
|
+
|
|
|
+ with open(".model.mvc", "w") as f:
|
|
|
+ f.write(code)
|
|
|
+ f.flush()
|
|
|
+
|
|
|
+ return do_compile(".model.mvc", COMPILER_PATH + "/grammars/modelling.g", "M")
|
|
|
+
|
|
|
+def _output(expected=None,port=None):
|
|
|
+ if port is None:
|
|
|
+ port = taskname
|
|
|
try:
|
|
|
- while len(outputs[task]) < 2:
|
|
|
- time.sleep(0.02)
|
|
|
-
|
|
|
- del outputs[task][0]
|
|
|
- #print("[OUT] %s" % outputs[0])
|
|
|
+ global last_output
|
|
|
+ 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()
|
|
|
+ if expected is not None and last_output != expected:
|
|
|
+ raise InterfaceMismatch(_last_output(), expected)
|
|
|
+ return last_output
|
|
|
|
|
|
- if expected is not None and _last_output(task) != expected:
|
|
|
- raise InterfaceMismatch(_last_output(task), expected)
|
|
|
- return _last_output(task)
|
|
|
-
|
|
|
-def _last_output(task=None):
|
|
|
- if task is None:
|
|
|
- task = taskname
|
|
|
-
|
|
|
- return outputs[task][0]
|
|
|
+def _last_output():
|
|
|
+ return last_output
|
|
|
|
|
|
# Raise common exceptions
|
|
|
-def _handle_output(requested=None, split=False):
|
|
|
+def _handle_output(requested=None, split=None):
|
|
|
value = _output()
|
|
|
if value.startswith("Model exists: "):
|
|
|
raise ModelExists(value.split(": ", 1)[1])
|
|
@@ -213,14 +199,14 @@ def _handle_output(requested=None, split=False):
|
|
|
elif value.startswith("Attribute not found: "):
|
|
|
raise NoSuchAttribute(value.split(": ", 1)[1])
|
|
|
elif requested is not None and value.startswith(requested):
|
|
|
- if not split:
|
|
|
+ if split is None:
|
|
|
return value
|
|
|
else:
|
|
|
- splitted = value.strip().split(" ", 1)
|
|
|
- if len(splitted) > 1:
|
|
|
- return splitted[1].split("\n")
|
|
|
+ splitted = value.strip().split(split, 1)
|
|
|
+ if len(splitted) == 1:
|
|
|
+ return ""
|
|
|
else:
|
|
|
- return []
|
|
|
+ return splitted[1].rstrip()
|
|
|
else:
|
|
|
raise InterfaceMismatch(value)
|
|
|
|
|
@@ -265,75 +251,25 @@ def alter_context(model_name, metamodel_name):
|
|
|
global registered_metamodels
|
|
|
registered_metamodels[model_name] = metamodel_name
|
|
|
|
|
|
-def _start_http_client(addr, port, timeout):
|
|
|
- import http_client
|
|
|
- ctrl = http_client.Controller()
|
|
|
- listener = ctrl.addOutputListener("request_out")
|
|
|
- socket2event.boot_translation_service(ctrl)
|
|
|
- thrd = threading.Thread(target=ctrl.start)
|
|
|
- thrd.daemon = True
|
|
|
- thrd.start()
|
|
|
-
|
|
|
- evt = listener.fetch(-1)
|
|
|
- if evt.name != "http_client_initialized":
|
|
|
- raise Exception("HTTP client did not behave as expected during init: " + str(evt.name))
|
|
|
-
|
|
|
- ctrl.addInput(Event("connect", "request_in", [(addr, port), timeout]))
|
|
|
-
|
|
|
- evt = listener.fetch(-1)
|
|
|
-
|
|
|
- if evt.name == "http_client_timeout":
|
|
|
- raise Exception("HTTP client timeout")
|
|
|
- if evt.name != "http_client_ready":
|
|
|
- raise Exception("HTTP client did not behave as expected during connect: " + str(evt.name))
|
|
|
-
|
|
|
- return ctrl
|
|
|
-
|
|
|
# Main MvC operations
|
|
|
def init(address_param="127.0.0.1:8001", timeout=20.0):
|
|
|
"""Starts up the connection to the Modelverse."""
|
|
|
- # Start up the HTTP Client SC
|
|
|
- global ctrl_input
|
|
|
- global ctrl_output
|
|
|
-
|
|
|
- if ctrl_input is not None:
|
|
|
- ctrl_input.stop()
|
|
|
- if ctrl_output is not None:
|
|
|
- ctrl_output.stop()
|
|
|
-
|
|
|
- global address
|
|
|
- global port
|
|
|
-
|
|
|
- address, port = address_param.split(":", 1)
|
|
|
- port = int(port)
|
|
|
-
|
|
|
- ctrl_input = _start_http_client(address, port, timeout)
|
|
|
- ctrl_output = _start_http_client(address, port, timeout)
|
|
|
- controllers = [ctrl_input, ctrl_output]
|
|
|
-
|
|
|
global mode
|
|
|
- start_time = time.time()
|
|
|
- task = str(random.random())
|
|
|
-
|
|
|
- _input_raw('"%s"' % task, "task_manager")
|
|
|
-
|
|
|
- mode = MODE_UNAUTHORIZED
|
|
|
-
|
|
|
- global outputs
|
|
|
+ global address
|
|
|
global taskname
|
|
|
- taskname = task
|
|
|
- outputs = {}
|
|
|
-
|
|
|
- _listen_to_output(ctrl_output, task)
|
|
|
-
|
|
|
-def _listen_to_output(controller, task):
|
|
|
- global outputs
|
|
|
- outputs[task] = [None]
|
|
|
-
|
|
|
- # This re-assign also diconnects the previous get_output connections to the outputs variable
|
|
|
- thrd = threading.Thread(target=_output_thread, args=[controller, outputs, task])
|
|
|
- thrd.daemon = True
|
|
|
- thrd.start()
|
|
|
+ address = "http://%s" % address_param
|
|
|
+ start_time = time.time()
|
|
|
+ taskname = random.random()
|
|
|
+ while 1:
|
|
|
+ try:
|
|
|
+ _input_raw('"%s"' % taskname, "task_manager")
|
|
|
+ mode = MODE_UNAUTHORIZED
|
|
|
+ break
|
|
|
+ except URLError as e:
|
|
|
+ if time.time() - start_time > timeout:
|
|
|
+ raise ConnectionError(e.reason)
|
|
|
+ else:
|
|
|
+ time.sleep(0.1)
|
|
|
|
|
|
def login(username, password):
|
|
|
"""Log in a user, if user doesn't exist, it is created."""
|
|
@@ -369,20 +305,34 @@ def login(username, password):
|
|
|
else:
|
|
|
raise InterfaceMismatch(_last_output())
|
|
|
|
|
|
-def model_add(model_name, metamodel_name, model_code=""):
|
|
|
+def model_add(model_name, metamodel_name, model_code=None):
|
|
|
"""Instantiate a new model."""
|
|
|
_goto_mode(MODE_MODELLING)
|
|
|
|
|
|
+ # Do this before creating the model, as otherwise compilation errors would make us inconsistent
|
|
|
+ if model_code is not None:
|
|
|
+ try:
|
|
|
+ compiled = _compile_model(model_code)
|
|
|
+ except Exception as e:
|
|
|
+ raise CompilationError(e)
|
|
|
+ else:
|
|
|
+ compiled = [0]
|
|
|
+
|
|
|
_input(["model_add", metamodel_name, model_name])
|
|
|
_handle_output("Waiting for model constructors...")
|
|
|
- _input(model_code)
|
|
|
+ _input(compiled)
|
|
|
_output("Success")
|
|
|
|
|
|
global registered_metamodels
|
|
|
registered_metamodels[model_name] = metamodel_name
|
|
|
|
|
|
def upload_code(code):
|
|
|
- _input(code)
|
|
|
+ try:
|
|
|
+ compiled = _compile_AL(code)
|
|
|
+ except Exception as e:
|
|
|
+ raise CompilationError(e)
|
|
|
+
|
|
|
+ _input(compiled)
|
|
|
|
|
|
def model_delete(model_name):
|
|
|
"""Delete an existing model."""
|
|
@@ -395,16 +345,19 @@ def model_list(location):
|
|
|
"""List all models."""
|
|
|
_goto_mode(MODE_MODELLING)
|
|
|
_input(["model_list", location])
|
|
|
- return set(_handle_output("Success: ", split=True))
|
|
|
+ return set(_handle_output("Success: ", split=" ").split("\n"))
|
|
|
|
|
|
def model_list_full(location):
|
|
|
"""List full information on all models."""
|
|
|
_goto_mode(MODE_MODELLING)
|
|
|
_input(["model_list_full", location])
|
|
|
- output = _handle_output("Success: ", split=True)
|
|
|
+ output = _handle_output("Success: ", split=" ")
|
|
|
+ if output == "":
|
|
|
+ return set([])
|
|
|
|
|
|
lst = set([])
|
|
|
- for v in output:
|
|
|
+ value = output.strip().split("\n")
|
|
|
+ for v in value:
|
|
|
m = v.strip()
|
|
|
perm, own, grp, m = m.split(" ", 3)
|
|
|
lst.add((m, own, grp, perm))
|
|
@@ -419,15 +372,23 @@ def verify(model_name, metamodel_name=None):
|
|
|
metamodel_name = _get_metamodel(model_name)
|
|
|
|
|
|
_input(["verify", model_name, metamodel_name])
|
|
|
- return _handle_output("Success: ", split=True)[0]
|
|
|
+ return _handle_output("Success: ", split=" ")
|
|
|
|
|
|
-def model_overwrite(model_name, new_model="", metamodel_name=None):
|
|
|
+def model_overwrite(model_name, new_model=None, metamodel_name=None):
|
|
|
"""Upload a new model and overwrite an existing model."""
|
|
|
_goto_mode(MODE_MODIFY, model_name)
|
|
|
|
|
|
+ if new_model is not None:
|
|
|
+ try:
|
|
|
+ compiled = _compile_model(new_model)
|
|
|
+ except Exception as e:
|
|
|
+ raise CompilationError(e)
|
|
|
+ else:
|
|
|
+ compiled = [0]
|
|
|
+
|
|
|
_input("upload")
|
|
|
_handle_output("Waiting for model constructors...")
|
|
|
- _input(new_model)
|
|
|
+ _input(compiled)
|
|
|
_output("Success")
|
|
|
|
|
|
if metamodel_name is not None:
|
|
@@ -453,19 +414,30 @@ def model_render(model_name, mapper_name):
|
|
|
_goto_mode(MODE_MODELLING)
|
|
|
|
|
|
_input(["model_render", model_name, mapper_name])
|
|
|
- return json.loads(_handle_output("Success: ", split=True)[0])
|
|
|
+ return json.loads(_handle_output("Success: ", split=" "))
|
|
|
|
|
|
def transformation_between(source, target):
|
|
|
_goto_mode(MODE_MODELLING)
|
|
|
|
|
|
_input(["transformation_between", source, target])
|
|
|
- output = _handle_output("Success: ", split=True)
|
|
|
- return set(output)
|
|
|
+ output = _handle_output("Success: ", split=" ")
|
|
|
+ if output == "":
|
|
|
+ return set([])
|
|
|
+ return set([v for v in output.split("\n")])
|
|
|
|
|
|
def transformation_add_MT(source_metamodels, target_metamodels, operation_name, code, callback=lambda: None):
|
|
|
"""Create a new model transformation."""
|
|
|
global mode
|
|
|
_goto_mode(MODE_MODELLING)
|
|
|
+ import time
|
|
|
+
|
|
|
+ start = time.time()
|
|
|
+ try:
|
|
|
+ compiled = _compile_model(code)
|
|
|
+ except Exception as e:
|
|
|
+ raise CompilationError(e)
|
|
|
+ #print("Compilation took: %ss" % (time.time() - start))
|
|
|
+ start = time.time()
|
|
|
|
|
|
mv_dict_rep = _dict_to_list(source_metamodels) + [""] + _dict_to_list(target_metamodels) + [""]
|
|
|
_input(["transformation_add_MT"] + mv_dict_rep + [operation_name])
|
|
@@ -477,17 +449,25 @@ def transformation_add_MT(source_metamodels, target_metamodels, operation_name,
|
|
|
callback()
|
|
|
_input("exit")
|
|
|
mode = MODE_MODELLING
|
|
|
+ #print("Callbacks took: %ss" % (time.time() - start))
|
|
|
+ start = time.time()
|
|
|
|
|
|
# Done, so RAMify and upload the model
|
|
|
_handle_output("Waiting for model constructors...")
|
|
|
- _input(code)
|
|
|
+ _input(compiled)
|
|
|
_handle_output("Success")
|
|
|
+ #print("Upload and RAMify took: %ss" % (time.time() - start))
|
|
|
|
|
|
def transformation_add_AL(source_metamodels, target_metamodels, operation_name, code, callback=lambda: None):
|
|
|
"""Create a new action language model, which can be executed."""
|
|
|
global mode
|
|
|
_goto_mode(MODE_MODELLING)
|
|
|
|
|
|
+ try:
|
|
|
+ compiled = _compile_AL(code)
|
|
|
+ except Exception as e:
|
|
|
+ raise CompilationError(e)
|
|
|
+
|
|
|
mv_dict_rep = _dict_to_list(source_metamodels) + [""] + _dict_to_list(target_metamodels) + [""]
|
|
|
_input(["transformation_add_AL"] + mv_dict_rep + [operation_name])
|
|
|
|
|
@@ -500,7 +480,7 @@ def transformation_add_AL(source_metamodels, target_metamodels, operation_name,
|
|
|
mode = MODE_MODELLING
|
|
|
|
|
|
_handle_output("Waiting for code constructors...")
|
|
|
- _input(code)
|
|
|
+ _input(compiled)
|
|
|
_output("Success")
|
|
|
|
|
|
def transformation_add_MANUAL(source_metamodels, target_metamodels, operation_name, callback=lambda: None):
|
|
@@ -521,7 +501,7 @@ def transformation_add_MANUAL(source_metamodels, target_metamodels, operation_na
|
|
|
|
|
|
_handle_output("Success")
|
|
|
|
|
|
-def transformation_execute_AL(operation_name, input_models_dict, output_models_dict, statechart=None):
|
|
|
+def transformation_execute_AL(operation_name, input_models_dict, output_models_dict, callback=lambda i: None):
|
|
|
"""Execute an existing model operation."""
|
|
|
global mode
|
|
|
_goto_mode(MODE_MODELLING)
|
|
@@ -531,21 +511,19 @@ def transformation_execute_AL(operation_name, input_models_dict, output_models_d
|
|
|
_input(["transformation_execute", operation_name] + mv_dict_rep)
|
|
|
_handle_output("Success: ready for AL execution")
|
|
|
|
|
|
- if statechart is not None:
|
|
|
- # We are to delegate this information to another statechart, which wants interaction
|
|
|
- # As such, we continue on a different thread, where we pipe the information, and let this call return immediately
|
|
|
+ # We are now executing, so everything we get is part of the dialog, except if it is the string for transformation termination
|
|
|
+ while _output() not in ["Success", "Failure"]:
|
|
|
mode = MODE_DIALOG
|
|
|
- _exec_on_statechart(statechart)
|
|
|
+ reply = callback(_last_output())
|
|
|
mode = MODE_MODELLING
|
|
|
- return None
|
|
|
+ if reply is not None:
|
|
|
+ _input(reply)
|
|
|
+
|
|
|
+ # Got termination message, so we are done!
|
|
|
+ if _last_output() == "Success":
|
|
|
+ return True
|
|
|
else:
|
|
|
- # No statechart associated, so just wait until we are finished
|
|
|
- while _output() not in ["Success", "Failure"]:
|
|
|
- pass
|
|
|
- if _last_output() == "Success":
|
|
|
- return True
|
|
|
- else:
|
|
|
- return False
|
|
|
+ return False
|
|
|
|
|
|
def transformation_execute_MANUAL(operation_name, input_models_dict, output_models_dict, callback=lambda i: None):
|
|
|
"""Execute an existing model operation."""
|
|
@@ -574,7 +552,7 @@ def transformation_execute_MANUAL(operation_name, input_models_dict, output_mode
|
|
|
else:
|
|
|
return False
|
|
|
|
|
|
-def transformation_execute_MT(operation_name, input_models_dict, output_models_dict, statechart=None):
|
|
|
+def transformation_execute_MT(operation_name, input_models_dict, output_models_dict, callback=lambda i: None):
|
|
|
"""Execute an existing model operation."""
|
|
|
global mode
|
|
|
_goto_mode(MODE_MODELLING)
|
|
@@ -584,31 +562,32 @@ def transformation_execute_MT(operation_name, input_models_dict, output_models_d
|
|
|
_input(["transformation_execute", operation_name] + mv_dict_rep)
|
|
|
_handle_output("Success: ready for MT execution")
|
|
|
|
|
|
- if statechart is not None:
|
|
|
- # We are to delegate this information to another statechart, which wants interaction
|
|
|
- # As such, we continue on a different thread, where we pipe the information, and let this call return immediately
|
|
|
+ # We are now executing, so everything we get is part of the dialog, except if it is the string for transformation termination
|
|
|
+ while _output() not in ["Success", "Failure"]:
|
|
|
mode = MODE_DIALOG
|
|
|
- _exec_on_statechart(statechart)
|
|
|
+ reply = callback(_last_output())
|
|
|
mode = MODE_MODELLING
|
|
|
- return None
|
|
|
+ if reply is not None:
|
|
|
+ _input(reply)
|
|
|
+
|
|
|
+ # Got termination message, so we are done!
|
|
|
+ if _last_output() == "Success":
|
|
|
+ return True
|
|
|
else:
|
|
|
- # No statechart associated, so just wait until we are finished
|
|
|
- while _output() not in ["Success", "Failure"]:
|
|
|
- pass
|
|
|
- if _last_output() == "Success":
|
|
|
- return True
|
|
|
- else:
|
|
|
- return False
|
|
|
+ return False
|
|
|
|
|
|
def transformation_list():
|
|
|
"""List existing model operations."""
|
|
|
_goto_mode(MODE_MODELLING)
|
|
|
|
|
|
_input("transformation_list")
|
|
|
- output = _handle_output("Success: ", split=True)
|
|
|
+ output = _handle_output("Success: ", split=" ")
|
|
|
+ if output == "":
|
|
|
+ return set([])
|
|
|
|
|
|
lst = set([])
|
|
|
- for v in output:
|
|
|
+ value = output.strip().split("\n")
|
|
|
+ for v in value:
|
|
|
t, m = v.strip().split(" ", 1)
|
|
|
t = t[1:-1].strip()
|
|
|
m = m.strip().split(":")[0].strip()
|
|
@@ -730,8 +709,10 @@ def element_list(model_name):
|
|
|
|
|
|
_input("list_full")
|
|
|
lst = set([])
|
|
|
- output = _handle_output("Success: ", split=True)
|
|
|
- for v in output:
|
|
|
+ output = _handle_output("Success: ", split=" ")
|
|
|
+ if output == "":
|
|
|
+ return set([])
|
|
|
+ for v in output.split("\n"):
|
|
|
m, mm = v.split(":")
|
|
|
m = m.strip()
|
|
|
mm = mm.strip()
|
|
@@ -744,8 +725,10 @@ def types(model_name):
|
|
|
|
|
|
_input("types")
|
|
|
lst = set([])
|
|
|
- output = _handle_output("Success: ", split=True)
|
|
|
- for v in output:
|
|
|
+ output = _handle_output("Success: ", split=" ")
|
|
|
+ if output == "":
|
|
|
+ return set([])
|
|
|
+ for v in output.split("\n"):
|
|
|
m, mm = v.split(":")
|
|
|
m = m.strip()
|
|
|
lst.add(m)
|
|
@@ -757,8 +740,10 @@ def types_full(model_name):
|
|
|
|
|
|
_input("types")
|
|
|
lst = set([])
|
|
|
- output = _handle_output("Success: ", split=True)
|
|
|
- for v in output:
|
|
|
+ output = _handle_output("Success: ", split=" ")
|
|
|
+ if output == "":
|
|
|
+ return set([])
|
|
|
+ for v in output.split("\n"):
|
|
|
m, mm = v.split(":")
|
|
|
m = m.strip()
|
|
|
mm = mm.strip()
|
|
@@ -770,7 +755,8 @@ def read(model_name, ID):
|
|
|
_goto_mode(MODE_MODIFY, model_name)
|
|
|
|
|
|
_input(["read", ID])
|
|
|
- v = _handle_output("Success: ", split=True)
|
|
|
+ output = _handle_output("Success: ", split=" ")
|
|
|
+ v = output.split("\n")
|
|
|
t = v[1].split(":")[1].strip()
|
|
|
if (not v[2].startswith("Source:")):
|
|
|
rval = (t, None)
|
|
@@ -785,10 +771,11 @@ def read_attrs(model_name, ID):
|
|
|
_goto_mode(MODE_MODIFY, model_name)
|
|
|
|
|
|
_input(["read", ID])
|
|
|
- output = _handle_output("Success: ", split=True)
|
|
|
+ output = _handle_output("Success: ", split=" ")
|
|
|
+ v = output.split("\n")
|
|
|
searching = True
|
|
|
rval = {}
|
|
|
- for r in output:
|
|
|
+ for r in v:
|
|
|
if searching:
|
|
|
if r == "Attributes:":
|
|
|
# Start working on attributes
|
|
@@ -817,7 +804,7 @@ def instantiate(model_name, typename, edge=None, ID=""):
|
|
|
_input(["instantiate_node", typename, ID])
|
|
|
else:
|
|
|
_input(["instantiate_edge", typename, ID, edge[0], edge[1]])
|
|
|
- return _handle_output("Success: ", split=True)[0]
|
|
|
+ return _handle_output("Success: ", split=" ")
|
|
|
|
|
|
def delete_element(model_name, ID):
|
|
|
"""Delete the element with the given ID"""
|
|
@@ -837,12 +824,16 @@ def attr_assign(model_name, ID, attr, value):
|
|
|
def attr_assign_code(model_name, ID, attr, code):
|
|
|
"""Assign a piece of Action Language code to the attribute"""
|
|
|
_check_type(code)
|
|
|
+ try:
|
|
|
+ compiled = _compile_AL(code)
|
|
|
+ except Exception as e:
|
|
|
+ raise CompilationError(e)
|
|
|
|
|
|
_goto_mode(MODE_MODIFY, model_name)
|
|
|
|
|
|
- _input(["attr_add_code", ID, attr])
|
|
|
+ _input(["attr_add", ID, attr])
|
|
|
_handle_output("Waiting for code constructors...")
|
|
|
- _input(code)
|
|
|
+ _input(compiled)
|
|
|
_output("Success")
|
|
|
|
|
|
def attr_delete(model_name, ID, attr):
|
|
@@ -857,47 +848,45 @@ def read_outgoing(model_name, ID, typename):
|
|
|
_goto_mode(MODE_MODIFY, model_name)
|
|
|
|
|
|
_input(["read_outgoing", ID, typename])
|
|
|
- output = _handle_output("Success: ", split=True)
|
|
|
- return set(output)
|
|
|
+ output = _handle_output("Success: ", split=" ")
|
|
|
+ if output == "":
|
|
|
+ return set([])
|
|
|
+ else:
|
|
|
+ return set(output.split("\n"))
|
|
|
|
|
|
def read_incoming(model_name, ID, typename):
|
|
|
"""Returns a list of all incoming associations of a specific type ("" = all)"""
|
|
|
_goto_mode(MODE_MODIFY, model_name)
|
|
|
|
|
|
_input(["read_incoming", ID, typename])
|
|
|
- output = _handle_output("Success: ", split=True)
|
|
|
- return set(output)
|
|
|
+ output = _handle_output("Success: ", split=" ")
|
|
|
+ if output == "":
|
|
|
+ return set([])
|
|
|
+ else:
|
|
|
+ return set(output.split("\n"))
|
|
|
|
|
|
def read_association_source(model_name, ID):
|
|
|
"""Returns the source of an association."""
|
|
|
_goto_mode(MODE_MODIFY, model_name)
|
|
|
|
|
|
_input(["read_association_source", ID])
|
|
|
- return _handle_output("Success: ", split=True)[0]
|
|
|
+ return _handle_output("Success: ", split=" ")
|
|
|
|
|
|
def read_association_destination(model_name, ID):
|
|
|
"""Returns the destination of an association."""
|
|
|
_goto_mode(MODE_MODIFY, model_name)
|
|
|
|
|
|
_input(["read_association_destination", ID])
|
|
|
- return _handle_output("Success: ", split=True)[0]
|
|
|
+ return _handle_output("Success: ", split=" ")
|
|
|
|
|
|
##### To document:
|
|
|
|
|
|
def service_register(name, function):
|
|
|
"""Register a function as a service with a specific name."""
|
|
|
|
|
|
- def service_process(service_task):
|
|
|
- global address
|
|
|
- global port
|
|
|
-
|
|
|
- ctrl = _start_http_client(address, port, 10.0)
|
|
|
- _listen_to_output(ctrl, service_task)
|
|
|
+ def service_process(port):
|
|
|
while 1:
|
|
|
- client_task = service_get(service_task)
|
|
|
- ctrl = _start_http_client(address, port, 10.0)
|
|
|
- _listen_to_output(ctrl, client_task)
|
|
|
- thrd = threading.Thread(target=function, args=[client_task])
|
|
|
+ thrd = threading.Thread(target=function, args=[service_get(port)])
|
|
|
thrd.daemon = True
|
|
|
thrd.start()
|
|
|
|
|
@@ -908,12 +897,10 @@ def service_register(name, function):
|
|
|
|
|
|
# Now we are in service-mode
|
|
|
mode = MODE_SERVICE
|
|
|
- task = _handle_output("Success: ", split=True)[0]
|
|
|
+ port = _handle_output("Success: ", split=" ")
|
|
|
|
|
|
# Process events in the background!
|
|
|
- thrd = threading.Thread(target=service_process, args=[task])
|
|
|
- thrd.daemon = True
|
|
|
- thrd.start()
|
|
|
+ threading.Thread(target=service_process, args=[port]).start()
|
|
|
|
|
|
def service_stop():
|
|
|
"""Stop the currently executing process."""
|
|
@@ -924,19 +911,18 @@ def service_stop():
|
|
|
global mode
|
|
|
mode = MODE_MODELLING
|
|
|
|
|
|
-def service_get(task):
|
|
|
- """Get the values on the specified task."""
|
|
|
+def service_get(port):
|
|
|
+ """Get the values on the specified port."""
|
|
|
_goto_mode(MODE_SERVICE)
|
|
|
|
|
|
- val = _output(task=task)
|
|
|
- return val
|
|
|
+ return _output(port=port)
|
|
|
|
|
|
-def service_set(task, value):
|
|
|
- """Set a value on a specified task."""
|
|
|
+def service_set(port, value):
|
|
|
+ """Set a value on a specified port."""
|
|
|
_check_type_list(value)
|
|
|
_goto_mode(MODE_SERVICE)
|
|
|
|
|
|
- _input(value, task=task)
|
|
|
+ _input(value, port=port)
|
|
|
|
|
|
def user_password(user, password):
|
|
|
"""Change a user's password."""
|
|
@@ -952,7 +938,7 @@ def element_list_nice(model_name):
|
|
|
|
|
|
_input(["element_list_nice", model_name, _get_metamodel(model_name)])
|
|
|
|
|
|
- data = _handle_output("Success: ", split=True)[0]
|
|
|
+ data = _handle_output("Success: ", split=" ")
|
|
|
try:
|
|
|
return json.loads(data)
|
|
|
except:
|
|
@@ -964,23 +950,29 @@ def connections_between(model_name, source_element, target_element):
|
|
|
_goto_mode(MODE_MODIFY, model_name)
|
|
|
|
|
|
_input(["connections_between", source_element, target_element])
|
|
|
- output = _handle_output("Success: ", split=True)
|
|
|
- return set(output)
|
|
|
+ output = _handle_output("Success: ", split=" ")
|
|
|
+ if output == "":
|
|
|
+ return set([])
|
|
|
+ else:
|
|
|
+ return set(output.split("\n"))
|
|
|
|
|
|
def define_attribute(model_name, node, attr_name, attr_type):
|
|
|
"""Create a new attribute, which can be instantiated one meta-level below."""
|
|
|
_goto_mode(MODE_MODIFY, model_name)
|
|
|
|
|
|
_input(["define_attribute", node, attr_name, attr_type])
|
|
|
- return _handle_output("Success: ", split=True)[0]
|
|
|
+ return _handle_output("Success: ", split=" ")
|
|
|
|
|
|
def all_instances(model_name, type_name):
|
|
|
"""Returns a list of all elements of a specific type."""
|
|
|
_goto_mode(MODE_MODIFY, model_name)
|
|
|
|
|
|
_input(["all_instances", type_name])
|
|
|
- output = _handle_output("Success: ", split=True)
|
|
|
- return set(output)
|
|
|
+ output = _handle_output("Success: ", split=" ")
|
|
|
+ if output == "":
|
|
|
+ return set([])
|
|
|
+ else:
|
|
|
+ return set(output.split("\n"))
|
|
|
|
|
|
def service_poll(port):
|
|
|
"""Checks whether or not the Modelverse side has any input ready to be processed."""
|
|
@@ -1004,20 +996,6 @@ def add_conformance(model_name, metamodel_name, partial_type_mapping=None):
|
|
|
_handle_output("Success")
|
|
|
|
|
|
def folder_create(folder_name):
|
|
|
- """Create a new folder."""
|
|
|
_goto_mode(MODE_MODELLING)
|
|
|
_input(["folder_create", folder_name])
|
|
|
_handle_output("Success")
|
|
|
-
|
|
|
-def model_types(model_name):
|
|
|
- """Fetch all typings defined for this specific model."""
|
|
|
- _goto_mode(MODE_MODELLING)
|
|
|
- _input(["model_types", model_name])
|
|
|
- output = _handle_output("Success: ", split=True)
|
|
|
- return set(output)
|
|
|
-
|
|
|
-import atexit
|
|
|
-def _close_model():
|
|
|
- if mode == MODE_MODIFY:
|
|
|
- _model_exit()
|
|
|
-atexit.register(_close_model)
|