modelverse.py 16 KB

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