modelverse.py 15 KB

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