Browse Source

Added some documentation about the HTTP interface

Yentl Van Tendeloo 7 years ago
parent
commit
0df5550f25
4 changed files with 247 additions and 20 deletions
  1. 1 1
      bootstrap/core_algorithm.alc
  2. 0 2
      bootstrap/mini_modify.alc
  3. 246 0
      doc/http.rst
  4. 0 17
      wrappers/classes/modelverse.xml

+ 1 - 1
bootstrap/core_algorithm.alc

@@ -2411,7 +2411,7 @@ Void function user_function_skip_init(user_id : String):
 		elif (cmd == "process_execute"):
 			output(cmd_process_execute(single_input("Process to execute?"), dict_input("Model bindings to use?")))
 		elif (cmd == "process_signature"):
-			output(cmd_process_signature(single_input("Process to execute?")))
+			output(cmd_process_signature(single_input("Process to query?")))
 		elif (cmd == "transformation_between"):
 			output(cmd_transformation_between(dict_input("Source signature?"), dict_input("Target signature?")))
 		elif (cmd == "model_render"):

+ 0 - 2
bootstrap/mini_modify.alc

@@ -473,8 +473,6 @@ Boolean function modify(model : Element, write : Boolean):
 			output(cmd_help_m(write))
 		elif (cmd == "exit"):
 			return True!
-		elif (cmd == "drop"):
-			return False!
 		elif (cmd == "upload"):
 			output(cmd_upload(write, model))
 		elif (cmd == "instantiate_node"):

+ 246 - 0
doc/http.rst

