AMIL Language and Interpreter

Author: Basil Krikeles, BAE Systems - Technology Solutions
Version 1.0
March 5, 2011

Introduction

The purpose of AMIL is to serve as the ARRoW Model Interconnection Language. AMIL is a meta-model for modeling interconnections between heterogeneous models while making minimal assumptions about the nature of these models. For example, AMIL makes no assumption about shared meta-models as is the case in many modeling tool chains such as Eclipse Modeling Framework. The strategy in AMIL is to to only assume that external models and modeling tools provide some sort of access interface and that they are capable of exporting unique identifiers for modeling elements that are relevant across multiple models. AMIL creates proxies for these elements as nodes in an attributed graph. These nodes can be associated with related nodes (proxie of other model elements) with attributed edges. The approach is fundamentally lazy, i.e. represent only the proxies that are required and only introduce the interconnections that are useful. The underlying attributed graph semantics provides a general and extremely flexible foundation in support of the model interconnection semantics. Both nodes and edges of the interconnection network contain lists of key-value pairs that can be extended without arbitrary limit. New relationship types can be introduced on demand without compromising performance.

Retrieval of information from the graph has additional semantics that enables the dynamic extraction of information from the authoritative source model (see getNodes). With the added semantics, AMIL is arbitrarily extensible (always in a lazy fashion) to accomodate heterogeneity in the external models.



AMIL Interpreter Interface

AMIL Interpreter exposes one interface with the following signature:
String execute(String amilStmt)
where amilStmt is a valid AMIL statement formatted as a JSON string, and the return value is also a JSON formatted string containing the results of the execution of the amilStmt. This document lists the supported AMIL statements and provides examples of their syntax in terms of JSON.

The AMIL interpreter interface with its JSON binding can be easily exposed as a Web Service. Java applications can embed the AMIL interpreter. A command line client is also included.

Execution of AMIL statements has transactional semantics. The statement is executed within a transaction, and either all of its parts succeed or all fail.

The AmilInterpreter constructor has the following signature:
AmilInterpreter (String dbDir)
where dbDir is a directory where the database files are stored. This directory can be passed to the front-end web service, can be read from a properties file, or it can be hard coded.

AMIL Command Line tool

It is implemented in the class: com.ait.meta.lang.Amil.java
java -Damil_server=dbDir -classpath=... com.ait.meta.lang.Amil amilFile [amilFile]
where each amilFile contains a single AMIL statement.

AMIL Statement Syntax in JSON format

AMILStatement =>
[Action, SequenceOfNodeOrEdge]

Action =>
{
    action : actionName,
    preConditions : {predicateList},
    postConditions : {predicateList}
}

actionName => 
"createNodes" | "createLinks" | "getNodesRaw" | "getNodes" | "getLinks" | "deleteNodes" | "deleteLinks" | "updateNodes" | "clearDatabase"

PredicateList => PredicateCall | PredicateCall, PredicateList

PradicateCall => predicateName : [parameterList]

ParameterList=> String | String, ParameterList

SequenceOfNodeOrEdge=>
    NodeOrEdge,
    NodeOrEdge, SequenceOfNodeOrEdge

NodeOrEdge=>
{
        type : nodeOrEdgeType,
        uniqueId : {nameValueList}
}

NameValueList=> name : value | name : value, NameValueList

NodeOrEdgeType=> node | edge

AMIL Statements

  1. createNodes 
  2. createLinks
  3. getNodesRaw 
  4. getNodes 
  5. getLinks 
  6. deleteNodes 
  7. deleteLinks
  8. updateNodes
  9. clearDatabase
  10. getClosure

Statement Description

createNodes

Example
[
    {
        "action" : "createNodes",
        "preConditions" : {},
        "postConditions" : {}       
    },
   
    {
        "type" : "node",
        "massOfFrame1" :
        {
            "modelType" : "Behavior",
            "toolName" : "OpenModelica",
            "elementId" : "A1979_z",
            "projectId" : "//server/meta/modelica/proj.mod"
        }
    },
       
    {
        "type" : "node",
        "massOfFrame2" :
        {
            "modelType" : "SysML",
            "toolName" : "MagicDraw",
            "elementId" : "123",
            "projectId" : "//server/meta/sysml/proj.mzip"
        }
    }
]


createLinks

Example:
[
    {
        "action" : "createLinks",
        "preConditions" : {},
        "postConditions" : {}       
    },
       
    {
        "type" : "edge",
        "reference1" :
        {
            "type" : "REFERENCE",
            "from" : "massOfFrame1",
            "to" : "massOfFrame2"
        }
    }
]


getNodesRaw

