A service mogram represents a service model that is executed by a dynamic federation of services. In other words a mogram exerts the collaborating service providers in a service federation created at runtime as specified by the mogram. Mograms are written in the Service Modeling Language (SML) that consists of two parts: Context Modeling Language (CML) and Exertion-Oriented Language (EOL). The former is used to specify data models (data contexts) for exertions and collections of interrelated functional compositions - context models. While CML is used for declarative service-oriented programming, EOL is focused on object-oriented composites of services - exertions. A model is a declarative representation of something, especially a system, phenomenon, or service that accounts for its properties and is used to study its characteristics expressed in terms of service variables associated with functional compositions.

In every computing process variables represent data elements and the number of variables increases with the increased complexity of the problems being solved. The value of a service variable is not necessarily part of an equation or formula as in mathematics - its value is a result of service execution or the service itself. Handling large sets of interconnected variables for adaptive complex systems requires adequate programming methodologies.

In SORCER interrelated service variables of a model are called entries. An entry used in a model refers by name (path) to one of the pieces of data value. A value can be explicit or calculated by a subroutine. A parameter is a special kind of entry, named in a subroutine by its path (semantic name) and returning the value of the entry. These values, called arguments, that are used in subroutines are defined by input entries of the model. Most parameters are functionals – functions that take functions as their arguments. A selected subset of output entries defines a studied response of the model. Just as in standard mathematical usage, the argument is the actual input passed to a subroutine, whereas the parameter is the variable inside the implementation of the subroutine. Depending on the type of subroutine (evaluation, invocation, service, or composite evaluation) we distinguish four types of basic context models (EntModel, ParModel, SrvModel, VarModel) with ServiceContext as the data model for exertions, as depicted in the bottom-left section of (Service Orientation diagram).

Data Contexts (Data Models)

The data context declared with the context operator describes the data that service providers work on. It is a data structure that describes service provider controlled vocabulary (taxonomy) defined by the provider’s developer. Each term in a taxonomy is in one or more parent-child relationship to other terms in the context taxonomy. Conceptually a data context is similar in structure to a files system, where taxonomy paths refer to objects instead to files. The meaning of a hierarchical path is generalization/specification. A requestor submitting a context to a provider has to comply with that taxonomy as it specifies how the context data is interpreted and used by the provider.

Each context entry (association) is considered as a variable, where a taxonomic path is its semantic name associated with its value. Paths of the data context form domain specific inputs and outputs used by service providers. Context input entries are used by the providers to compute output entries that are returned in the output context. There are many types of entries: common entries (ent operator), input entries (inEnt operator), output entries (outEnt operator), input/output enties (inoutEnt operator). Entry declared with a path only has its value undefined, that is Context.none. Understanding the context taxonomy and semantics of entry types a provider can retrieve from its context also all input, output, inout entries, or entries marked with domain specific relationships. Below, the operators context, add, value, get, asis, put illustrate how a context is created and how its data can be used and updated in the data context.

    Context cxt = context(ent("arg/x1", 1.1), ent("arg/x2", 1.2),
            ent("arg/x3", 1.3), ent("arg/x4", 1.4), ent("arg/x5", 1.5));

    add(cxt, ent("arg/x6", 1.6));

    assertTrue(cxt instanceof Context);

    assertTrue(value(cxt, "arg/x1").equals(1.1));
    assertTrue(get(cxt, "arg/x1").equals(1.1));
    assertTrue(asis(cxt, "arg/x1").equals(1.1));

    // aliasing with an reactive value entry - rvEnt
    put(cxt, rvEnt("arg/x1", value(cxt, "arg/x5")));
    assertTrue(get(cxt, "arg/x1").equals(1.5));

    Context subcxt = context(cxt, list("arg/x4", "arg/x5"));
    logger.info("subcontext: " + subcxt);
    assertNull(get(subcxt, "arg/x1"));
    assertNull(get(subcxt, "arg/x2"));
    assertNull(get(subcxt, "arg/x3"));
    assertTrue(get(cxt, "arg/x4").equals(1.4));
    assertTrue(get(cxt, "arg/x5").equals(1.5));
    assertTrue(get(cxt, "arg/x6").equals(1.6));

Context entries can be annotated as input, output, and both as input and output, and queried for their annotations.

    add(cxt, outEnt("out/y1", 1.7));
    add(cxt, outEnt("out/y2", 1.8));
    add(cxt, inoutEnt("par/z", 1.9));