@@ -0,0 +1,246 @@
+HTTP interface
+==============
+
+If you want to use the Modelverse on an as of yet unsupported platform, you will have to make use of the HTTP interface directly.
+While it is possible to directly send HTTP requests, it is recommended to create a wrapper, similar to the Python wrapper mentioned before.
+Otherwise, many of the more complex operations (e.g., process enactment) will quickly result in problems.
+Now follows a detailed description of how the HTTP interface works.
+An example implementation can be found in the Python wrapper, which should prove a valuable starting point for creating a new interface.
+
+Request and Reply format
+------------------------
+
+HTTP requests to the Modelverse use the POST format, and should be directed at the location at which the Modelverse server is running.
+The request itself is a URL encoded form of the following dictionary: {"op": operation, "value": value, "taskname": taskname}.
+In this format, the operation is either *set_input* or *get_output*, with the logical meanings (see further).
+Value is only present if the operation is *set_input*, and contains a JSON serialized value to set as input.
+For multiple simultaneous requests, it is possible to not use a key *value*, but a key *data*.
+If the data key is present, this should contain a JSON serialized representation of multiple invocations.
+The semantics is identical, except that only a single HTTP request (and reply) is used.
+Finally, the taskname indicates the task to which the request is targetted.
+Tasknames are provided by the Modelverse when necessary.
+Fetching data from the Modelverse is done using the *get_output* operation, which is blocking until an output is present.
+Note that a timeout might occur if no output becomes available within the time specified as the HTTP output.
+This is not a problem, but should be handled.
+Output requests are handled in a FIFO manner, as multiple calls can be made for output simultaneously.
+
+Apart from the primitive types usually supported by JSON, action language primitives can also be sent.
+These are JSON serialized as a dictionary, with a single key *value* and its value being the string representation of the element.
+For example, an *If* construct is serialized as {"value":"If"}.
+The Modelverse understands this special case, but your interface should also be able to handle such data.
+Note that communication of these internal primitive types is extremely rare.
+
+The reply to this request is simple.
+For a *set_input* operation, the reply merely indicates that the input is put in the input queue of the task, and the content of the reply can be ignored.
+For a *get_output* operation, the reply contains a JSON serialized representation of the output data put in the Modelverse.
+This is always a primitive type of JSON, and will never be a list or dictionary.
+
+.. note::
+    Communication over HTTP uses a POST request to allow for unlimited amounts of data to be transfered.
+    Instead, the request parameters, normally part of the GET URL, are sent as data of the POST request.
+    The Modelverse ignores GET requests.
+    This nicely follows the REST standards, as all requests indeed alter the state of the Modelverse (contrary to GET requests).
+
+Examples
+^^^^^^^^
+
+To send the integer 1 to the task with name abc in the Modelverse, send the following data in the POST request::
+
+    op=set_input&value=1&taskname=abc
+
+To send the string def to the task with name xyz in the Modelverse, send the following data in the POST request::
+
+    op=set_input&value="def"&taskname=xyz
+
+To send both the integer 1 and the string def to the task with name abc in the Modelverse, send either two seperate requests, or a single request::
+
+    op=set_input&data=[1,"def"]&taskname=xyz
+
+To fetch the output value of a task xyz in the Modelverse, send the following HTTP request, which yields (possibly) the following answer::
+
+    op=get_output&taskname=xyz
+
+    "The output value is a string containing a JSON serialized value."
+
+Startup
+-------
+
+When starting up the Modelverse, only a simple task manager is running.
+To startup a new task, the task manager should be informed of the new name of the task, by sending it input.
+This is done using the following request::
+
+    op=set_input&value="name_of_new_task"&taskname=task_manager
+
+There is no reply from the task manager, and it is assumed that the task can now be used for communication.
+From this point on, communication with the created task can commence, following the operations specified next.
+
+.. warning::
+   This behaviour is likely to change in the near future, where the task manager will output the name of a new task, thereby preventing conflicting tasknames.
+
+Operations
+----------
+
+Upon startup of a task, the communication starts in verbose mode to allow for interactive use.
+This means that initially, every sent input will result in one (or multiple) output values.
+For a wrapper this is cumbersome, as it creates a lot of HTTP requests, and therefore it can be disabled with the input *quiet*.
+A more detailed overview of all operations, their order and possible interleavings, and their possible responses, we refer to the SCCD model in *wrappers/classes/modelverse.xml*.
+
+The first two input values that are to be sent are the username and password, which can happen using the following request::
+
+    op=set_input&data=["my username","my password"]&taskname=name_of_new_task
+
+Depending on the output values received, it can be determined whether this is a new or existing user.
+If this is a new user, a subsequent request should again send the password to confirm the password.
+If this is an existing user, the task continues and is now logged in.
+
+When logged in, there are three possible modes: megamodelling, modelling, and service.
+Apart from the responses mentioned here, several other responses are also possible, though these are exceptions.
+All ordinary responses to operations start with *Success:*, or merely *Success* if there is no value to output.
+
+Megamodelling
+^^^^^^^^^^^^^
+
+In megamodelling mode, which is the first mode to be entered after login, users can modify the megamodel, containing the relation of all models in the Modelverse.
+It is in this mode that new models should be created, models should be deleted, or new transformations be defined.
+Additionally, as all user access control is modelled explicitly, this is also the mode in which user management is done.
+
+There are two operations to allow mode switching: *model_modify* and *service_register*.
+To go to modelling, send *model_modify*, followed by the name of the model you wish to open and the name of the metamodel that should be used.
+For example::
+
+    op=set_input&data=["model_modify","formalisms/ProcessModel","formalisms/SimpleClassDiagrams"]&taskname=xyz
+
+To go to service mode, send *service_register*, followed by the name of the service that is to be registered.
+For example::
+
+    op=set_input&data=["service_register","HUTN_compiler"]&taskname=xyz
+
+In megamodelling mode, the following simple operations are supported.
+For each request, the output normally starts with a *Success*, following the actual return value as a string.
+As all responses are strings, there is some encoding to them (e.g., split on newlines, split on colon, ...).
+Most are trivial to deserialize when the result comes in, and therefore we refer to the SCCD model.
+While operation and parameters are shown distinct in the table, the HTTP request merely sends them in exactly the same fashion.
+For example::
+    
+    op=set_input&data=["model_mode","formalisms/ProcessModel","formalisms/PM"]&taskname=xyz
+
+
+Some more complex operations are mentioned below these standard operations.
+
++-------------------------------+----------------------------------------+
+| operation                     | parameters                             |
++-------------------------------+----------------------------------------+
+| model_move                    | model_name, new_location               |
+| process_signature             | process_name                           |
+| transformation_between        | source_name, target_name               |
+| model_render                  | model_name, mapper_name, rendered_name |
+| model_rendered                | model_name, mapper_name                |
+| verify                        | model_name, metamodel_name             |
+| model_delete                  | model_name                             |
+| model_list                    | location                               |
+| model_list_full               | location                               |
+| permission_modify             | model_name, permissions                |
+| permission_owner              | model_name, owner                      |
+| permission_group              | model_name, group                      |
+| group_create                  | group                                  |
+| group_delete                  | group                                  |
+| group_owner_add               | group, user                            |
+| group_owner_delete            | group, user                            |
+| group_join                    | group, user                            |
+| group_kick                    | group, user                            |
+| group_list                    |                                        |
+| admin_promote                 | user                                   |
+| admin_demote                  | user                                   |
+| user_password                 | user, password                         |
+| transformation_read_signature | transformation_name                    |
+| verbose                       |                                        |
+| quiet                         |                                        |
+| folder_create                 | location                               |
+| add_conformance               | model_name, metamodel_name             |
+| model_types                   | model_name                             |
+| AL_text                       | location                               |
+| model_add                     | metamodel_name, model_name, code       |
++-------------------------------+----------------------------------------+
+
+More complex operations have multiple phases, as there is a modification step involved, or a preliminary check before the next piece of data can be forwarded.
+These operations are presented next.
+
++---------------------------+---------------------------------------------------+
+| operation                 | parameters                                        |
++---------------------------+---------------------------------------------------+
+| model_overwrite           | model_name, metamodel_name                        |
+| transformation_add_MANUAL | source_models\*, target_models\*, name            |
+| transformation_add_AL     | source_models\*, target_models\*, name            |
+| transformation_add_MT     | source_models\*, target_models\*, name            |
+| transformation_execute    | activity_name, source_models\*, target_models\*   |
+| process_execute           | process_name, model_bindings\*                    |
++---------------------------+---------------------------------------------------+
+
+Parameters marked with a \* are actually dictionaries, and should be sent as such.
+Since the Modelverse has no primitive notion of dictionaries, a dictionary is expanded as a sequence of key value pairs, terminated with an empty key.
+For example, the dictionary {"abc": "def", "ghi": "jkl"} is sent as five individual requests (or a single data request)::
+
+    ...&data=["abc","def","ghi","jkl",""]&...
+
+For the model_overwrite operation, the Modelverse will first perform some checks as to whether the overwritten model can indeed be overwritten.
+If so, it will output the reply *Waiting for model constructors...*, after which the actual code may be sent.
+The operations starting with transformation_add are similar, but they have two phases.
+First, they output the name of the merged metamodel, ready to be RAMified.
+There is then the possibility to modify this metamodel before RAMification starts, by logging in using a different task, modifying the model, and storing the changes.
+As soon as all changes are made, any input will initiate RAMification.
+Second, the Modelverse will query for the code that specify the transformation.
+For manual operations, this query is not done.
+For AL, this query expects ActionLanguage code.
+For MT, this query expects a model conforming to the RAMified metamodel.
+Of course, these constructors can be passed an empty model, in which case the models have to be updated later on using model_modify.
+
+The transformation_execute operation and process_execute are special operations, in the sense that they (potentially) spawn other tasks.
+The output value of these operations is the name of a newly spawned task, on which execution should continue.
+These tasks might not be identical to other tasks, in the sense that they are purely able to communicate with the currently executing operation.
+This operation is rather complex, and we refer to the SCCD model for detailed information.
+The process_execute operation is similar, but instead of outputting only a single taskname, we output multiple, combined with the activity that spawned it.
+
+Modelling
+^^^^^^^^^
+
+In modelling mode, a single model is opened and ready to be modified.
+There are several supported operations, most of which are simple to use.
+To switch back to megamodelling mode, send the *exit* input.
+
++-------------------------------+-------------------------------+
+| operation                     | parameters                    |
++-------------------------------+-------------------------------+
+| help                          |                               |
+| instantiate_node              | type, element                 |
+| instantiate_edge              | type, element, source, target |
+| attr_add                      | element, attribute, value     |
+| attr_delete                   | element, attribute            |
+| attr_name                     | element, attribute, name      |
+| attr_type                     | element, attribute, type      |
+| attr_optional                 | element, attribute, optional  |
+| delete                        | element                       |
+| list                          |                               |
+| list_full                     |                               |
+| JSON                          |                               |
+| read_outgoing                 | element, type                 |
+| read_incoming                 | element, type                 |
+| read                          | element                       |
+| read_attrs                    | element                       |
+| read_defined_attrs            | element                       |
+| types                         |                               |
+| retype                        | element, type                 |
+| read_association_source       | element                       |
+| read_association_destination  | element                       |
+| connections_between           | element, element              |
+| all_instances                 | type                          |
+| define_attribute              | element, attribute, type      |
+| undefine_attribute            | element, attribute            |
++-------------------------------+-------------------------------+
+
+Some additional operations are again available that work in two phases.
+These operations are *attr_add_code* and *upload*, which first perform some checks and then wait for AL code or a model.
+
+Service
+^^^^^^^
+
+In service mode, the Modelverse blocks until the input *service_stop* is received, and this task is used to process the service.

