modelverse.py 16 KB

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