Positional Context maintains both paths and indexes.

    // return the value at index 1 and 6 in cxt
    assertTrue(get(cxt, 1).equals(1.1));
    assertTrue(get(cxt, 6).equals(1.6));

    // return the value at position 1 and 6 in cxt
    assertTrue(getAt(cxt, 1).equals(1.1));
    assertTrue(getAt(cxt, 6).equals(1.6));

    // return selected values at given positions in cxt
    assertEquals(select(cxt, 2, 4, 5), list(1.2, 1.4, 1.5));

    // get input and output contexts
    List<String> inputs = list("arg/x2", "arg/x3", "arg/x4", "arg/x5", "par/z");
    List<String> outputs = list("out/y1", "out/y2", "par/z");
    assertTrue(inputs.equals(paths(inputs(cxt))));
    assertTrue(outputs.equals(paths(outputs(cxt))));

    // return all values of inEntries
    assertEquals(inValues(cxt), list(1.5, 1.4, 1.3, 1.2, 1.9));

    // return all paths of inEntries
    assertEquals(inPaths(cxt), list("arg/x5", "arg/x4", "arg/x3", "arg/x2", "par/z"));

    // return all values of outEntries
    assertEquals(outValues(cxt), list(1.8, 1.7, 1.9));

    // return all paths of outEntries
    assertEquals(outPaths(cxt), list("out/y2", "out/y1", "par/z"));

Context pipes (declared with the pipe operator) specify how data flows between contexts of component exertions that are shared between service providers in service collaborations. Learn more about exertions and how pipes are used with job exertions at the tutorial page Service Exertions.

Review the wide range of data-models in examples/sml/src/test/java/sorcer/sml/contexts/DataModels.

Ent-Models

A data context is a dictionary composed of path-value entries, i.e., associations, such that each path referring to its value as is appears at most once in the context. A path of each entry is an implicit invocation as is parameter. If that parameter is an object then the object is returned as is. However, everything that has an independent existence is expressed in entry models (ent-models for short) as active relationships between entries that can implement sorcer.service.Evaluation interface. In contrast to data contexts, an ent-model entry is evaluated and then the value of the entry of the sorcer.service.Evaluation type is sorcer.service.Evaluation#getValue(), whereas in a data model the object that implements the sorcer.service.Evaluation interface is returned as is.

    // use the entModel operator to create an EntModel the same way as
    // a regular data context or convert a data context to entModel(<context>)
    Model cxt = entModel(ent("arg/x1", 1.0), ent("arg/x2", 2.0),
         ent("arg/x3", 3.0), ent("arg/x4", 4.0), ent("arg/x5", 5.0));

    add(cxt, ent("arg/x6", 6.0));
    assertTrue(value(cxt, "arg/x6").equals(6.0));

    // entries are entities of the Evaluation type
    // entries in models are evaluated
    put(cxt, ent("arg/x6", ent("overwrite", 20.0)));
    assertTrue(value(cxt, "arg/x6").equals(20.0));

    // invoker is of the Invocation type
    add(cxt, ent("arg/x7", invoker("x1 + x3", ents("x1", "x3"))));

    assertTrue(value(cxt, "arg/x7").equals(4.0));
    assertTrue(asis((Context)cxt, "arg/x7") instanceof Entry);
    assertTrue(asis((Entry)asis((Context)cxt, "arg/x7")) instanceof Invocation);

Declare the model response and evaluate the contex tmodel.

    // evaluate the model
    addResponse(cxt, "invoke");
    value(cxt);
    assertTrue(value(cxt).equals(4.0));

    // evaluate the model with overwritten inputs
    Double result = value(cxt, ent("arg/x1", 2.0), ent("arg/x2", 3.0));
    assertTrue(result.equals(5.0));


    // evaluate the model with a new subroutine
    add(cxt, ent("invoke", invoker("x6 * x7 + x1", ents("x1", "x6", "x7"))));
    result = value(cxt, ent("arg/x6", 6.0), ent("arg/x7", 7.0));
    assertTrue(result.equals(44.0));

The model response context may include multiple entries

    add(cxt, ent("add", invoker("x1 + x3", ents("x1", "x3"))));
    add(cxt, ent("multiply", invoker("x4 * x5", ents("x4", "x5"))));

    // two outpus declared for the result
    addResponse(cxt, "add", "multiply");

    // evaluate the model
    Context result = (Context) response(cxt);
    assertTrue(result.equals(context(ent("add", 4.0), ent("multiply", 20.0))));

Exert the context model

  // exert the model
  Model model = exert(cxt);
  Context result = response(model);
  assertTrue(result.equals(context(ent("add", 4.0), ent("multiply", 20.0))));

Review the wide range of ent-models in examples/sml/src/test/java/sorcer/sml/contexts/EntModels.

Par-Models

A parameter entry, for short a par, is a special kind of variable, used in context models to refer to one of the named pieces of data as used in ent-models and additionally as the value calculated by a par’s procedural attachment called an invoker. An invoker is an object of the sorcer.service.Invocation type. A value returned by an invoker is defined by its sorcer.service.Invocation#invoke(Context context) operation with the argument context used first for its dependent entries before its model entries are used. Invocation is a kind of evaluation as in ent-models but additionally with its own private scope applied first for binding to the invoker dependent variables.

