Coaty JS Documentation

Coaty Communication Events

This specification conforms to Coaty 2

Table of Contents

Introduction

Communication in a Coaty application is based on communication events which are published by Coaty agents and which can be subscribed to by Coaty agents. Coaty provides an essential set of event-based communication patterns to discover, query, share, and update data on demand in a distributed system, and to request execution of context-filtered remote operations.

Event Patterns

The following one-way and two-way communication event patterns are defined:

Event Structure

A Coaty communication event has the following characteristics:

The definition of an event filter is specific to the following event type:

UUIDs (Universally Unique Identifiers) must conform to the UUID version 4 format as specified in RFC 4122. In the string representation of a UUID the hexadecimal values “a” through “f” are output as lower case characters.

Event Data

Communication event data to be published consists of attribute-value pairs in JavaScript Object Notation format (JSON, see RFC 4627). Each communication event type defines its own data schema.

In the following sections, the JSON data schema for specific event types are specified. Common type definitions include:

Note: Raw events and IO value events with raw data do not conform to this specification. They are published as binary data encoded in any application-specific format.

The Advertise event is used to communicate Coaty objects to agents interested in a specific type of object. Advertise events can be observed based on either an object’s core type (coreType) or an object’s object type (objectType).

An Advertise event accepts this JSON data:

{
  "object": <object>,
  "privateData": <any>
}

The property privateData is optional. It contains application-specific options in the form of key-value pairs.

Deadvertise Event Data

The Deadvertise event works in combination with the Advertise event. By publishing a Deadvertise event with the unique object ID of an object, you can notify observers that this object (which has been advertised earlier) is no longer available.

A Deadvertise event accepts this JSON data:

{ "objectIds": [ UUID1, UUID2, ... ] }

The objectIds property specifies the unique IDs of all objects that should be deadvertised.

Channel Event Data

The Channel event provides a very efficient way of pushing any type of Coaty objects to observers that share a specific channel identifier. It differs from Advertise events in that these are pushing objects of specific core or object types to interested observers.

A Channel event accepts the following JSON data:

{
  "object": <object1>,
  "privateData": <any>
}

or

{
  "objects": [ <object1>, <object2>, ... ],
  "privateData": <any>
}

The property privateData is optional. It contains application-specific options in the form of key-value pairs.

Discover - Resolve Event Data

The two-way Discover-Resolve event pattern can be used to discover Coaty objects of a certain core or object type and/or with a certain object ID or external ID.

A Discover request event accepts the following JSON data:

{ 
    "externalId": "extId",
    "objectTypes": ["object type", ...],
    "coreTypes": ["core type", ...]
}

Discover an object by specifying its external ID (e.g. barcode scan id). Since external IDs are not guaranteed to be unique, results can be restricted by one of the specified object types or core types (optional).

{ "objectId": UUID }

Discover an object based on its object ID.

{ "externalId": "extId", "objectId": UUID }

Discover an object based on its external ID and its object ID. Useful for finding an object with an external representation that is persisted in an external data store.

{ "objectTypes": ["object type", ...], "coreTypes": ["core type", ...] }

Discover an object based on the specified object type or core type. Exactly one of the properties objectTypes or coreTypes must be specified. To discover a series of objects based on type restrictions and object attribute filtering, use the Query - Retrieve event pattern.

A Resolve response event accepts the following JSON data:

{
  "object": <object>,
  "privateData": <any>
}

or

{
  "relatedObjects": [<object>, ...],
  "privateData": <any>
}

or

{
  "object": <object>,
  "relatedObjects": [<object>, ...],
  "privateData": <any>
}

The property privateData is optional. It contains application-specific options in the form of key-value pairs.

Query - Retrieve Event Data

The two-way Query-Retrieve event pattern is used to query objects based on object type restrictions, object attribute filtering and joining conditions, and ordering criteria.

The Query request event accepts this JSON data:

{
  "objectTypes": ["object type", ...],
  "coreTypes": ["core type", ...],
  "objectFilter": ObjectFilter,
  "objectJoinConditions": ObjectJoinCondition | ObjectJoinCondition[]
}

Query objects are retrieved based on the specified object types or core types, an optional object filter, and optional join conditions. Exactly one of the properties objectTypes or coreTypes must be specified.

The optional objectFilter defines conditions for filtering and arranging result objects:

{
  // Conditions for filtering objects by logical 'and' or 'or' combination.
  "conditions": ["<propertyName>[.<subpropertyName>]*", <filterOperator1>, ...<filterOperands1>] |
  {
     and: | or: [
       ["<propertyName1>[.<subpropertyName1>]*", <filterOperator1>, ...<filterOperands1>],
       ["<propertyName2>[.<subpropertyName2>]*", <filterOperator2>, ...<filterOperands2>],
       ...
     ]
  },

  // Sort result objects by the given property names (optional)
  "orderByProperties": [["<propertyName>[.<subpropertyName>]*", "Asc" | "Desc"], ...],

  // Take no more than the given number of results (optional).
  "take": <number>,

  // Skip the given number of results (optional).
  "skip": <number>

}

The following filter operators are defined (for details see framework source documentation of enum ObjectFilterOperator):

LessThan,
LessThanOrEqual,
GreaterThan,
GreaterThanOrEqual,
Between,
NotBetween,
Like,
Equals,
NotEquals,
Exists,
NotExists,
Contains,
NotContains,
In,
NotIn

The optional join conditions are used to join related objects into a result set of objects. Result objects are augmented by resolving object references to related objects and storing them in an extra property. A join condition looks like the following:

{
  // Specifies the property name of an object reference to be resolved by joining.
  "localProperty": "<property to resolve>",

  // Specifies the name of the extra property to be added to the result objects.
  "asProperty": "<extra property for resolved object(s)>",

  // Specifies whether the value of the local property is an array
  // whose individual elements should be matched for equality against the value of the
  // corresponding property of the related object (optional).
  "isLocalPropertyArray": <boolean>,

  // Specifies whether the join between the 'localProperty' and the corresponding
  // property of the related object is a one to one relation. If true, the extra property
  // 'asProperty' contains a single related object; otherwise it contains an array of
  // related objects (optional).
  "isOneToOneRelation": <boolean>

}

The Retrieve response event accepts the following JSON data:

{
  "objects": [ <object>, ... ],
  "privateData": <any>
}

The property privateData is optional. It contains application-specific options in the form of key-value pairs.

Update - Complete Event Data

The two-way Update-Complete event pattern is used to update and synchronize object state across agents. An agent can request or suggest an object update and receive accomplishments by Complete events. Update events can be observed based on either an object’s core type (coreType) or an object’s object type (objectType).

An Update request or proposal specifies an entire Coaty object as JSON data:

{
  "object": <object>
}

A Complete event signals accomplishment with the entire (usually changed) object as event data. This approach avoids complex merging operations of incremental change deltas in the agents. Since objects are treated as immutable entities on the agent this approach is in line.

The JSON data for the Complete response event looks like the following:

{
  "object": <object>,
  "privateData": <any>
}

The property privateData is optional. It contains application-specific options in the form of an key-value pairs.

Call - Return Event Data

The two-way Call-Return event pattern is used to request execution of a remote operation and to receive results - or errors in case the operation fails - by one or multiple agents. Call events can be observed based on an operation name.

The operation name should be defined using a hierarchical naming pattern with some levels in the hierarchy separated by periods (., pronounced “dot”) to avoid name collisions, following Java package naming conventions (i.e. domain.package.operationname). For example, the remote operation to switch on/off lights in the lights package of domain com.mydomain could be named "com.mydomain.lights.switchLight".

The JSON data of the Call request event contains the optional parameter values passed to the referenced operation to be invoked, and an optional context filter that defines conditions under which the operation should be executed by a remote end.

{
  "parameters": [ <valueParam1>, ... ] | { "<nameParam1>": <valueParam1>, ... },
  "filter": ContextFilter
}

If parameters are given, they must be specified either by-position through a JSON array or by-name through a JSON object.

The optional filter property defines contextual constraints by conditions that must match a local context object provided by the remote end in order to allow execution of the remote operation:

{
  // Conditions for filtering objects by logical 'and' or 'or' combination.
  "conditions": ["<propertyName>[.<subpropertyName>]*", <filterOperator1>, ...<filterOperands1>] |
  {
     and: | or: [
       ["<propertyName1>[.<subpropertyName1>]*", <filterOperator1>, ...<filterOperands1>],
       ["<propertyName2>[.<subpropertyName2>]*", <filterOperator2>, ...<filterOperands2>],
       ...
     ]
  }
}

More details and valid filter operators are specified here.

A filter match fails if and only if a context filter in the data and a context object at the remote end are both specified and they do not match (by checking object property values against the filter conditions). In all other cases, the match is considered successfull.

The JSON data of the Return response event has two forms. If the remote operation executes successfully, the data looks like the following:

{
  "result": <any>,
  "executionInfo": <any>
}

The result property contains the return value of the operation call which can be any JSON value.

The optional executionInfo property (any JSON value) in the Return event data may be used to specify additional parameters of the execution environment, such as the execution time of the operation, or the ID and name of the operated control unit.

If an error occurred while executing the remote operation, the response data looks like the following:

{
  "error": { "code": <integer>, "message": <string> },
  "executionInfo": <any>
}

The error code given is an integer that indicates the error type that occurred, either a predefined error or an application defined one. Predefined error codes are within the range -32768 to -32000. Any code within this range, but not defined explicitly in the table below is reserved for future use. Application defined error codes must be defined outside this range.

Error Code Error Message
-32602 Invalid params

The error message provides a short description of the error. Predefined error messages exist for all predefined error codes.

Raw Event Data

A Raw event is publishing arbitrary binary data (byte array) as its payload data. Encoding and decoding of payload data is left to the application. A Raw event is observed based on a subscription topic which may be pattern-based and which is in a binding-specific format.

Associate Event Data

An Associate event is published by an IO router to associate or disassociate an IO source with an IO actor. Associate events accept the following JSON data:

{
  "ioSourceId": <IO source objectId>,
  "ioActorId": <IO actor objectId>,
  "associatingRoute": <topic name>,
  "updateRate": <number>
}

The properties ioSourceId and ioActorId are mandatory.

updateRate is optional; if given it specifies the recommended drain rate (in milliseconds) for publishing IoValue events.

The property associatingRoute defines the subscription or publication topic of the association; if undefined the association should be dissolved. Since an associating route is used for both topic publication and subscription, it must not be pattern-based. Note that the topic format is binding-specific.

Associating routes between Coaty-defined IO sources and IO actors use the topic of an IoValue event. Note that the <IO source objectId> specifies the object ID of the publishing IO source and not the agent’s identity.

Associating routes published by external IO sources or subscribed to by external IO actors must not use the Coaty topic structure, but any other valid topic shape according to the specific binding used.

IoValue Event Data

For Coaty-defined IO sources, an IoValue event is published to submit IO values to associated IO actors. Such events either accept a valid UTF-8 encoded string in JSON format or a binary byte array as data. In the latter case, decoding is left to the application logic of the receiving IO actor.

Likewise, the data published by an external IO source can be either specified as a UTF-8 encoded string in JSON format or as binary data (byte array). In the latter case, decoding is left to the application logic of the receiving IO actor.


Copyright (c) 2020 Siemens AG. This work is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License.