modelverse.py 17 KB

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