modelverse.py 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702
  1. import urllib
  2. import urllib2
  3. import json
  4. import random
  5. from urllib2 import URLError
  6. import sys
  7. # Bind to the compiler
  8. sys.path.append("../interface/HUTN")
  9. from hutn_compiler.compiler import main as do_compile
  10. # Helper functions and configuration: do not use yourself!
  11. taskname = random.random()
  12. address = None
  13. last_output = None
  14. mode = 0
  15. def _input(value):
  16. # Ugly json encoding of primitives
  17. if isinstance(value, type([])):
  18. value = json.dumps(value)
  19. urllib2.urlopen(urllib2.Request(address, urllib.urlencode({"op": "set_input", "data": value, "taskname": taskname}))).read()
  20. else:
  21. value = json.dumps(value)
  22. urllib2.urlopen(urllib2.Request(address, urllib.urlencode({"op": "set_input", "value": value, "taskname": taskname}))).read()
  23. def _input_raw(value, taskname):
  24. # Ugly json encoding of primitives
  25. urllib2.urlopen(urllib2.Request(address, urllib.urlencode({"op": "set_input", "value": value, "taskname": taskname}))).read()
  26. def _compile_AL(code):
  27. # Compile an action language file and send the compiled code
  28. code_fragments = code.split("\n")
  29. code_fragments = [i for i in code_fragments if i.strip() != ""]
  30. code_fragments = [i.replace(" ", "\t") for i in code_fragments]
  31. initial_tabs = min([len(i) - len(i.lstrip("\t")) for i in code_fragments])
  32. code_fragments = [i[initial_tabs:] for i in code_fragments]
  33. code_fragments.append("")
  34. code = "\n".join(code_fragments)
  35. with open("__constraint.alc", "w") as f:
  36. f.write(code)
  37. f.flush()
  38. return do_compile("__constraint.alc", "../interface/HUTN/grammars/actionlanguage.g", "CS")
  39. def _compile_model(code):
  40. # Compile a model and send the compiled graph
  41. # First change multiple spaces to a tab
  42. code_fragments = code.split("\n")
  43. code_fragments = [i for i in code_fragments if i.strip() != ""]
  44. code_fragments = [i.replace(" ", "\t") for i in code_fragments]
  45. initial_tabs = min([len(i) - len(i.lstrip("\t")) for i in code_fragments])
  46. code_fragments = [i[initial_tabs:] for i in code_fragments]
  47. code_fragments.append("")
  48. code = "\n".join(code_fragments)
  49. with open("__model.mvc", "w") as f:
  50. f.write(code)
  51. f.flush()
  52. return do_compile("__model.mvc", "../interface/HUTN/grammars/modelling.g", "M") + ["exit"]
  53. def _output(expected=None):
  54. try:
  55. global last_output
  56. last_output = json.loads(urllib2.urlopen(urllib2.Request(address, urllib.urlencode({"op": "get_output", "taskname": taskname}))).read())
  57. except:
  58. raise UnknownError()
  59. if expected is not None and last_output != expected:
  60. raise InterfaceMismatch(last_output)
  61. return last_output
  62. def _last_output():
  63. return last_output
  64. def _consume_to_end():
  65. while (_output() not in ["Ready for command...", "Please give your command."]):
  66. pass
  67. # Exceptions
  68. class ModelverseException(Exception):
  69. pass
  70. class UnknownException(ModelverseException):
  71. pass
  72. class UnknownIdentifier(ModelverseException):
  73. pass
  74. class UnknownType(ModelverseException):
  75. pass
  76. class NotAnAssociation(ModelverseException):
  77. pass
  78. class UnsupportedValue(ModelverseException):
  79. pass
  80. class CompilationError(ModelverseException):
  81. pass
  82. class NoSuchAttribute(ModelverseException):
  83. pass
  84. class UnknownModel(ModelverseException):
  85. pass
  86. class ConnectionError(ModelverseException):
  87. pass
  88. class ModelExists(ModelverseException):
  89. pass
  90. class PermissionDenied(ModelverseException):
  91. pass
  92. class InvalidMode(ModelverseException):
  93. pass
  94. class InterfaceMismatch(ModelverseException):
  95. pass
  96. # Main MvC operations
  97. def init(address_param="http://localhost:8001"):
  98. """Starts up the connection to the Modelverse."""
  99. # return None
  100. # raises ConnectionError
  101. # raises UnknownError
  102. # raises InvalidMode
  103. global mode
  104. if mode != 0:
  105. raise InvalidMode()
  106. global address
  107. address = address_param
  108. try:
  109. _input_raw('"%s"' % taskname, "task_manager")
  110. mode = 1
  111. except URLError as e:
  112. raise ConnectionError(e.reason)
  113. def login(username, password):
  114. """Log in a user, if user doesn't exist, it is created."""
  115. # return None
  116. # raises UnknownError
  117. # raises PermissionDenied
  118. # raises InterfaceMismatch
  119. global mode
  120. if mode != 1:
  121. raise InvalidMode()
  122. _output("Log on as which user?")
  123. _input(username)
  124. if _output() == "User password?":
  125. _input(password)
  126. if _output() == "Welcome to the Model Management Interface v2.0!":
  127. _output("Use the 'help' command for a list of possible commands")
  128. _output("Ready for command...")
  129. mode = 2
  130. elif _last_output() == "Wrong password!":
  131. raise PermissionDenied()
  132. else:
  133. raise InterfaceMismatch(_last_output())
  134. elif _output() == "This is a new user: please give password!":
  135. _input(password)
  136. _output("Please repeat the password")
  137. _input(password)
  138. if _output() == "Welcome to the Model Management Interface v2.0!":
  139. _output("Use the 'help' command for a list of possible commands")
  140. _output("Ready for command...")
  141. mode = 2
  142. elif _last_output() == "Not the same password!":
  143. # We just sent the same password, so it should be identical, unless the interface changed
  144. raise InterfaceMismatch(_last_output())
  145. else:
  146. raise InterfaceMismatch(_last_output())
  147. else:
  148. raise InterfaceMismatch(_last_output())
  149. def model_add(model_name, metamodel_name, model_code=None):
  150. """Instantiate a new model."""
  151. # return None
  152. # raises UnknownModel
  153. # raises ModelExists
  154. # raises UnknownError
  155. # raises PermissionDenied
  156. # raises CompilationError
  157. if mode != 2:
  158. raise InvalidMode()
  159. # Do this before creating the model, as otherwise compilation errors would make us inconsistent
  160. if model_code is not None:
  161. try:
  162. compiled = _compile_model(model_code)
  163. except:
  164. raise CompilationError()
  165. else:
  166. compiled = ["exit"]
  167. _input("model_add")
  168. _output("Creating new model!")
  169. _output("Model type?")
  170. _input(metamodel_name)
  171. if _output() == "Model name?":
  172. _input(model_name)
  173. if _output() == "Waiting for model constructors...":
  174. _input(compiled)
  175. _output("Model upload success!")
  176. _output("Ready for command...")
  177. elif _last_output() == "Model with that name already exists!":
  178. _output("Ready for command...")
  179. raise ModelExists()
  180. else:
  181. raise InterfaceMismatch(_last_output())
  182. elif _last_output().startswith("Could not find type model"):
  183. _output("Ready for command...")
  184. raise UnknownModel()
  185. elif _last_output() == "Permission denied":
  186. _output("Ready for command...")
  187. raise PermissionDenied()
  188. def model_modify(model_name):
  189. """Modify an existing model."""
  190. # return is_write
  191. # raises UnknownModel
  192. # raises PermissionDenied
  193. # raises UnknownError
  194. global mode
  195. if mode != 2:
  196. raise InvalidMode()
  197. _input("model_modify")
  198. _output("Which model do you want to modify?")
  199. _input(model_name)
  200. if _output() == "Permission denied":
  201. _output("Ready for command...")
  202. raise PermissionDenied()
  203. elif _last_output() == "Could not find model!":
  204. _output("Ready for command...")
  205. raise UnknownModel()
  206. elif _last_output() == "Model loaded, ready for commands!":
  207. mode = 3
  208. if ("r/w" in _output()):
  209. write = True
  210. else:
  211. write = False
  212. _output("Use 'help' command for a list of possible commands")
  213. _output("Please give your command.")
  214. return write
  215. else:
  216. raise InterfaceMismatch()
  217. def model_list():
  218. """List all models."""
  219. # return [(model1, metamodel1), (model2, metamodel2), ...]
  220. # raises UnknownError
  221. if mode != 2:
  222. raise InvalidMode()
  223. _input("model_list")
  224. lst = []
  225. while (_output() != "Ready for command..."):
  226. v = _last_output()
  227. m, mm = v.split(":")
  228. m = m.strip()
  229. mm = mm.strip()
  230. lst.append((m, mm))
  231. return lst
  232. def model_list_full():
  233. """List full information on all models."""
  234. # return [(model1, metamodel1, owner1, group1, permissions1), (model2, metamodel2, owner2, group2, permissions2), ...]
  235. # raises UnknownError
  236. if mode != 2:
  237. raise InvalidMode()
  238. _input("model_list_full")
  239. lst = []
  240. while (_output() != "Ready for command..."):
  241. v = _last_output()
  242. m, mm = v.split(":")
  243. m = m.strip()
  244. mm = mm.strip()
  245. perm, own, grp, m = m.split(" ")
  246. lst.append((m, mm, own, grp, perm))
  247. return lst
  248. def model_overwrite(model_name, new_model=None):
  249. """Upload a new model and overwrite an existing model."""
  250. # return None
  251. # raises UnknownModel
  252. # raises PermissionDenied
  253. # raises CompilationError
  254. # raises UnknownError
  255. if mode != 2:
  256. raise InvalidMode()
  257. if new_model is not None:
  258. try:
  259. compiled = _compile_model(new_model)
  260. except Exception as e:
  261. raise CompilationError(e)
  262. else:
  263. compiled = ["exit"]
  264. _input("model_overwrite")
  265. _output("Which model to overwrite?")
  266. _input(model_name)
  267. if _output() == "Permission denied":
  268. _output("Ready for command...")
  269. raise PermissionDenied()
  270. elif _last_output() == "No such model":
  271. _output("Ready for command...")
  272. raise UnknownModel()
  273. elif _last_output() == "Waiting for model constructors...":
  274. _input(compiled)
  275. _output("Model overwrite success")
  276. _output("Ready for command...")
  277. def user_logout():
  278. """Log out the current user and break the connection."""
  279. # return None
  280. # raises UnknownException
  281. global mode
  282. if mode != 2:
  283. raise InvalidMode()
  284. _input("exit")
  285. mode = 0
  286. def user_delete():
  287. """Removes the current user and break the connection."""
  288. # return None
  289. # raises UnknownException
  290. global mode
  291. if mode != 2:
  292. raise InvalidMode()
  293. _input("self-destruct")
  294. mode = 0
  295. def transformation_add_MT_language():
  296. """Create a new Model Transformation language out of a set of metamodels."""
  297. raise NotImplementedError()
  298. def transformation_add_MT():
  299. """Create a new model transformation."""
  300. raise NotImplementedError()
  301. def transformation_add_AL():
  302. """Create a new action language fragment."""
  303. raise NotImplementedError()
  304. def transformation_add_MANUAL():
  305. """Create a new manual model operation."""
  306. raise NotImplementedError()
  307. def transformation_execute():
  308. """Execute an existing model operation."""
  309. raise NotImplementedError()
  310. def transformation_list():
  311. """List existing model operations."""
  312. raise NotImplementedError()
  313. def transformation_list_full():
  314. """List detailed information on model operations."""
  315. raise NotImplementedError()
  316. def transformation_detail():
  317. """List full details of a a model operation."""
  318. raise NotImplementedError()
  319. def transformation_RAMify():
  320. """Ramify an existing metamodel."""
  321. raise NotImplementedError()
  322. def process_execute():
  323. """Execute a process model."""
  324. raise NotImplementedError()
  325. def permission_modify():
  326. """Modify permissions of a model."""
  327. raise NotImplementedError()
  328. def permission_owner():
  329. """Modify the owning user of a model."""
  330. raise NotImplementedError()
  331. def permission_group():
  332. """Modify the owning group of a model."""
  333. raise NotImplementedError()
  334. def group_create():
  335. """Create a new group."""
  336. raise NotImplementedError()
  337. def group_delete():
  338. """Delete a group of which you are an owner."""
  339. raise NotImplementedError()
  340. def group_owner_add():
  341. """Add a new owning user to a group you own."""
  342. raise NotImplementedError()
  343. def group_owner_delete():
  344. """Delete an owning user to a group you own."""
  345. raise NotImplementedError()
  346. def group_join():
  347. """Add a new user to a group you own."""
  348. raise NotImplementedError()
  349. def group_kick():
  350. """Delete a user from a group you own."""
  351. raise NotImplementedError()
  352. def group_list():
  353. """List existing groups."""
  354. raise NotImplementedError()
  355. def admin_promote():
  356. """Promote a user to admin status."""
  357. raise NotImplementedError()
  358. def admin_demote():
  359. """Demote a user from admin status."""
  360. raise NotImplementedError()
  361. # Actual operations on the model
  362. def element_list():
  363. """Return a list of all IDs and the type of the element"""
  364. # return [(name1, type1), (name2, type2), ...]
  365. # raises UnknownError
  366. if mode != 3:
  367. raise InvalidMode()
  368. _input("list")
  369. lst = []
  370. _output("List of all elements:")
  371. while (_output() != "Please give your command."):
  372. v = _last_output()
  373. m, mm = v.split(":")
  374. m = m.strip()
  375. mm = mm.strip()
  376. lst.append((m, mm))
  377. return lst
  378. def types():
  379. """Return a list of all types usable in the model"""
  380. # return [type1, type2, ...]
  381. # raises UnknownError
  382. if mode != 3:
  383. raise InvalidMode()
  384. _input("types")
  385. _output("List of all types:")
  386. lst = []
  387. while (_output() != "Please give your command."):
  388. v = _last_output()
  389. m, mm = v.split(":")
  390. m = m.strip()
  391. lst.append(m)
  392. return lst
  393. def read(ID):
  394. """Return a tuple of information on the element: its type and source/target (None if not an edge)"""
  395. # return (type, (source, target))
  396. # raises UnknownError
  397. # raises UnknownIdentifier
  398. if mode != 3:
  399. raise InvalidMode()
  400. _input("read")
  401. _output("Element to read?")
  402. _input(ID)
  403. _output("ID: " + str(ID))
  404. if _last_output() == "Unknown element; aborting":
  405. _output("Please give your command.")
  406. raise UnknownIdentifier()
  407. else:
  408. t = _output().split(":")[1].strip()
  409. if (not _output().startswith("Source:")):
  410. rval = (t, None)
  411. else:
  412. src = _last_output().split(":")[1].strip()
  413. trg = _output().split(":")[1].strip()
  414. rval = (t, (src, trg))
  415. while (_output() != "Please give your command."):
  416. pass
  417. return rval
  418. def read_attrs(ID):
  419. """Return a dictionary of attribute value pairs"""
  420. # return {attr1: value1, attr2: value2, ...}
  421. # raises UnknownError
  422. # raises UnknownIdentifier
  423. if mode != 3:
  424. raise InvalidMode()
  425. _input("read")
  426. _output("Element to read?")
  427. _input(ID)
  428. _output("ID: " + str(ID))
  429. if _last_output() == "Unknown element; aborting":
  430. _output("Please give your command.")
  431. raise UnknownIdentifier()
  432. else:
  433. rval = {}
  434. # Skip until attributes
  435. while (_output() != "Attributes:"):
  436. pass
  437. while (_output() != "Please give your command."):
  438. r = _last_output()
  439. key, value = r.split(":")
  440. _, value = value.split("=")
  441. key = json.loads(key.strip())
  442. value = value.strip()
  443. value = None if value == "None" else json.loads(value)
  444. rval[key] = value
  445. return rval
  446. def instantiate(typename, edge=None, ID=""):
  447. """Create a new instance of the specified typename, between the selected elements (if not None), and with the provided ID (if any)"""
  448. # return instantiated_ID
  449. # raises UnknownError
  450. # raises UnknownType
  451. # raises UnknownIdentifier
  452. # raises NotAnEdge
  453. if mode != 3:
  454. raise InvalidMode()
  455. _input("instantiate")
  456. if (_output() == "Permission denied"):
  457. _output("Please give your command.")
  458. raise PermissionDenied()
  459. else:
  460. _input(typename)
  461. if (_output() == "Name of new element?"):
  462. _input(ID)
  463. if (_output() == "Element already exists; aborting"):
  464. _output("Please give your command.")
  465. raise ElementExists()
  466. if (edge is not None) and (_last_output() == "Source name?"):
  467. # Is an edge and we have data
  468. _input(edge[0])
  469. if _output() == "Destination name?":
  470. _input(edge[1])
  471. if _output() == "Instantiation successful!":
  472. ID = _output()
  473. _output("Please give your command.")
  474. return ID
  475. elif _last_output() == "Unknown destination; aborting":
  476. _output("Please give your command.")
  477. raise UnknownIdentifier()
  478. else:
  479. raise InterfaceMismatch(_last_output())
  480. elif _last_output() == "Unknown source; aborting":
  481. _output("Please give your command.")
  482. raise UnknownIdentifier()
  483. else:
  484. raise InterfaceMismatch(_last_output())
  485. elif (edge is None) and (_last_output() != "Source name?"):
  486. # Is no edge and we don't have data
  487. ID = _last_output()
  488. _output("Please give your command.")
  489. return ID
  490. elif (edge is not None) and (_last_output() != "Source name?"):
  491. # Is no edge, but we have edge data to input: ERROR
  492. # Delete the element again
  493. ID = _last_output()
  494. _output("Please give your command.")
  495. delete_element(ID)
  496. raise NotAnEdge()
  497. elif (edge is None) and (_last_output() == "Source name?"):
  498. # Is an edge, but we have no edge data to input: ERROR
  499. # Add an empty source, which is guaranteed not to be there
  500. _input("")
  501. _output("Unknown source; aborting")
  502. _output("Please give your command.")
  503. raise NotAnEdge()
  504. elif (_last_output() == "Permission denied"):
  505. _output("Please give your command.")
  506. raise PermissionDenied()
  507. elif (_last_output() == "Unknown type specified; aborting"):
  508. _output("Please give your command.")
  509. raise UnknownType()
  510. else:
  511. raise InterfaceMismatch(_last_output())
  512. def delete_element(ID):
  513. """Delete the element with the given ID"""
  514. # return None
  515. # raises UnknownError
  516. # raises UnknownIdentifier
  517. if mode != 3:
  518. raise InvalidMode()
  519. _input("delete")
  520. if _output() == "What is the name of the element you want to delete?":
  521. _input(ID)
  522. if _output() == "Deleted!":
  523. _output("Please give your command.")
  524. elif _last_output() == "No such element; aborting":
  525. _output("Please give your command.")
  526. raise UnknownIdentifier()
  527. else:
  528. raise InterfaceMismatch(_last_output())
  529. elif _output() == "Permission denied":
  530. _output("Please give your command.")
  531. raise PermissionDenied()
  532. else:
  533. raise InterfaceMismatch(_last_output())
  534. def attr_assign(ID, attr, value):
  535. """Assign a value to an attribute"""
  536. # return None
  537. # raises UnknownError
  538. # raises UnknownIdentifier
  539. # raises NoSuchAttribute
  540. # raises UnsupportedValue
  541. if mode != 3:
  542. raise InvalidMode()
  543. _input("attr_modify")
  544. _input(ID)
  545. _input(attr)
  546. _input(value)
  547. _consume_to_end()
  548. def attr_assign_code(ID, attr, code):
  549. """Assign a piece of Action Language code to the attribute"""
  550. # return None
  551. # raises UnknownError
  552. # raises UnknownIdentifier
  553. # raises NoSuchAttribute
  554. # raises UnsupportedValue
  555. if mode != 3:
  556. raise InvalidMode()
  557. _input("attr_modify")
  558. _input(ID)
  559. _input(attr)
  560. _compile_AL(code)
  561. def upload(new_model):
  562. """Overwrite the current model with the provided model"""
  563. # return None
  564. # raises UnknownError
  565. # raises CompilationError
  566. if mode != 3:
  567. raise InvalidMode()
  568. _input("upload")
  569. _compile_model(new_model)
  570. def read_outgoing(ID, typename):
  571. """Returns a list of all outgoing associations of a specific type ("" = all)"""
  572. # return [name1, name2, ...]
  573. # raises UnknownError
  574. # raises UnknownIdentifier
  575. # raises UnknownType
  576. if mode != 3:
  577. raise InvalidMode()
  578. _input("read_outgoing")
  579. _input(ID)
  580. _input(typename)
  581. lst = []
  582. while (_output() != "Please give your command."):
  583. lst.append(_last_output())
  584. return lst
  585. def read_incoming(ID, typename):
  586. """Returns a list of all incoming associations of a specific type ("" = all)"""
  587. # return [name1, name2, ...]
  588. # raises UnknownError
  589. # raises UnknownIdentifier
  590. # raises UnknownType
  591. if mode != 3:
  592. raise InvalidMode()
  593. _input("read_incoming")
  594. _input(ID)
  595. _input(typename)
  596. lst = []
  597. while (_output() != "Please give your command."):
  598. lst.append(_last_output())
  599. return lst
  600. def read_association_source(ID):
  601. """Returns the source of an association."""
  602. pass
  603. # returns name
  604. # raises UnknownError
  605. # raises UnknownIdentifier
  606. # raises NotAnAssociation
  607. def read_association_destination(ID):
  608. """Returns the destination of an association."""
  609. pass
  610. # returns name
  611. # raises UnknownError
  612. # raises UnknownIdentifier
  613. # raises NotAnAssociation
  614. def model_exit():
  615. """Leave model modify mode."""
  616. # return None
  617. # raises UnknownError
  618. global mode
  619. if mode != 3:
  620. raise InvalidMode()
  621. _input("exit")
  622. _consume_to_end()
  623. mode = 2