from sccd.runtime.statecharts_core import Event import sccd.runtime.socket2event as socket2event import modelverse_SCCD import time import threading # Exceptions class ModelverseException(Exception): pass class UnknownError(ModelverseException): pass class UnknownIdentifier(ModelverseException): pass class CompilationError(ModelverseException): pass class NoSuchAttribute(ModelverseException): pass class UnknownModel(ModelverseException): pass class ConnectionError(ModelverseException): pass class ModelExists(ModelverseException): pass class PermissionDenied(ModelverseException): pass class InvalidMode(ModelverseException): pass class InterfaceMismatch(ModelverseException): pass class UnknownMetamodellingHierarchy(ModelverseException): pass def run_controller(): try: controller.start() finally: controller.stop() def _next_ID(): global ID ID += 1 return ID def __run_new_modelverse(address, username, password, callback, model): init(address) login(username, password) callback(model) exit_save(model) def __run_new_modelverse_activity(address, username, password, taskname, pipe, callback): init(address, taskname=taskname) controller.username = username controller.password = password t = OUTPUT() if t == "OP": model = OUTPUT() if callback is not None: __invoke(callback, model) controller.addInput(Event("data_input", "action_in", [None, None])) time.sleep(2) elif t == "SC": while 1: empty = True # Fetch output from the MV response = responses.fetch(0) if response is not None: if response.name == "data_output": # Got output of MV, so forward to SCCD if pipe is not None: pipe.send(("input", response.parameters)) elif response.name == "result": # Finished execution, so continue and return result if pipe is not None: pipe.send(("terminate", [])) pipe.close() return else: raise Exception("Unknown data from MV to SC: " + str(response)) empty = False # Fetch output from the SC if pipe is not None and 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 p = multiprocessing.Process(target=__run_new_modelverse, args=[controller.address, controller.username, controller.password, callback, model]) p.start() p.join() 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 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 response = port_sc.fetch(0) if response is not None: p2c_pipe.send(response) empty = False if empty: time.sleep(0.05) p.join() def _process_OP(callback, taskname): import multiprocessing 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])) def OUTPUT(): while 1: response = responses.fetch(-1) if response.name == "result": return response.parameters[1] elif response.name == "exception": if response.parameters[1] == "UnknownIdentifier": raise UnknownIdentifier() elif response.parameters[1] == "UnknownMetamodellingHierarchy": raise UnknownMetamodellingHierarchy() else: print("Unknown error: " + str(response.parameters)) raise UnknownError() def init(address_param="127.0.0.1:8001", timeout=20.0, taskname=None): global controller global ID global responses controller = modelverse_SCCD.Controller(taskname) socket2event.boot_translation_service(controller) ID = 0 thrd = threading.Thread(target=run_controller) thrd.daemon = True thrd.start() responses = controller.addOutputListener("action_out") controller.addOutputListener("ready").fetch(-1) INPUT("init", None, [address_param, timeout]) controller.address = address_param return OUTPUT() def login(username, password): controller.username = username controller.password = password INPUT("login", None, [username, password]) return OUTPUT() def model_list(location): INPUT("model_list", None, [location]) return OUTPUT() def model_add(model_name, metamodel_name, model_code=""): INPUT("model_add", None, [model_name, metamodel_name, model_code]) return OUTPUT() def model_delete(model_name): INPUT("model_delete", None, [model_name]) return OUTPUT() def model_list_full(location): INPUT("model_list_full", None, [location]) return OUTPUT() def verify(model_name, metamodel_name): INPUT("verify", None, [model_name, metamodel_name]) return OUTPUT() def model_overwrite(model_name, new_model): INPUT("model_overwrite", None, [model_name, new_model]) return OUTPUT() def disconnect(): INPUT("disconnect", None, []) return OUTPUT() def user_logout(): INPUT("user_logout", None, []) return OUTPUT() def user_delete(): INPUT("user_delete", None, []) return OUTPUT() def model_render(model_name, mapper_name, rendered_name): INPUT("model_render", None, [model_name, mapper_name, rendered_name]) return OUTPUT() def transformation_between(sources, targets): INPUT("transformation_between", None, [source, target]) return OUTPUT() 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]) model = OUTPUT() if callback is not None: __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]) model = OUTPUT() if model is not None: # In case the source and target metamodels are empty, the model will be None, indicating that we are finished already (no callbacks allowed) if callback is not None: __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]) model = OUTPUT() if callback is not None: __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): if statechart is not None: port_sc = statechart[0].addOutputListener(statechart[2]) INPUT("transformation_execute", None, [operation_name, input_models_dict, output_models_dict, tracability_model, fetch_output]) taskname = OUTPUT() if statechart is not None: 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) def transformation_execute_AL(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) 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]) taskname = OUTPUT() _process_OP(callback, taskname) return OUTPUT() def transformation_signature(operation_name): INPUT("transformation_signature", None, [operation_name]) return OUTPUT() def process_signature(process_name): INPUT("process_signature", None, [operation_name]) return OUTPUT() def permission_modify(model_name, permissions): INPUT("permission_modify", None, [model_name, permissions]) return OUTPUT() def permission_owner(model_name, permission): INPUT("permission_owner", None, [model_name, permission]) return OUTPUT() def permission_group(model_name, group): INPUT("permission_group", None, [model_name, group]) return OUTPUT() def group_create(group_name): INPUT("group_create", None, [group_name]) return OUTPUT() def group_delete(group_name): INPUT("group_delete", None, [group_name]) return OUTPUT() def group_owner_add(group_name, user_name): INPUT("group_owner_add", None, [group_name, user_name]) return OUTPUT() def group_owner_delete(group_name, user_name): INPUT("group_owner_delete", None, [group_name, user_name]) return OUTPUT() def group_join(group_name, user_name): INPUT("group_join", None, [group_name, user_name]) return OUTPUT() def group_kick(group_name, user_name): INPUT("group_kick", None, [group_name, user_name]) return OUTPUT() def group_list(): INPUT("group_list", None, []) return OUTPUT() def admin_promote(user_name): INPUT("admin_promote", None, [user_name]) return OUTPUT() def admin_demote(user_name): INPUT("admin_demote", None, [user_name]) return OUTPUT() def conformance_delete(model_name, metamodel_name): INPUT("conformance_delete", None, [model_name, metamodel_name]) return OUTPUT() def conformance_add(model_name, metamodel_name): INPUT("conformance_add", None, [model_name, metamodel_name]) return OUTPUT() def folder_create(folder_name): INPUT("folder_create", None, [folder_name]) return OUTPUT() def model_types(model_name): INPUT("model_types", None, [model_name]) return OUTPUT() def alter_context(model_name, metamodel_name): INPUT("alter_context", None, [model_name, metamodel_name]) def element_list(model_name, context=None): INPUT("element_list", context, [model_name]) return OUTPUT() def element_list_nice(model_name, context=None): INPUT("element_list_nice", context, [model_name]) return OUTPUT() def types(model_name, context=None): INPUT("types", context, [model_name]) return OUTPUT() def types_full(model_name, context=None): INPUT("types_full", context, [model_name]) return OUTPUT() def read_info(model_name, ID, context=None): INPUT("read_info", context, [model_name, ID]) return OUTPUT() def read_attrs(model_name, ID, context=None): INPUT("read_attrs", context, [model_name, ID]) return OUTPUT() def instantiate(model_name, typename, edge=None, ID="", context=None): INPUT("instantiate", context, [model_name, typename, edge, ID]) return OUTPUT() def delete_element(model_name, ID, context=None): INPUT("delete_element", context, [model_name, ID]) return OUTPUT() def attr_assign(model_name, ID, attr, value, context=None): INPUT("attr_assign", context, [model_name, ID, attr, value]) return OUTPUT() def attr_assign_code(model_name, ID, attr, code, context=None): INPUT("attr_assign_code", context, [model_name, ID, attr, code]) return OUTPUT() def attr_delete(model_name, ID, attr, context=None): INPUT("attr_delete", context, [model_name, ID, attr]) return OUTPUT() def read_outgoing(model_name, ID, typename, context=None): INPUT("read_outgoing", context, [model_name, ID, typename]) return OUTPUT() def read_incoming(model_name, ID, typename, context=None): INPUT("read_incoming", context, [model_name, ID, typename]) return OUTPUT() def read_association_source(model_name, ID, context=None): INPUT("read_association_source", context, [model_name, ID]) return OUTPUT() def read_association_destination(model_name, ID, context=None): INPUT("read_association_destination", context, [model_name, ID]) return OUTPUT() def connections_between(model_name, source, target, context=None): INPUT("connections_between", context, [model_name, source, target]) return OUTPUT() def define_attribute(model_name, node, attr_name, attr_type, context=None): INPUT("define_attribute", context, [model_name, node, attr_name, attr_type]) return OUTPUT() def all_instances(model_name, type_name, context=None): INPUT("all_instances", context, [model_name, type_name]) return OUTPUT() def process_execute(process_name, model_mapping, callbacks=None): # for all callbacks to SCs, start up the output port already sc_ports = {} for k, v in callbacks.items(): if isinstance(v, (tuple, list)): # Is a statechart, so register already sc_ports[k] = v[0].addOutputListener(v[2]) INPUT("process_execute", None, [process_name, model_mapping]) while 1: result = OUTPUT() if result == "Success": # Finished return None else: taskname, operation = result if (operation in callbacks): data = callbacks[operation] if isinstance(data, (tuple, list)): # Statechart, so consider like that threading.Thread(target=_process_SC, args=[data, sc_ports[operation], taskname]).start() else: # Assume function threading.Thread(target=_process_OP, args=[data, taskname]).start() else: # Assume empty function threading.Thread(target=_process_OP, args=[None, taskname]).start() 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 import urllib2 def service_register(name, function): """Register a function as a service with a specific name.""" INPUT("service_register", None, [name, function]) port = OUTPUT() return port def service_stop(): """Stop the currently executing process.""" INPUT("service_stop", None, []) return OUTPUT() def service_get(port): """Get the values on the specified port.""" val = json.loads(urllib2.urlopen(urllib2.Request("http://%s" % controller.address, urllib.urlencode({"op": "get_output", "taskname": port}))).read()) return val def service_set(port, value): """Set a value on a specified port.""" if isinstance(value, type([])): value = json.dumps(value) urllib2.urlopen(urllib2.Request("http://%s" % controller.address, urllib.urlencode({"op": "set_input", "data": value, "taskname": port}))).read() else: value = json.dumps(value) urllib2.urlopen(urllib2.Request("http://%s" % controller.address, urllib.urlencode({"op": "set_input", "value": value, "taskname": port}))).read() def service_poll(port): """Checks whether or not the Modelverse side has any input ready to be processed.""" raise NotImplementedError()