Synopsis: Unconditionally retrieve the nodes listed according to their unique identifier. It does not take any actions based on the semantics of the node, e.g. an valueType property that might be present in a node.
Example:
[
    {
        "action" : "getNodesRaw",
        "preConditions" : {},
        "postConditions" : {}       
    },
   
    {
        "massOfFrame1" : {}
    },
       
    {
        "massOfFrame2" : {}
    }   
   
]


getNodes

Synopsis: Retrieve the nodes listed according to their unique identifier but subject to configurable semantic interpretation based on the optional valueType property. If valueType is not present the result is immediate and equivalent to the action of getNodesRaw on that node. This is the default action. If the property valueType is present and its  value is externalCall, then the property className should also be present. Instead of returning the node, getNodes returns the result of invoking the class with name className with the node, serialize in JSON format, as a parameter. The target class must implement the External interface This is one mechanism that enables the introduction of levels of indirection in accessing the proxies in the graph. The external call can invoke an external tool in order to dynamically retrieve information from its counterpart. 

Example:
[
    {
        "action" : "getNodes",
        "preConditions" : {},
        "postConditions" : {}       
    },
   
    {
        "massOfFrame" : {}
    }
]

Where massOfFrame was created as follows:
[
    {
        "action" : "createNodes",
        "preConditions" : {},
        "postConditions" : {}       
    },
       
    {
        "type" : "node",
        "massOfFrame" :
        {
            "modelType" : "SysML",
            "toolName" : "MagicDraw",
            "elementId" : "123",
            "projectId" : "//server/meta/sysml/proj.mzip",
            "valueType" : "external",
            "className" : "com.ait.meta.lang.ExternSample"           
        }
    }
]


getLinks

Example
[
    {
        "action" : "getLinks",
        "preConditions" : {},
        "postConditions" : {},
        "depth" : "2"       
    },

    {
        "type" : "edge",
        "dummy" :
        {
            "type" : "REFERENCE",
            "from" : "a",
            "to" : {}
        }
    }   
]


deleteNodes

Example

[
    {
        "action" : "deleteNodes",
        "preConditions" : {},
        "postConditions" : {}       
    },
   
    {
        "a" : {}
    },
    {
        "d" : {}
    },
    {
        "foo" : {}
    }       
]


deleteLinks

Example

[
    {
        "action" : "deleteLinks",
        "preConditions" : {},
        "postConditions" : {},   
    },

    {
        "type" : "edge",
        "dummy" :
        {
            "type" : "REFERENCE",
            "from" : "a",
            "to" : "b"
        }
    },
    {
        "type" : "edge",
        "dummy" :
        {
            "type" : "REFERENCE",
            "from" : "d",
            "to" : "e"
        }
    }   
]


updateNodes

Example

[
    {
        "action" : "updateNodes",
        "preConditions" : {},
        "postConditions" : {}       
    },
   
    {
        "type" : "node",
        "a" :
        {
            "modelType" : "b_x",
            "toolName" : "b_y",
            "elementId" : "b_z",
            "projectId" : "b_proj"
        }
    },
   
    {
        "type" : "node",
        "e" :
        {
            "modelType" : "f_x",
            "toolName" : "f_y",
            "elementId" : "f_z",
            "projectId" : "f_proj"
        }
    }                   
]


clearDatabase

Note: After a clearDatabase statement it appears that in the current implementation all indices are removed. Since getNodes and getNodesRaw rely on the index, the underlying Lucene implementation will generate a runtime error if an attempt is made to call them after the clearDatabase call.

Example


[
    {
        "action" : "clearDatabase",
        "preConditions" : {},
        "postConditions" : {}       
    }
]


getClosure

Example

[
    {
        "action" : "getClosure",
        "entryPoints" : ["a", "anotherNode"],
        "relationships" : ["r1", "r2", "rel"],
        "doRelationshipClosure" : "",
        "preConditions" : {},
        "postConditions" : {}           
    }
]

Semantics

The getClosure action starts by retrieving the nodes referenced in the "entryPoints" property. Starting with these nodes it retrieves all nodes that can be reached by following relationships referenced in the "relationships" property. If the "doRelationshipClosure" property is not present, the getClosure action will return the reachable nodes (including the entry point nodes) and the relationships (links) that are referenced in the "relationships" property. If the "doRelationshipClosure" property is  present then the result of the action are the nodes reached plus all the relationships (links) between these nodes whether they are referenced in the "relationships" property or not. The value of the "doRelationshipClosure" property does not matter, it is its presence or absence that is used.

Appendix A - Interfaces

External

public interface External {
    /**
     *
     * @param params are the input parameters of
     * the external call as key-value pairs,
     * same as the properties (key-val pairs) stored in the AMIL node
     * @return the results as key-value pairs
     *
     * When implementing this use whatever means necessary to
     * make the external call using parameters extracted from params
     * params has everything that was in the AMIL node
     * The result should have everything produced by the computation.
     */
    Map<String, String> invoke(Map<String, String> params);
}