modelverse.py 17 KB

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