modelverse.py 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475
  1. from sccd.runtime.statecharts_core import Event
  2. import sccd.runtime.socket2event as socket2event
  3. import modelverse_SCCD
  4. import time
  5. import threading
  6. # Exceptions
  7. class ModelverseException(Exception):
  8. pass
  9. class UnknownError(ModelverseException):
  10. pass
  11. class UnknownIdentifier(ModelverseException):
  12. pass
  13. class CompilationError(ModelverseException):
  14. pass
  15. class NoSuchAttribute(ModelverseException):
  16. pass
  17. class UnknownModel(ModelverseException):
  18. pass
  19. class ConnectionError(ModelverseException):
  20. pass
  21. class ModelExists(ModelverseException):
  22. pass
  23. class PermissionDenied(ModelverseException):
  24. pass
  25. class InvalidMode(ModelverseException):
  26. pass
  27. class InterfaceMismatch(ModelverseException):
  28. pass
  29. class UnknownMetamodellingHierarchy(ModelverseException):
  30. pass
  31. def run_controller():
  32. try:
  33. controller.start()
  34. finally:
  35. controller.stop()
  36. def _next_ID():
  37. global ID
  38. ID += 1
  39. return ID
  40. def _process_SC(statechart, port_sc, context):
  41. print("Context: " + str(context))
  42. while 1:
  43. empty = True
  44. # Fetch output from the MV
  45. response = responses.fetch(0)
  46. if response is not None:
  47. print("Output of MV to SC")
  48. if response.name == "data_output":
  49. # Got output of MV, so forward to SCCD
  50. statechart[0].addInput(Event("input", statechart[1], response.parameters))
  51. elif response.name == "result":
  52. # Finished execution, so continue and return result
  53. statechart[0].addInput(Event("terminate", statechart[1], []))
  54. return response.parameters[1]
  55. else:
  56. raise Exception("Unknown data from MV to SC: " + str(response))
  57. empty = False
  58. # Fetch output from the SC
  59. response = port_sc.fetch(0)
  60. if response is not None:
  61. print("Output of SC to MV")
  62. if response.name == "output":
  63. controller.addInput(Event("data_input", "action_in", [response.parameters, context]))
  64. else:
  65. raise Exception("Unknown data from SC to MV: " + str(response))
  66. empty = False
  67. if empty:
  68. time.sleep(0.5)
  69. def INPUT(action, context, parameters):
  70. controller.addInput(Event("action", "action_in", [action, _next_ID(), context, parameters]))
  71. def OUTPUT():
  72. while 1:
  73. response = responses.fetch(-1)
  74. if response.name == "result":
  75. return response.parameters[1]
  76. elif response.name == "exception":
  77. if response.parameters[1] == "UnknownIdentifier":
  78. raise UnknownIdentifier()
  79. elif response.parameters[1] == "UnknownMetamodellingHierarchy":
  80. raise UnknownMetamodellingHierarchy()
  81. else:
  82. print("Unknown error: " + str(response.parameters))
  83. raise UnknownError()
  84. def init(address_param="127.0.0.1:8001", timeout=20.0):
  85. global controller
  86. global ID
  87. global responses
  88. controller = modelverse_SCCD.Controller()
  89. socket2event.boot_translation_service(controller)
  90. ID = 0
  91. thrd = threading.Thread(target=run_controller)
  92. thrd.daemon = True
  93. thrd.start()
  94. responses = controller.addOutputListener("action_out")
  95. controller.addOutputListener("ready").fetch(-1)
  96. INPUT("init", None, [address_param, timeout])
  97. controller.address = address_param
  98. return OUTPUT()
  99. def login(username, password):
  100. INPUT("login", None, [username, password])
  101. return OUTPUT()
  102. def model_list(location):
  103. INPUT("model_list", None, [location])
  104. return OUTPUT()
  105. def model_add(model_name, metamodel_name, model_code=""):
  106. INPUT("model_add", None, [model_name, metamodel_name, model_code])
  107. return OUTPUT()
  108. def model_delete(model_name):
  109. INPUT("model_delete", None, [model_name])
  110. return OUTPUT()
  111. def model_list_full(location):
  112. INPUT("model_list_full", None, [location])
  113. return OUTPUT()
  114. def verify(model_name, metamodel_name):
  115. INPUT("verify", None, [model_name, metamodel_name])
  116. return OUTPUT()
  117. def model_overwrite(model_name, new_model, context=None):
  118. INPUT("model_overwrite", context, [model_name, new_model])
  119. return OUTPUT()
  120. def disconnect():
  121. INPUT("disconnect", None, [])
  122. return OUTPUT()
  123. def user_logout():
  124. INPUT("user_logout", None, [])
  125. return OUTPUT()
  126. def user_delete():
  127. INPUT("user_delete", None, [])
  128. return OUTPUT()
  129. def model_render(model_name, mapper_name, rendered_name):
  130. INPUT("model_render", None, [model_name, mapper_name, rendered_name])
  131. return OUTPUT()
  132. def transformation_between(sources, targets):
  133. INPUT("transformation_between", None, [source, target])
  134. return OUTPUT()
  135. def transformation_add_MT(source_metamodels, target_metamodels, operation_name, code, callback=None):
  136. INPUT("transformation_add_MT", None, [source_metamodels, target_metamodels, operation_name, code, True])
  137. context, model = OUTPUT()
  138. if callback is not None:
  139. callback(context)
  140. INPUT("exit", context, [])
  141. return OUTPUT()
  142. def transformation_add_AL(source_metamodels, target_metamodels, operation_name, code, callback=None):
  143. INPUT("transformation_add_AL", None, [source_metamodels, target_metamodels, operation_name, code, True])
  144. context, model = OUTPUT()
  145. if context is None:
  146. # In case the source and target metamodels are empty, the context will be None, indicating that we are finished already (no callbacks allowed)
  147. return
  148. if callback is not None:
  149. callback(context)
  150. INPUT("exit", context, [])
  151. return OUTPUT()
  152. def transformation_add_MANUAL(source_metamodels, target_metamodels, operation_name, callback=None):
  153. INPUT("transformation_add_MANUAL", None, [source_metamodels, target_metamodels, operation_name, True])
  154. context, model = OUTPUT()
  155. if callback is not None:
  156. callback(context)
  157. INPUT("exit", context, [])
  158. return OUTPUT()
  159. def __transformation_execute(operation_name, input_models_dict, output_models_dict, statechart, tracability_model, fetch_output):
  160. if statechart is not None:
  161. port_sc = statechart[0].addOutputListener(statechart[2])
  162. INPUT("transformation_execute", None, [operation_name, input_models_dict, output_models_dict, tracability_model, fetch_output])
  163. op, name, context = OUTPUT()
  164. if statechart is not None:
  165. threading.Thread(target=_process_SC, args=[statechart, port_sc, context]).start()
  166. else:
  167. val = OUTPUT()
  168. print("Transformation result: " + str(val))
  169. return val
  170. def transformation_execute_MT(operation_name, input_models_dict, output_models_dict, statechart=None, tracability_model="", fetch_output=True):
  171. return __transformation_execute(operation_name, input_models_dict, output_models_dict, statechart, tracability_model, fetch_output)
  172. def transformation_execute_AL(operation_name, input_models_dict, output_models_dict, statechart=None, tracability_model="", fetch_output=True):
  173. return __transformation_execute(operation_name, input_models_dict, output_models_dict, statechart, tracability_model, fetch_output)
  174. def transformation_execute_MANUAL(operation_name, input_models_dict, output_models_dict, callback=None, tracability_model=""):
  175. INPUT("transformation_execute", None, [operation_name, input_models_dict, output_models_dict, tracability_model])
  176. op, name, context, model = OUTPUT()
  177. if callback is not None:
  178. callback(context)
  179. INPUT("exit", context, [])
  180. return OUTPUT()
  181. def transformation_signature(operation_name):
  182. INPUT("transformation_signature", None, [operation_name])
  183. return OUTPUT()
  184. def process_signature(process_name):
  185. INPUT("process_signature", None, [operation_name])
  186. return OUTPUT()
  187. def permission_modify(model_name, permissions):
  188. INPUT("permission_modify", None, [model_name, permissions])
  189. return OUTPUT()
  190. def permission_owner(model_name, permission):
  191. INPUT("permission_owner", None, [model_name, permission])
  192. return OUTPUT()
  193. def permission_group(model_name, group):
  194. INPUT("permission_group", None, [model_name, group])
  195. return OUTPUT()
  196. def group_create(group_name):
  197. INPUT("group_create", None, [group_name])
  198. return OUTPUT()
  199. def group_delete(group_name):
  200. INPUT("group_delete", None, [group_name])
  201. return OUTPUT()
  202. def group_owner_add(group_name, user_name):
  203. INPUT("group_owner_add", None, [group_name, user_name])
  204. return OUTPUT()
  205. def group_owner_delete(group_name, user_name):
  206. INPUT("group_owner_delete", None, [group_name, user_name])
  207. return OUTPUT()
  208. def group_join(group_name, user_name):
  209. INPUT("group_join", None, [group_name, user_name])
  210. return OUTPUT()
  211. def group_kick(group_name, user_name):
  212. INPUT("group_kick", None, [group_name, user_name])
  213. return OUTPUT()
  214. def group_list():
  215. INPUT("group_list", None, [])
  216. return OUTPUT()
  217. def admin_promote(user_name):
  218. INPUT("admin_promote", None, [user_name])
  219. return OUTPUT()
  220. def admin_demote(user_name):
  221. INPUT("admin_demote", None, [user_name])
  222. return OUTPUT()
  223. def conformance_delete(model_name, metamodel_name):
  224. INPUT("conformance_delete", None, [model_name, metamodel_name])
  225. return OUTPUT()
  226. def conformance_add(model_name, metamodel_name):
  227. INPUT("conformance_add", None, [model_name, metamodel_name])
  228. return OUTPUT()
  229. def folder_create(folder_name):
  230. INPUT("folder_create", None, [folder_name])
  231. return OUTPUT()
  232. def model_types(model_name):
  233. INPUT("model_types", None, [model_name])
  234. return OUTPUT()
  235. def alter_context(model_name, metamodel_name):
  236. INPUT("alter_context", None, [model_name, metamodel_name])
  237. def element_list(model_name, context=None):
  238. INPUT("element_list", context, [model_name])
  239. return OUTPUT()
  240. def element_list_nice(model_name, context=None):
  241. INPUT("element_list_nice", context, [model_name])
  242. return OUTPUT()
  243. def types(model_name, context=None):
  244. INPUT("types", context, [model_name])
  245. return OUTPUT()
  246. def types_full(model_name, context=None):
  247. INPUT("types_full", context, [model_name])
  248. return OUTPUT()
  249. def read_info(model_name, ID, context=None):
  250. INPUT("read_info", context, [model_name, ID])
  251. return OUTPUT()
  252. def read_attrs(model_name, ID, context=None):
  253. INPUT("read_attrs", context, [model_name, ID])
  254. return OUTPUT()
  255. def instantiate(model_name, typename, edge=None, ID="", context=None):
  256. INPUT("instantiate", context, [model_name, typename, edge, ID])
  257. return OUTPUT()
  258. def delete_element(model_name, ID, context=None):
  259. INPUT("delete_element", context, [model_name, ID])
  260. return OUTPUT()
  261. def attr_assign(model_name, ID, attr, value, context=None):
  262. INPUT("attr_assign", context, [model_name, ID, attr, value])
  263. return OUTPUT()
  264. def attr_assign_code(model_name, ID, attr, code, context=None):
  265. INPUT("attr_assign_code", context, [model_name, ID, attr, code])
  266. return OUTPUT()
  267. def attr_delete(model_name, ID, attr, context=None):
  268. INPUT("attr_delete", context, [model_name, ID, attr])
  269. return OUTPUT()
  270. def read_outgoing(model_name, ID, typename, context=None):
  271. INPUT("read_outgoing", context, [model_name, ID, typename])
  272. return OUTPUT()
  273. def read_incoming(model_name, ID, typename, context=None):
  274. INPUT("read_incoming", context, [model_name, ID, typename])
  275. return OUTPUT()
  276. def read_association_source(model_name, ID, context=None):
  277. INPUT("read_association_source", context, [model_name, ID])
  278. return OUTPUT()
  279. def read_association_destination(model_name, ID, context=None):
  280. INPUT("read_association_destination", context, [model_name, ID])
  281. return OUTPUT()
  282. def connections_between(model_name, source, target, context=None):
  283. INPUT("connections_between", context, [model_name, source, target])
  284. return OUTPUT()
  285. def define_attribute(model_name, node, attr_name, attr_type, context=None):
  286. INPUT("define_attribute", context, [model_name, node, attr_name, attr_type])
  287. return OUTPUT()
  288. def all_instances(model_name, type_name, context=None):
  289. INPUT("all_instances", context, [model_name, type_name])
  290. return OUTPUT()
  291. def process_execute(process_name, prefix, callbacks=None):
  292. # for all callbacks to SCs, start up the output port already
  293. sc_ports = {}
  294. for k, v in callbacks.items():
  295. if isinstance(v, (tuple, list)):
  296. # Is a statechart, so register already
  297. sc_ports[k] = v[0].addOutputListener(v[2])
  298. INPUT("process_execute", None, [process_name, prefix])
  299. operation = OUTPUT()
  300. while 1:
  301. if isinstance(operation, (list, tuple)):
  302. if operation[0] == "OP":
  303. t, name, context, model = operation
  304. if name in callbacks:
  305. callbacks[name](context)
  306. INPUT("exit", context, [])
  307. operation = OUTPUT()
  308. elif operation[0] == "SC":
  309. t, name, context = operation
  310. if name in callbacks:
  311. statechart = callbacks[name]
  312. else:
  313. statechart = None
  314. while 1:
  315. empty = True
  316. # Fetch output from the MV
  317. response = responses.fetch(0)
  318. if response is not None:
  319. if response.name == "data_output":
  320. # Got output of MV, so forward to SCCD
  321. if statechart:
  322. statechart[0].addInput(Event("input", statechart[1], response.parameters))
  323. elif response.name == "result":
  324. # Finished execution, so continue and return result
  325. if statechart:
  326. statechart[0].addInput(Event("terminate", statechart[1], []))
  327. # Break from the most inner loop
  328. operation = response.parameters[1]
  329. break
  330. empty = False
  331. # Fetch output from the SC
  332. if statechart:
  333. response = sc_ports[name].fetch(0)
  334. if response is not None:
  335. if response.name == "output":
  336. controller.addInput(Event("data_input", "action_in", [response.parameters, context]))
  337. empty = False
  338. if empty:
  339. time.sleep(0.01)
  340. else:
  341. if operation == "Finished":
  342. # Finished execution of the process, so exit
  343. return None
  344. def get_taskname():
  345. """Fetch the taskname of the current connection."""
  346. return controller.taskname
  347. """ Some hardcoded functions... Way easier to express them with code than with statecharts!"""
  348. import json
  349. import urllib
  350. import urllib2
  351. def service_register(name, function):
  352. """Register a function as a service with a specific name."""
  353. INPUT("service_register", None, [name, function])
  354. port = OUTPUT()
  355. return port
  356. def service_stop():
  357. """Stop the currently executing process."""
  358. INPUT("service_stop", None, [])
  359. return OUTPUT()
  360. def service_get(port):
  361. """Get the values on the specified port."""
  362. val = json.loads(urllib2.urlopen(urllib2.Request("http://%s" % controller.address, urllib.urlencode({"op": "get_output", "taskname": port}))).read())
  363. return val
  364. def service_set(port, value):
  365. """Set a value on a specified port."""
  366. if isinstance(value, type([])):
  367. value = json.dumps(value)
  368. urllib2.urlopen(urllib2.Request("http://%s" % controller.address, urllib.urlencode({"op": "set_input", "data": value, "taskname": port}))).read()
  369. else:
  370. value = json.dumps(value)
  371. urllib2.urlopen(urllib2.Request("http://%s" % controller.address, urllib.urlencode({"op": "set_input", "value": value, "taskname": port}))).read()
  372. def service_poll(port):
  373. """Checks whether or not the Modelverse side has any input ready to be processed."""
  374. raise NotImplementedError()