123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247 |
- 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.
|