Collections of pars with other entries of ent-models constitute par-models that can be used in exertions as data contexts or as standalone modeling local/remote service providers. In contrast to ent-models, a par-model entry of the sorcer.service.Invocation type is sorcer.service.Invocation#getValue(), whereas in a ent-model the object that implements the sorcer.service.Invocation interface is returned as is.

Review the wide range of task par-models in examples/sml/src/test/java/sorcer/pml/modeling.

Srv-Models

A service entry, for short a srv, is a special kind of variable, used in service models to refer to the result of service expressed as a mogram. An mogram is an object of the sorcer.service.Mogram type. A value returned by a mogram is defined by the data context of sorcer.service.Mogram#exert() operation. Note that exertions, context models, and data contexts are mograms, therefore all of them can provides services for srv-models. Exerting is an invocation that exerts a federation of service providers specified by a mogram. It is a kind of invocation as in par-models when mograms use their own scope applied first before binding their dependent variables to the srvs of their containing srv-model.

Collections of srvs with other entries of par-models constitute srv-models that can be used in exertions as data contexts or as standalone modeling local/remote service providers. Note that exertions implement both sorcer.service.Evaluation and sorcer.service.Invocation interfaces but context models only the ’sorcer.service.Modelinterface as depicted in <a href="images/mogramming.png">Service Orientation diagram</a>. Therefore exertions can be used as evaluators of ent-model entries, as invokers of pars, and as services of srvs. However, data and context models can be called only in srv-models with the result determined by sorcer.service.Model#getResult()that is indirectly caled viasorcer.service.Mogram#exert()`.

Review the wide range of srv-models in examples/sml/src/test/java/sorcer/contexts/SrvModels.

Var-Models

A multi-fidelity entry, for short a var, is a aggregated entry used in context models to refer a collection of triplets: <evaluator, getter, setter>. Each triplet is called a var-fidelitity, where:

1.  An evaluator is an evaluation with the argument vars that define the var dependency chain.
2.  A getter is a pipeline of filters processing and returning the result of evaluation.
3.  A setter assigns a value that is a quantity filtered out from the output of the current evaluator.

Vars implement sorcer.service.modeling.CompositeEvaluation that extends the sorcer.service.Evaluation interface. The CompositeEvaluation interface allows to access an evaluator, getter, and setter of a selected var-fidelity. The selected var-fidelity defines the current value of the var: setter(getter(evaluator))). Var-models are par-models so can be reconfigured at runtime as needed by their related pars to update fidelities of vars at runtime.

The input var is typically the entry representing the value being manipulated or changed and the output var is the observed result of the input vars being manipulated. If there is a relation specifying output in terms of given inputs, then output is known as an “output var” and the var’s inputs are “argument vars”. Argument vars can be either output or input vars.

A var-model describes the desired result of the output vars, without explicitly listing instructions or steps that need to be carried out to achieve the result. The focus is on how vars are connected (composed) in the scope of the model, unlike imperative programming, which focuses on how evaluators calculate. Three types of var-models can be created: response, parametric, and optimization.

These var-models are declared using the SORCER modeling library that is not part of the open source SORCER.

SML examples in the SORCER Project

  1. Collections used in SML
    • sml/src/test/java/sorcer/arithmetic/collections
  2. Service signatures, providers, services (exertions), and context models (contexts and models) in SML
    • sml/test/java/sorcer/sml/services
  3. Intro to service provider/requestor development
    • service/src/main
    • service/src/test
    • service/src/netlet and
    • worker/src/main/java/sorcer/worker/provider
    • worker/src/main/java/sorcer/worker/requestor
    • worker/test/java/sorcer/worker/tests
  4. Arithmetic providers and requestors, contexts and exertions as providers
    • sml/main/java/sorcer/arithmetic/provider
    • sml/main/java/sorcer/arithmetic/requestor
    • sml/main/netlets
  5. Service contexts
    • sml/test/java/sorcer/sml/contexts
  6. Exertions: tasks, jobs, and blocks
    • sml/test/java/sorcer/sml/tasks
    • sml/test/java/sorcer/sml/jobs
    • sml/test/java/sorcer/sml/blocks
  7. Data models (data contexts), entry models and service models
    • sml/test/java/sorcer/sml/contexts
  8. Par-models, providers and agents
    • pml/main/java/sorcer/pml/model
    • pml/main/java/sorcer/pml/provider
    • pml/test/java/sorcer/pml/modeling

Back to top

Version: 1.0-SNAPSHOT. Last Published: 2020-01-18.