Skip to main content
Jump to: navigation, search

SensiNact/Gateway Core

sensiNact Gateway Core

About integration

The problem

When talking about integration, nobody needs to be convinced about the importance of maintainability, reusability, and adaptability. However, quite often, when looking at a framework in a global way, it is difficult to understand why things are built like they are. So recapitulating some basic concepts can help in understanding the big picture.

Doing an integration work means making two or more distinct processes communicate. This work can be done by creating a 'connector' between each involved processes pair, and for each possible interconnection case.

Sna connectors.png


  1. class Connector_1g {
  2.   void fromGreenProcessToBlueProcessPropertyA() { 	
  3.     long a = the_green_process.readProperty("A");
  4.     the_blue_process.writeProperty("A", a + 3);
  5.   }
  6. }

According to the number of interconnected processes it can be more efficient to use a shared set of data structures, avoiding an exponential increasing of the connectors number, reducing this way the work to be done for interconnecting two processes.

Sna commonDSs.png


  1. Connector { 
  2.   Process process = null;
  3.   long operand = 0;
  4.  
  5.   Connector(Process process, long operand) {
  6.     this.process = process;
  7.     this.operand = operand;
  8.   }
  9. }
  10.  
  11. ConnectorBlue {      
  12.   ConnectorBlue() {
  13.     super(the_blue_process, 3);
  14.   }
  15.  
  16.   long readPropertyA() {
  17.     return super.process.readProperty("A");
  18.   } 
  19.  
  20.   void writePropertyA(long value) {
  21.     return super.process.writeProperty("A", value + super.operand);
  22.   }   
  23. }

The communication between two processes may imply for one to know the current value of a 'property' held by the other one, or to be informed about the value changes when they occur without need of asking for; moreover it may imply to set this same value. those needs allow to draw the frame of a set of raw basic commands that may be required to realize the integration work: one to read in a client/server mode, another one to read in publish/subscribe mode, and finally one to write. Once more, by defining a generic implementation of those operations for a generic connector it is possible to increase the system maintainability.

Sna commonOps.png


  1. Connector { 
  2.   Process process = null;
  3.   long operand = 0;
  4.  
  5.   Connector(Process process, long operand) {
  6.     this.process = process;
  7.     this.operand = operand;
  8.   }
  9.  
  10.   long readProperty(String propertyName) {
  11.     return super.process.readProperty(propertyName);
  12.   } 
  13.  
  14.   void writeProperty(String propertyName, long value) {
  15.     return super.process.writeProperty(String propertyName, value + super.operand);
  16.   } 
  17. }
  18.  
  19. ConnectorBlue {      
  20.   ConnectorBlue() {
  21.     super(the_blue_process, 3);
  22.   }
  23. }

By working on lose coupling between issues, the number of involved objects increases for a single operation; the two last code samples imply the use of an entity coping with orchestration aspects.

The common data structures

Of course, what will really allow the integration framework to grow up and easily adapt to the changes is the choice of the shared data structures. On one hand, more precise (and so more specific to a business logic) is the data model and more difficult is the adaptation to any new concept; on the other hand more generic is the data model and more difficult is the initial work of implementing the business logic.

Rarely, a business logic uses flat concepts, more often it implies a hierarchy of concepts parameterizing the processing to be done.

Sna core concepts.png


What about sensiNact

To respond to the questions that the integration problematic asks, the sensiNact platform defines a generic data model and a set of generic access methods. The initial field of use of sensiNact is the Internet of Things, this is why some concepts of the framework directly refer to it.

The data model

Sna core datamodel1.png

The data model is mainly composed of three elements : ServiceProvider, Service and Resource. The logic being that the ServiceProvider is attach to a location and holds a set of Services, which gather the Resources according to the business logic (all the resources associated to the current weather for example). Finally the Resources handle the effective values of the system under the form of attributes, characterized by metadata. The generic access methods apply on the Resources; three of those access methods can be used with every types of Resource : GET (read on client/server mode) , SUBSCRIBE/UNSUBSCRIBE (read on a publish/subscribe mode), SET (write). The ACT method only applies on one type of Resource, the ActionResource one, that allows to handle the concept of actuator. The other types of Resource are : the StateVariableResource defining the state of the system and whose update can be linked to an ActionResource invocation, a PropertyResource defining the configuration of the system that may be modified by a user (an administrator), and a SensorDataResource, generally unmodifiable by a user and representing the business value provided by the system (a temperature provided by a thermometer for example). The implementation of the data model introduces more data structures than those needed to understand how sensiNact works. This data structures are used to interact with the OSGi host environment and to cope with some of the non functional requirements of the framework, including the security. the SensiNactResourceModel completes the data model described above. It handles the messaging mechanism for all the elements of the data model, as well as the security information allowing the instantiation of the proxies according to the access profile applying, as defined in the datastore. The SensiNactResourceModelConfiguration configuring the SensiNactResourceModel allows to extend the basis model and to define the global behavior : start at initialization time, dynamic build, etc...

