modelverse.py 19 KB

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