Skip to content

Service Bus (Quick)

Carsten Stocklöw edited this page Apr 25, 2018 · 4 revisions

Table of Contents

Service Ontology

Service Ontology is the shared model between service requester and provider. It works as an anchor to the Ontological model. It also allows restrictions over the original model to make services more specific.

Service Ontologies are usually included in the related ontology domain module, but more can also be created in other modules or in the applications themselves. The module containing the Service Ontology must be available to both requester and provider.

Creating service ontologies

A Service Ontology is in fact just a single concept that connects to the Ontology Model of the domain it is going to handle, by one or more properties. It inherits from the concept Service included in the Service Bus. It should be linked to the most “root-like” concept(s) of domain ontologies, thus allowing providers to handle all possible combinations of the domain concepts. The property (or properties) linking to the domain is usually named MANAGES, CONTROLS or HANDLES.

 //Ontology concept code that represents the service ontology
 // This class represents the Lighting service concept
 public class Lighting extends Service {
   public static final String MY_URI = LightingOntology.NAMESPACE + "Lighting";
   public static final String PROP_CONTROLS = LightingOntology.NAMESPACE + "controls";
   ...
 }
Ontological restrictions can be defined over the Service Ontologies and therefore over all properties reachable through it. These can be used to narrow the possible services that can be provided with this Service Ontology. But in general these restrictions are defined by instances of the Service Ontology created by Service Callees (see next section), while generic Service Ontologies should be exactly that: generic.
 //Ontology code to create a service ontology for lighting services
 // Lighting concept is a service controlling the lights. The property CONTROLS links it to LightSource concept
 oci = createNewOntClassInfo(Lighting.MY_URI, factory, 4);
 oci.addSuperClass(Service.MY_URI);
 oci.addObjectProperty(Lighting.PROP_CONTROLS);
 oci.addRestriction(MergedRestriction.getAllValuesRestriction(Lighting.PROP_CONTROLS, LightSource.MY_URI));

Service Callees and Profiles

Service Callees are those applications that provide services of certain Service Ontology. They do so by registering Service Profiles.

Service Profiles are the equivalent to methods. They represent the operation to perform. Starting at the Service Ontology they describe arguments as a Path to a concept on which an Effect is expected.

An application can actually have more than one Callee. Each Callee can answer to multiple Profiles. The Profiles are registered when the Callee is constructed. It is also possible to add more or remove later.

A Callee can use its own instance of a Service Ontology to define its own restrictions to narrow its provided services. This is done by creating an extension of the Service Ontology, usually named Provided Service. The Service Profiles are usually defined in this Provided Service class too.

 //Service Callee code with the method to receive calls
 public class MyCallee extends ServiceCallee {
   // Called if a request matches a profile (find out which)
   public ServiceResponse handleCall(ServiceCall call) {
      String operation = call.getProcessURI();
      if(operation.startsWith( 
         ProvidedService. PROF2_TURNON)){
         // Profile arguments can be taken from the call
         Object input = call.getInputValue( 
            ProvidedService.INPUT_LAMP);
         // Make the light turn on here... then return success
         return new ServiceResponse(CallStatus.succeeded);
 }  }  }

 //Application code to create and register a callee
 // Create (and register) the Service Callee with the profiles
 MyCallee callee=new MyCallee(moduleContext,ProvidedService.profs);

What is necessary to create a service callee

A Provided Service class is the most usual way to define the provided services. On one hand, it can define the desired restrictions because it is an extension of the Service Ontology to be provided. On the other hand, it´s also used to define the Service Profiles that will be handled by the Callee, each identified by a URI. If no restrictions are needed then it could also be possible not to have this Provided Service class and use the Service Ontology directly instead, declaring the Profiles elsewhere.

Then there is the Service Callee itself. It is an extension of ServiceCallee from the Service Bus. When created, it must be passed the Service Profiles it will answer to. Whenever a call is received that matches one of the profiles, its method handleCall will be invoked, along with the call. The Callee must then identify which Service Profile was called by looking into the call´s requested URI. Then it can work with the call, extract the arguments it knows it has, do something with it and return a response (success, error, timeout...), along with outputs, if any.