+ 0 - 17
wrappers/classes/modelverse.xml

@@ -1846,7 +1846,6 @@
                         <state id="recognized" initial="manual">
                             <state id="manual">
                                 <transition cond="self.expect_action('exit')" target="../../../../leaving_manual"/>
-                                <transition cond="self.expect_action('drop')" target="../../../../leaving_manual_drop"/>
 
                                 <transition cond="self.actions and self.actions[0]['parameters'][0] != self.current_model" target="../../../../leaving_manual"/>
                             </state>
@@ -1857,12 +1856,6 @@
                                         <parameter expr="'exit'"/>
                                     </raise>
                                 </transition>
-
-                                <transition cond="self.expect_action('drop')" target="../../../../operations/store_on_scripted/history">
-                                    <raise event="request">
-                                        <parameter expr="'drop'"/>
-                                    </raise>
-                                </transition>
                             </state>
 
                             <transition cond="self.expect_action('element_list')" target="../../../operations/element_list">
@@ -2097,16 +2090,6 @@
 
                     <transition cond="self.expect_response('Success', pop=True)" target="../wait_for_action/megamodelling"/>
                 </state>
-
-                <state id="leaving_manual_drop">
-                    <onentry>
-                        <raise event="request">
-                            <parameter expr="'drop'"/>
-                        </raise>
-                    </onentry>
-
-                    <transition cond="self.expect_response('Success', pop=True)" target="../wait_for_action/megamodelling"/>
-                </state>
             </state>
 
             <state id="queue">