Sna datamodel3.png

By the way of the ModelInstanceBuilder mechanism, the instantiation of model instances is simplified and framed, constraining the validation of security information referenced for the module in the datastore. The instantiation of a new SensiNactResourceModel is still allowed for an unknown module if it does not use of a resource model identifier known by the system.

When creating a new module for sensiNact, it has to be signed and references the SHA-1 signature of the module in charge of validating its own (defines the permission to explore the content of the bundle). Finally the signature of the new module has to be recorded in the sensiNact datastore and linked to the appropriate users' public keys to define the access profiles. Two important points are that the security data model allows to define the access level associated to an anonymous (unknown) user, and that the security policy is defined as a tree where a leaf can inherit from the security rules on its branch. The logic of the security in the sensiNact gateway is that the user only see what he/she can use, and that he/she can use every thing that he/she sees.

Sna security1.png

In the example described in the figure below, a user trying to access to the ServiceProviderX for which its access profile is Anonymous will receive a description object in which only one Service will be referenced (ServiceX1), containing a single Resource (ResourceX1S2) providing two AccessMethods, GET and SUBSCRIBE. To ensure this security management, only a proxy of the reified resource model element instance is accessible by a final user, either through a northbound bridge or through a module installed in the OSGi environment.

Sna security2.png

The access method response format

  • <timestamp> :: long
  • <attribute-name> :: string
  • <attribute-type> :: string
  • <attribute-value> :: depends on <attribute-type>
  • <updatable-metadata-list> :: <updatable-metadata>[,<updatable-metadata>]
  • <updatable-metadata> :: <updatable-metadata-name> : <updatable-metadata-value>
  • <updatable-metadata-name> :: string
  • <updatable-metadata-value> :: json value (cf. spec)depends on the metadata type
  • <triggereds> :: [<triggered>[,<triggered>]]
  • <triggered> :: json object (the response of the set access method called on associated StateVariableResource(s))
  • <task-identifier> :: string
  • <task-result> :: json value (cf. spec) depends on the task execution returned value
  • <task-status> :: string ("INITIALIZED"| "LAUNCHED" | "ACKNOWLEDGED" | "EXECUTED" | "ABORTED")
  • <subscription-identifier> :: string

GET access method

{
 "response": {
   "timestamp": <timestamp>,
   "name":  <attribute-name>,
   "type" : <attribute-type>,
   "value" : <attribute-value>[,
   <updatable-metadata-list>]
 },
 "statusCode": <status-code>,
 "type": "GET_RESPONSE",
 "uri": <resource-uri>
}

SET access method

{
 "response": {
   "timestamp": <timestamp>,
   "name":  <attribute-value>,
   "type" : <attribute-type>,
   "value" : <attribute-value>[,
   <updatable-metadata-list>]
 },
 "statusCode": <status-code>,
 "type": "SET_RESPONSE",
 "uri": <resource-uri>
}

ACT access method

{
 "response": {
     "taskId": <task-identifier>,
     "result": <task-result>,
     "status": <task-status>,
     "start": <timestamp>,
     "end": <timestamp>
   },
 "triggered": [<triggereds>],
 "statusCode": <status-code>,
 "type": "ACT_RESPONSE",
 "uri": <resource-uri>
}

SUBSCRIBE access method response

{
 "response": {
   "subscriptionId": <subscription-identifier>
 },
 "statusCode": <status-code>,
 "type": "SUBSCRIBE_RESPONSE",
 "uri": <resource-uri>
}

UNSUBSCRIBE access method response

{
 "response": {
     "taskId": <task-identifier>,
     "status": <task-status>,
     "start": <timestamp>,
     "end": <timestamp>
 },
 "statusCode": <status-code>,
 "type": "UNSUBSCRIBE_RESPONSE",
 "uri": <resource-uri>
}

Copyright © Eclipse Foundation, Inc. All Rights Reserved.