-
Notifications
You must be signed in to change notification settings - Fork 1
Utility API
The Utility API Library is a quick way of coding universAAL applications. The library has no other dependencies than the universAAL Middleware, and because it is just a library and not a bundle, it can be run in whatever (Java) uAAL Container.
You may wonder how this Utility API relates to the Annotated API. Well, it practically does the same: assisting you in using uAAL by writing less code, but in a different approach. The Utility API is just Java code, it does not use annotations. You can consider it as an API that wraps the Native API, encapsulating its features into shorter methods, reduced classes and defaulted features. This also means that you can use pieces of it directly into the Native API at different levels.
Here it is assumed that you already know at least the basic technical concepts of universAAL. It is also intended to get you started with the Utility API, but for delving into details it´s better to read the Javadoc whenever you need it. The Utility API Library contains a lot of verbose Javadoc with examples to which you can refer in case of doubt. You can access it directly here. Perform "mvn javadoc:javadoc" if you want to to generate it locally.
If you want to use, you just need to add this artifact to your app dependencies and then install it in your running environment:
- org.universAAL.support/utilities.api/x.y.z
You can start using universAAL features with the simplest API included in the Utility: The UAAL Helper class. Just create an instance with the right uAAL Module Context and you´ll be ready to use the basic methods:
// Obtain the Module Context, for instance from an OSGi Bundle Context bcontext
ModuleContext context = uAALBundleContainer.THE_CONTAINER.registerModule(new Object[] { bcontext });
// Instantiate the UAAL helper
UAAL u = new UAAL(context);You can now use the u instance throughout your app to perform uAAL operations. When your application is supposed to stop, remember to free the uAAL resources by calling:
u.terminate();The UAAL Helper lets you send Context Events into the Context Bus directly. Assuming you already have the Context Event instance you want to send, all you need to do is:
u.sendC(event);If you are wondering how the event instance is created, well, there is no simplification for that because the Native API is already simple. You should head to Reference Documentation to find out.
In the Native API you would need to implement your own extension of ContextSubscriber, with its subscription and its handleContextEvent method. The UAAL Helper nails it to just those two items whenever you want to subscribe for events. Assuming you already have the Context Event Patterns you want to subscribe to:
u.subscribeC(ceparray, new ICListener() {
public void handleContextEvent(ContextEvent event) {
// Do something with the received event
}
});As you see an interface ICListener is used, which performs the only thing useful from a ContextSubscriber: the handleContextEvent method, which is passed the received event. If you want to know how to make the Context Event Patterns that form that ceparray array, you can look into Reference Documentation or use the Utility API class Pattern.
Just like with Context Events, UAAL Helper lets you send Service Requests directly to the Service Bus, but you also get the Service Response in return. If you already have the Service Request prepared you just do:
ServiceResponse r = u.callS(srequest);You don´t gain too much in comparison to the Native API in this case: you just avoid having to create a DefaultServiceCaller. In any case the complex thing here has always been creating that srequest ServiceRequest and handling the ServiceResponse. But Utility API can help you with that with its Service APIs. You will notice that this method is the only one of UAAL that returns a value, because service calls are the only ones that can have a synchronous response.
Very much like you subscribe for events with UAAL Helper, you can provide ServiceProfiles and handle the calls to them, without having to extend ServiceCallee on your own. As long as you already have your ServiceProfiles defined you can do:
u.provideS(sprofilesarray, new ISListener() {
public ServiceResponse handleCall(ServiceCall s) {
// Check the call URI, do the right thing and return your response
}
});Again we are only interested in the handleCall method of the ServiceCallee, and we implement it within a simple ISListener. However the hard thing here is defining the provided ServiceProfiles that go into the sprofilesarray. The Utility API can help you too, by using its Service API.
Finally if you want to show something to the user and handle its response, with UAAL Helper it´s as simple as the above methods, assuming that you already have the UI request with the output you wan to show:
u.requestUI(uireq, new IUIListener() {
public void handleUIResponse(UIResponse r) {
// Read the user response, and make new requests if you like...
}
});You probably guessed that if you want to create that uireq UIRequest you can take advantage of the Utility API and its UI classes. And again you just use a simple IUIListener interface instead of extending the Native UICaller. However in this case the behaviour of the UAAL Helper is more limited because it doesn´t handle calls from Main Menu and it is a bit tricky with multiple requests. Refer to the Javadoc for details.
The rest of Utility APIs are specialized in each of the uAAL buses: Context, Service and UI. They all have their classes divided into different levels of "complexity", depending on how close they are to the Native API. Each level builds on top of the previous one.
The lowest level has a class that lets you crate simple Context Event Patterns by directly specifying the kind of Subject, Predicate and Object you want to filter.
// Pattern for events with [Subject: User, Predicate: hasLocation]
ContextEventPattern cep = new Pattern(User.MY_URI, User.PROP_PHYSICAL_LOCATION, null);When you create your own Context Publisher you always need an instance of ContextProvider. The next level of Context Utility API lets you create a simple one in one line, with or without specific provided Context Events (check the Javadoc).
// A Gauge provider that publishes events with [Subject: User, Predicate: hasLocation]
ContextProvider cpinfo = new Provider("http://ontology.universAAL.org/Example.owl#MyProvider",
ContextProviderType.gauge,
User.MY_URI, User.PROP_PHYSICAL_LOCATION, null));If you want to go straight into creating a Context Publisher, instead of extending the Native API one you can extend the simple one from the Context Utility API, which is easier (You can also instantiate UtilPublisher directly, if you think that´s enough!). Then you can create it quickly with:
// MySimplePublisher extends UtilPublisher from Utility API. It will publish events with [Subject: User, Predicate: hasLocation]
ContextPublisher cpublisher = new MySimplePublisher(context,
"http://ontology.universAAL.org/Example.owl#MyProvider",
ContextProviderType.gauge,
User.MY_URI, User.PROP_PHYSICAL_LOCATION, null));And in the same way you can create a Context Subscriber by extending the Context Utility API´s simple subscriber. You can argue that it´s the same as extending the native ContextSubscriber, but the advantage is that you can specify the subscription directly in the constructor, like in the above examples:
public class SubscriberExample extends UtilSubscriber{
protected SubscriberExample(ModuleContext context, String subjTypeURI, String predicate, String objTypeURI) {
super(context, subjTypeURI, predicate, objTypeURI);
}
public void handleContextEvent(ContextEvent event) {
// Called when received events
}
public void communicationChannelBroken() {
// Called when bus is lost
}
}The Service Utility API gives you all the tools you need to easily compose requests, profiles, and default callers and callees.
A Service Profile in short is a collection of arguments that all together describe an operation. Each argument is defined by a property path from the root service concept and a "leaf" at the end of that path that is suposed to behave in some way. The Service Utility API lets you compose profiles this way:
// This profile dims a certain lamp to a level: An Variable Input of type LightSource, and a Change Effect on its Brightness
// Create the profile from the root service concept
Profile prof2=new Profile(new Lighting(SERVICE_TURN_DIM));
// Put the first argument, as Variable Input, in the path [Lighting] > PROP_CONTROLS
prof2.put(Path.at(Lighting.PROP_CONTROLS),
Arg.in(LightSource.MY_URI),
INPUT_LAMP_URI);
// Put a second argument, as Change Effect, in the path [Lighting] > PROP_CONTROLS > [LightSource] > PROP_SOURCE_BRIGHTNESS
prof2.put(Path.at(Lighting.PROP_CONTROLS).to(LightSource.PROP_SOURCE_BRIGHTNESS),
Arg.change(TypeMapper.getDatatypeURI(Integer.class)),
INPUT_BRIGHTNESS);
// Finally extract the profile
profiles[2]=prof2.getTheProfile();As you can see, property paths are easily defined with the Service Utility API Path class. The leaf at the end of that path can as well be easily created with the Arg class, or any of the several Value subclasses, from the API.
Because Service Requests are supposed to match a Profile you can use almost the same code you used for the Profile and make sure they will match:
// This request wants to dims a certain lamp to a level: An Variable Input of type LightSource, and a Change Effect on its Brightness
// Create the request from the root service concept
Request req = new Request(new Lighting());
// Put the first argument, the desired light as Variable Input, in the path [Lighting] > PROP_CONTROLS
req.put(Path.at(Lighting.PROP_CONTROLS),
Arg.in(new LightSource(selected)));
// Put second argument, desired value as Change Effect, in path [Lighting] > PROP_CONTROLS > [LightSource] > PROP_SOURCE_BRIGHTNESS
req.put(Path.at(Lighting.PROP_CONTROLS).to(LightSource.PROP_SOURCE_BRIGHTNESS),
Arg.change(val));As you can see the code is practically the same, only that you don´t use URI (e.g. INPUT_LAMP_URI in the profile) when defining the arguments, and that you use the actual values you want for them. The created Request can be directly used in the call.
The next level in the Service Utility API has some helper classes that contain typical requests and profiles for the most used service interactions: Sensors, Actuators and Editors. A Sensor has a GET VALUE service, an Actuator has GET VALUE, SET ON, and SET OFF, and finally an Editor has GET, ADD, CHANGE and REMOVE services. For instance if you already have an instance representing a LightSource you control, you can get all profiles with:
ServiceProfile[] allprofiles = UtilActuator.getServiceProfiles(
"http://ontology.universAAL.org/SimpleApp.owl#", Lighting.MY_URI, mylight);To call those services you can get the matching requests the same way. For instance for calling the SET ON profile, if you already have an instance of the light with the same URI:
ServiceRequest req = UtilActuator.requestSetOn(Lighting.MY_URI, mylight);The Service Utility API provides you with typical implementations of Actuators, Sensors and Editors using the above premade profiles. If you intend to implement one of those services, you can do it easily by extending one of those classes. For instance, to implement your own Actuator class:
public class MyActuatorCallee extends UtilActuatorCallee{
public MyActuatorCallee(ModuleContext context, String namespace, OnOffActuator actuator) {
super(context, namespace, actuator);
}
public boolean executeGet() {
// Called when GET STATUS profile is requested ...
}
public boolean executeOff() {
// Called when TURN OFF profile is requested ...
}
public boolean executeOn() {
// Called when TURN ON profile is requested ...
}
}The UI Utility API comes in handy when you want to build your User Interfaces to be sent through UI Bus, and gives you helper classes in above levels to deal with them.
Instead of first creating a Form and then a UI Request as you would in the Native API, you can do it all together with the UI Utility API simple classes. Imagine that for a given user you want to create a Dialog for dimming a Light selectable from a list:
// Create dialog for the user
Dialog d=new Dialog(sampleUser, "My Title");
// Add a selector from a list
SelectOne one=new SelectOne(PROP_PATH_SELECTED_LAMP, "Lamps");
for(int i=0; i<lights.length;i++){
one.addOption(((LightSource)lights[i]).getURI());
}
d.add(one);
// Add a range selector for the dimmer
d.add(Forms.range(PROP_PATH_DIM, "Dimmer", 0, 100));
// Add a submit to execute, which requires the above inputs
SubmitCmd sub4=new SubmitCmd(REF_DIM, "Dim");
sub4.addMandatoryInput(one);
sub4.addMandatoryInput(range);
d.addSubmit(sub4);This Dialog can be sent to the bus because it already is a UIRequest. As you see you can use the class Forms for an even simpler way of creating UI controls. But these are not compatible with Native API and are only for use with Utility API.
In the Native API you would need to extend UICaller to handle User Interaction. But if you extend the simple UICaller of the UI Utility API instead it will be easier for you, as it also handles the button in the Main Menu. It would look like this:
public class MyUICaller extends UtilUICaller{
protected UIExample(ModuleContext context, String namespace, String url, String desc) {
super(context, namespace, url, desc);
}
public void executeStartUI(Resource user) {
// Called when initial dialog is requested by user -> show main dialog
}
public void handleUIResponse(UIResponse input) {
// Called when user has completed a dialog
}
}There are examples of real working code on how to use the features of the Utility API:
- A simple server for LightSources, working almost in the same way as the famous Lighting Example. Available in https://github.com/universAAL/samples/tree/master/utils/smp.utils.server. Contains examples for Service Callee and Context Publisher.
- A simple client for LightSoruces, with its own uAAL UI, working almost in the same way as the famous Lighting Example. Available in https://github.com/universAAL/samples/tree/master/utils/smp.utils.client. Contains examples for Service Caller, Context Subscriber and UI Caller.
- A simple application for Heating, both with UI and acting automatically. Available in https://github.com/universAAL/samples/tree/master/utils/smp.utils.app. Contains examples for Service Caller, Service Callee, Context Publisher, Context Subscriber and UI Caller in a simpler way.
- A simple mini-application for User editor. Available in https://github.com/universAAL/samples/tree/master/utils/smp.utils.mini. It uses the simplest UAAL Helper class to create an application using only an Activator.