Declaring services with the service profiles

A Profile is created by first defining which Service Ontology is being used as starting point. This is done by creating instances of the Provided Service. Then the arguments are added, as many as needed. The meaning of the operation is actually described by the combination of arguments and their restrictions.

 //Provided Service code extending service ontology and defining restrictions and profiles
 public class ProvidedService {
   // Profiles and restrictions will be placed here
   static final ServiceProfile[] profs = new ServiceProfile[2];
   static {
      // Define here the Service Profiles:
      // This profile is for getting all controlled lights
      ProvidedService prof1 = new ProvidedService(PROF1_GETALL);
      prof1.addOutput(OUTPUT_LAMPS, LightSource.MY_URI, 0, 0, new String[] { Lighting.PROP_CONTROLS });
      profs[0] = prof1.getProfile();
      // This one is for turning on a lamp (set brightness 100%)
      ProvidedService prof2 = new ProvidedService(PROF2_TURNON);
      prof2.addFilteringInput(INPUT_LAMP, LightSource.MY_URI, 1, 1, new String[] { Lighting.PROP_CONTROLS });
      prof2.getProfile().addChangeEffect(new String[]{Lighting.PROP_CONTROLS, LightSource.PROP_SOURCE_BRIGHTNESS }, new Integer(100));
      profs[1] = prof2.getProfile();
      ...
   }
 }
Each argument is identified by a URI that can be later used by the Callee to handle arriving calls to the Profile. Each argument is described by a Path and an Effect.

The Path leads to a concept in the Ontological Model, starting from the Service Ontology. It is represented as an array of the successive properties to follow from the Service Ontology to the desired concept.

The Effect determines what is expected to happen with the concept at the end of the path. Possible effects are Add, Change, Remove, Filter and Output. These are set depending on the method of Service used to define the argument.

Service Callers and Requests

Service Callers are the applications that request the execution of a service. This is achieved by issuing Service Requests. The Requests are matched to registered Profiles and if they are ontologically equivalent, the Callee(s) that registered them will be called and will give an answer.

Service Requests are the counterpart of Service Profiles, built the same way but declare what the Caller wants to execute.

One Caller is enough for most applications, but there can be more. There is also a default implementation. Nothing is needed at construction.

 //Service Caller code with the method to handle asynchronous responses
 public class MyCaller extends ServiceCaller {
   // Handles async. responses, when sendRequest(call) is used
   public void handleResponse(String requestID, ServiceResponse response) {
      // Handle the response
 }  }

Calling services with service requests

The default implementation is enough to send requests and getting the response. But if this must be handled asynchronously, ServiceCaller must be extended, and responses handled in handleResponse method. In any case, requests are sent with call method of the Caller.

What is sent in the call is a Service Request, which is built the same way as the Service Profile it intends to call: First create it with the root Service Ontology, and then add arguments with paths and effects. But because services are semantic it doesn´t have to be identical to the Profile: just call what is needed. All services which Profiles match the Request will respond, which means that a response may have answers from many services. This is relevant if outputs are requested.

 //Application code to create a request, create a caller, send the request and get outputs
 // Create the caller, which doesn´t need extra info
 MyCaller caller = new MyCaller(moduleContext);
 // Call “get all lamps”. Using Lighting instead of Provided Service and not specifying light type still matches the profile.
 ServiceRequest req = new ServiceRequest(new Lighting(), null);
 req.addRequiredOutput(REQUIRED_OUTPUT_LAMPS, new String[] { Lighting.PROP_CONTROLS });
 // Synchronous call. Asynchronous would be sendRequest(call)
 ServiceResponse rsp=caller.call(req);
 // Deal with response. There are other methods to get outputs.
 if (rsp.getCallStatus() == CallStatus.succeeded) {
   List lampList = rsp.getOutput(REQUIRED_OUTPUT_LAMPS, true);
 }

Support:

Found a problem?
  • Report suggestions, missing, outdated or wrong documentation creating an Issue with "documentation" tag
Clone this wiki locally