IST Amigo Project Amigo Training Document: ANS Version 2.0 IST-2004-004182 Public June 2007 Confidential Project Number : IST-004182 Project Title : Amigo Deliverable Type : Tutorial Deliverable Number : Title of Deliverable : Amigo Training Document: ANS Nature of Deliverable : Public Internal Document Number : Contractual Delivery Date : Actual Delivery Date : Contributing WPs : Author(s) : Todor Dimitrov, Edwin Naroska, Jörg Schmalenstroer, Volker Leutnant Abstract This document is a tutorial about using the Awareness and Notification System (ANS) of Amigo. ANS is part of the intelligent user services and provides an easy way to get access to changes in the context of the home environment. ANS provides functionality to allow people/applications to stay aware of context changes. This tutorial briefly introduces how to use ANS, i.e. how to write and ANS client. Keyword list Awareness and Notification System, ANS, ANS client, context Amigo IST-2004-004182 1/22 June 2007 Confidential Table of Contents Table of Contents................................................................................................... 2 1 2 Introduction ..................................................................................................... 3 1.1 Prerequisites..............................................................................................................................3 1.2 How to use this document ........................................................................................................3 System and software requirements ............................................................... 5 2.1 Installing and configuring Oscar ............................................................................................5 2.1.1 Installation ..........................................................................................................................5 2.1.2 GUI.....................................................................................................................................5 2.1.3 Installing bundles ...............................................................................................................6 2.1.4 Repositories ........................................................................................................................7 2.1.5 Stopping Oscar ...................................................................................................................7 3 Using the Awareness and Notification System ............................................. 8 3.1 Writing an ANS client ...........................................................................................................8 3.1.1 Looking up the ANS service ..............................................................................................8 3.1.2 The main component ........................................................................................................10 3.1.3 Service activator ...............................................................................................................14 3.1.4 Client notification.............................................................................................................14 3.1.5 Providing rules to ANS ....................................................................................................15 3.1.6 Service bundle metadata...................................................................................................16 3.1.7 Client bundle manifest......................................................................................................16 3.2 4 Writing a context source for testing...............................................................................17 Recommended next steps.............................................................................. 22 Amigo IST-2004-004182 2/22 June 2007 Confidential 1 Introduction This document is a tutorial about using the Awareness and Notification System (ANS) of Amigo. ANS is part of the intelligent user services and provides an easy way to get access to changes in the context of the home environment. ANS provides functionality to allow people/applications to stay aware of context changes. For example, it can inform applications about changes of the current location of a specific user. As a result, the application does not have to query all the various context sources that may provide appropriate location information. Instead, it subscribes to ANS and inject an appropriate rule that is automatically checked by ANS each time context information changes This tutorial briefly introduces how to use ANS, i.e. how to write and ANS client. 1.1 Prerequisites Amigo training blocks typically requires some Amigo related as well as non Amigo related skills or knowledge. These are given in the following: Non Amigo related prerequisites: o The reader should be familiar with either Java or C# to easily follow the explanations. o The reader should be familiar with an integrated development environment (IDE) for the programming language that shall be used. It is suggested to use either Eclipse 3.2 (or higher) for Java or Visual Studio 2005 for C#. Amigo related prerequisites: o The reader should be familiar with the Amigo Deployment Framework. To learn about this framework the Using Web Services can be used. The Tutorial can be downloaded from https://gforge.inria.fr/frs/?group_id=160. o The reader should also be familiar with using and developing Context Sources. Please read with the CMS Tutorial available from https://gforge.inria.fr/frs/?group_id=160. For some general information on the Amigo project please refer to the Amigo project web site at http://www.hitech-projects.com/euprojects/amigo/index.htm. 1.2 How to use this document This document aims at providing the reader with valuable information about how to use the Amigo middleware. To this end it gives a step by step introduction where explanations are accompanied with short programming assignments. Please proceed to the document section by section and step by step and try to do the assignments. In order to save some typing, an appropriate set of template files is given that can be used to fulfill the assignments. These template files already include a programming frame that must be extend by you in order to complete the assignment. For information on how where to obtain these template files please refer to Chapter 0. The example below shows how a piece of source code is printed. Note that code blocks are embedded in a box in order to easily separate them from normal text: using (Service service = new AddService(securedService)) { WebServer.AddWebService(serviceLocation, service); Console.WriteLine("Sample service 2 running." + Environment.NewLine + "Press <return> to quit"); Amigo IST-2004-004182 3/22 June 2007 Confidential Console.ReadLine(); } If code is printed in normal text, it is shown in italic. Amigo IST-2004-004182 4/22 June 2007 Confidential 2 System and software requirements For the Java parts of the tutorial you need an installed version of the Java Development Kit, including the javac compiler and the jar tools (Java Version 1.5.x). If your are using Java, then the following additional software is needed: Java Software Development Kit. This is a general package needed for Java software development. The package is available from http://java.sun.com. Oscar. Oscar is a open source OSGi framework. This software is also available from http://amigo.gforge.inria.fr/obr/tools/. Please note that it may be required to de-activated the firewall on the computer that shall run the test server. A set of template files have been prepared in order to help you running the practical parts of this tutorial. It is recommended that you use this templates. A package that includes this template along with some other files an be downloaded from https://gforge.inria.fr/frs/?group_id=160. 2.1 Installing and configuring Oscar Oscar is an open source implementation of the Open Services Gateway Initiative (OSGi) framework specification, which is used by many Amigo services. The main components of the CMS system are based on Oscar bundles, which are available through the Online Bundle Repository (OBR) of Amigo. 2.1.1 Installation Oscar does not have a special installation routine, so the full software package is available as a zip-file (e.g. http://amigo.gforge.inria.fr/obr/tools/oscar_j2se.zip) and has to be extracted to a directory of your choice. If you are connected to the Internet through a proxy server, you’ll have to add the appropriate proxy settings to the “system.properties” file located in the “lib” sub-directory. You’ll find the start scripts “oscar.bat” (Windows) and “oscar.sh” (Linux1) in the main directory. After calling the start script you are asked for a profile name (enter CMSTutorial, for example), which defines the name of the current Oscar profile. You can use profile names for separating different configurations. 2.1.2 GUI Below you see a screenshot of a running version of Oscar. On the left side you find the three items: Bundle List: A list of all installed bundles, showing Id , State and Location; additionally, local URLs can be entered for installing bundles (e.g.: file:///home/user/amigo_bundle.jar) Shell: Command shell OBR: A list of all bundles available from the repositories, this can be online or offline repositories as defined in /lib/bundle.properties. 1 If “oscar.sh” is not executable use “chmod u+x oscar.sh” to change the file attribute. Amigo IST-2004-004182 5/22 June 2007 Confidential Use the OBR item to install bundles from the repository and the Bundle List item for starting and stopping installed bundles. 2.1.3 Installing bundles Now start installing bundles to the Oscar platform: 1. Click on the item “OBR” 2. Select “amigo_core” and press “Start All” Installed dependencies: log4j Service Binder 3. Select “amigo_ksoap_binding” and press “Start All” 4. Select “amigo_ksoap_export” and press “Start All” Installed dependencies: Servlet HTTP Service (+ Amigo mods) 5. Select “amigo_wsdiscovery” and press “Start All” 6. Using the same procedure as describes above start the following bundles: “context_broker”, “context_source_manger” and “context_helper” All bundles that start with “ANS_...” Now click on the “Bundle list” to check if all bundles are installed. You should get the following list: Amigo IST-2004-004182 6/22 June 2007 Confidential If during the bundle installation the above listed dependencies are not installed (an error will occur and pop up), please install the dependencies prior to the bundles by hand. In the “OBR” list you also find several other software bundles, which you can use for your services. Now we should start with compiling bundles and installing them. 2.1.4 Repositories The URL of the repositories is defined in “lib/bundle.properties”. The standard Amigo repositories are defined by the following copy of the “bundle.properties” file. You also find the address of the actual repositories on the item OBR. # all known repositories oscar.repository.url=\ http://amigo.gforge.inria.fr/obr/tools/oscar-repository.xml \ http://amigo.gforge.inria.fr/obr/v2/repository.xml # the port on which the http server will listen # if you have several OSGi platforms on the same machines change the port number org.osgi.service.http.port=8080 2.1.5 Stopping Oscar You can stop Oscar by typing “shutdown” in the Oscar shell. If nothing happens you can press “Ctrl+c” for killing Oscar, but try to shutdown Oscar gently through the “shutdown”-command beforehand. Amigo IST-2004-004182 7/22 June 2007 Confidential 3 Using the Awareness and Notification System ANS is part of the intelligent user services and provides an easy way to get access to changes in the context of the home environment. ANS provides functionality to allow people/applications to stay aware of context changes. For example, it can inform applications about changes of the current location of a specific user. As a result, the application does not have to query all the various context sources that may provide appropriate location information. Instead, it subscribes to ANS and inject an appropriate rule that is automatically checked by ANS each time context information changes. Whenever the rule matches, an appropriate notification is send to the appropriate client. ANS has implemented in Java. However, it communicates with clients using SOAP which makes the client part independent of the actual server implementation. Communication between ANS and clients that make use of it happens in two directions: Client application searches for ANS and uses its interface to manage rules (subscribe, start, update etc.). Further, when a rule evaluates to true, ANS calls the client and uses its interface to notify it. 3.1 Writing an ANS client In the following, it is shown how to write an ANS client. The template files are located in “Code\Java\tutorial_ansclient\src\de\ims\fraunhofer\amigo\tutorial\ans_client”. The complete solutions can be found in the subdirectories starting with “Code_Solution”. 3.1.1 Looking up the ANS service First, we write a class named ANSWrapper that discovers the Amigo ANS service and encapsulates it. It provides the functionality of the IManageRules interface to an application that wants to use ANS. The unique instance of this class is provided by the getInstance. method. After retrieving an ANSWrapper object in this way, simply invoke the connect method and the wrapper will search automatically for available ANS services. Note that the class provides the same methods of the IManageRule interface. Hence, invocations are simply delegated to ANS. First, import the packages that are needed by the wrapper. Further, define some members that are internally used by the wrapper: package de.ims.fraunhofer.amigo.tutorial.ans_client; import java.rmi.RemoteException; import amigo.ans.api.IManageRule; import amigo.ans.api.Rule; import amigo.ans.api.RuleFormatException; import com.francetelecom.amigo.core.AmigoException; import com.francetelecom.amigo.core.AmigoLdapLookup; import com.francetelecom.amigo.core.AmigoService; public class ANSWrapper { /** ANS web service object */ private IManageRule ans = null; /** service objects */ private AmigoService[] services; /** lookup service */ private AmigoLdapLookup lookup = null; ... Amigo IST-2004-004182 8/22 June 2007 Confidential ANSWrapper is build according to the singleton pattern: /** singleton */ private static ANSWrapper instance = null; /** * Return the ANSWrapper instance * @return The unique instance */ public static ANSWrapper getInstance() { if (instance == null) { instance = new ANSWrapper(); } return instance; } /** private constructor to match singleton pattern */ private ANSWrapper() {} ... The connect method now looks up the Amigo ANS service on the network. To this end a service with service type “Amigo_ANS” is searched. Moreover, the service URL must contain the string “IManageRule” in order to use it. Here, we just use the first service that matches this specific pattern. In case of an success, true is returned. Otherwise, if no appropriate ANS service could be found the return value is false: /** * Searches for the ANS via service discovery and connects to it if a * service object is found. */ public boolean connect() { try { //reset connection... ans = null; services = lookup.lookup("(ServiceType=Amigo_ANS)"); //no service discoveres --> no connection if (services.length == 0) { return false; } else { // we use the first service with "IManageRule" // in its name that is found for (int i = 0; i < services.length; i++) { if (services[i].getReference(). getUrl().toLowerCase() .contains("imanagerule")) { ans = (IManageRule) services[i] .getSpecificStub( IManageRule.class); return true; } } } } catch (AmigoException ex) { ex.printStackTrace(); } Amigo IST-2004-004182 9/22 June 2007 Confidential //something has gone wrong or no ANS found --> return false return false; } ... The remainder of the class is dedicated to forwarding various method calls to the actual ANS service that has been found: /** * Return whether or not the application is connected to ANS. * * @return true if application is connected */ public boolean isConnected() { return (ans != null); } public int subscribe(Rule rule, String appID) throws RuleFormatException, RemoteException { return ans.subscribe(rule, appID); } public boolean unsubscribe(int ruleID) throws RemoteException { return ans.unsubscribe(ruleID); } public boolean updateRule(int ruleID, Rule rule) throws RemoteException { return ans.updateRule(ruleID, rule); } public Rule queryRule(int ruleID) throws RemoteException { return ans.queryRule(ruleID); } public boolean startRule(int ruleID) throws RemoteException { return ans.startRule(ruleID); } public boolean stopRule(int ruleID) throws RemoteException { return ans.stopRule(ruleID); } public void bindLookupService(AmigoLdapLookup lookup) { this.lookup = lookup; } public void unbindLookupService(AmigoLdapLookup lookup) { if (this.lookup == lookup) { this.lookup = null; } } } 3.1.2 The main component The code below shows the main component of the client application. Note that this class implements the Lifeycle interface in order to provide the appropriate functionality to work as a Web service within OSGi. Note further, that the client works as an Web Service within OSGi. Amigo IST-2004-004182 10/22 June 2007 Confidential package de.ims.fraunhofer.amigo.tutorial.ans_client; import java.io.BufferedReader; import java.io.InputStream; import java.io.InputStreamReader; import java.rmi.RemoteException; import org.apache.log4j.Logger; import org.ungoverned.gravity.servicebinder.Lifecycle; import amigo.ans.api.INotifyApplication; import amigo.ans.api.Rule; import import import import import com.francetelecom.amigo.core.AmigoException; com.francetelecom.amigo.core.AmigoExportedService; com.francetelecom.amigo.core.AmigoLdapLookup; com.francetelecom.amigo.core.AmigoReference; com.francetelecom.amigo.core.AmigoServiceExporter; /** * Exports the ANS Client as a webservice for Oscar. */ public class MainComponent implements Lifecycle { private private private private Logger logger = Logger.getRootLogger(); AmigoServiceExporter serviceExporter; AmigoExportedService ansclient_not; AmigoLdapLookup lookup; /** The id of the subscribed rule */ private int m_ruleId; /** * Called by the service binder when a service exporter is available. * * @param serviceExporter * The service exporter that was just registered */ public void bindServiceExporter(AmigoServiceExporter serviceExporter) { this.serviceExporter = serviceExporter; } /** * Called by the service binder when a service exporter is no more * available. * * @param serviceExporter * The service exporter that was just unregistered */ public void unbindServiceExporter( AmigoServiceExporter serviceExporter) { if (this.serviceExporter == serviceExporter) { this.serviceExporter = null; } } … The activate method is called by OSGi when the component is activated. Within the method the service object is created. This object will finally receive the notifications issued by ANS. Amigo IST-2004-004182 11/22 June 2007 Confidential Hence, we need to make a Web service from it. Please mind to provide an unique identifier for the client in order to distinguish it from other clients. /** * Called when the component is ativated. Creates an ANS client * and exports it as a webservice. */ public void activate() { logger.info("\n> ANS client :: activated\n"); // create a service object out of our own application, // change this line to use your own ClientNotify service = new ClientNotify(); ansclient_not = serviceExporter.createService(service); try { // add service id for discovery and export interface // as web service ansclient_not.addProperty("oid", "Client_notify"); ansclient_not.exportInterface(AmigoReference.DEFAULT, INotifyApplication.class); logger.info("> exported service with reference " + ansclient_not.getReference()); } catch (AmigoException e) { e.printStackTrace(); } // publish the services for discovery ansclient_not.addProperty("ServiceType", "ANS_Client"); // register service at lookup for wsdiscovery try { lookup.registerService(ansclient_not); } catch (AmigoException e) { e.printStackTrace(); } ... Now that the client has been registered as an Web Service, contact the ANS wrapper and load the rule into the wrapper. Note that the wrapper will forward these requests to the actual ANS service running on the network. The major objective of the next code sequence is to load the rule (note that loadRule is a method of the current class) and subscribe with ANS. ANS will reply with an rule ID that can be used to identify the rule. if (ANSWrapper.getInstance().connect()) { logger.info("Successfully connected to ANS!"); final Rule rule; try { rule = loadRule(); } catch (Exception ex) { logger.error("Unable to load test rule!", ex); throw new RuntimeException(ex); } try { m_ruleId = ANSWrapper.getInstance().subscribe(rule, "ANS_Client"); ANSWrapper.getInstance().startRule(m_ruleId); } catch (Exception ex) { logger.error("Unable to subscribe rule", ex); throw new RuntimeException(ex); Amigo IST-2004-004182 12/22 June 2007 Confidential } logger.info("Successfully subscribed rule with id: " + m_ruleId); } else { logger.error("Unable to connect to ANS!"); } } … Next, define the method that is used to load the rule. Here, read out a file and convert the stream into a string buffer. The buffer can then be used to create a instance of class Rule from it: /** * Loads the test rule * * @return the non-null loaded rule * @throws Exception * if an error occurs */ private Rule loadRule() throws Exception { final InputStream ruleStream = getClass().getResourceAsStream( "ReviewRules_Peter1.xml"); final StringBuffer buf = new StringBuffer(); String line = null; final BufferedReader reader = new BufferedReader( new InputStreamReader(ruleStream)); while ((line = reader.readLine()) != null) { buf.append(line).append("\n"); } return new Rule(buf.toString()); } The deactivate method is called by OSGi when the component is deactivated. Within this method the client Web service is unregistered and shut down. /** * Called when the component is deactivated. Unregisters the * service from the lookup. */ public void deactivate() { if (ANSWrapper.getInstance().isConnected()) { try { if (ANSWrapper.getInstance().unsubscribe(m_ruleId)) { logger.info("Successfully unsubscribed" + " rule with id: " + m_ruleId); } else { logger.error("Unable to unsubscribe rule" + " with id: " + m_ruleId); } } catch (RemoteException ex) { logger.error("Error while trying to unsibscribe" + " rule with id: " + m_ruleId, ex); } } if (ansclient_not != null) { try { lookup.unregisterService(ansclient_not); } catch (AmigoException e) { e.printStackTrace(); Amigo IST-2004-004182 13/22 June 2007 Confidential } } logger.info("\n> ANS client :: stopped\n"); } … Finally, code is needed to react on the availability of an lookup service. /** * Binds the lookup service * * @param lookup * The lookup service that was just registered */ public void bindLookupService(AmigoLdapLookup lookup) { this.lookup = lookup; ANSWrapper.getInstance().bindLookupService(lookup); } /** * Unbinds the lookup service * * @param lookup * The lookup service that was just unregistered */ public void unbindLookupService(AmigoLdapLookup lookup) { if (this.lookup == lookup) { this.lookup = null; ANSWrapper.getInstance().unbindLookupService(lookup); } } } 3.1.3 Service activator To start a service as an OSGi bundle an activator class is needed. This class will be used by OSGi to start the service. Here it is located in Tutorials\Web Services\Code\Java\tutorial_server\src\de\ims\fraunhofer\amigo\tutorial\server\AmigoCoreActi vator.java. package de.ims.fraunhofer.amigo.tutorial.ans_client; import org.ungoverned.gravity.servicebinder.GenericActivator; /** * @see GenericActivator * * @author Todor Dimitrov (todor.dimitrov@ims.fraunhofer.de) * @version 08.10.2007 22:32:10 */ public class Activator extends GenericActivator { } 3.1.4 Client notification Notification by ANS is done by calling an corresponding method of a class that implement the INotifyApplication interface. In this example, the ANS Client just shows sends a simple message to the log screen in case of an event is received. If you are developing an own application, you can either extend this class or replace it with an own component. If you do this, you have to implement the amigo.ans.api.INotifyApplication interface and create a service out of your own component in MainComponent.java. Note that notify takes three arguments: a Amigo IST-2004-004182 14/22 June 2007 Confidential string message that contains the description of the event, a user ID and an intensity level (which is a number between 0 (lowest intensity) and 10): package de.ims.fraunhofer.amigo.tutorial.ans_client; import org.apache.log4j.Logger; import amigo.ans.api.INotifyApplication; public class ClientNotify implements INotifyApplication { private final Logger m_logger = Logger.getLogger(ClientNotify.class); /** * @see INotifyApplication#notify(String, String, int) */ public void notify(String message, String userID, int intensity) { switch (intensity) { case 10: case 9: case 8: showAlertNotification(userID, message); break; case 7: case 6: case 5: case 4: showMediumNotification(userID, message); break; case 3: case 2: case 1: showLowNotification(userID, message); break; case 0: } } private void showMediumNotification(String userID, String message) { m_logger.info("Medium notification :: Message to " + userID + ": \n " + message); } private void showLowNotification(String userID, String message) { m_logger.info("Low notification :: Message to " + userID + ": \n " + message); } private void showAlertNotification(String userID, String message) { m_logger.info("Alert notification :: Message to " + userID + ": \n " + message); } } 3.1.5 Providing rules to ANS In order to operate properly, ANS need rules that need to be checked. In the example, the rules is read out from a file. The rule defined blow will fire an event whenever user John enters the kitchen. In detail, ANS will then send the message “John has entered the kitchen”: Amigo IST-2004-004182 15/22 June 2007 Confidential <?xml version="1.0" encoding="UTF-8"?> <ECARule xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="ECAXML.xsd"> <upon> <event name="isLocatedIn" state_transition="EnterTrue"> <param> <literal value="User.John"/> </param> <param> <literal value="Kitchen"/> </param> </event> </upon> <do> <notification name="Notify"> <param> <literal value="ANS_Client"/> </param> <param> <literal value="John has entered the kitchen."/> </param> </notification> </do> <lifetime value="testing"/> </ECARule> For the rule syntax please read with the ANS documentation. 3.1.6 Service bundle metadata In order to run this software as an OSGi bundle, some information is needed that describes some dependencies of the software: <?xml version="1.0" encoding="UTF-8" ?> <bundle> <component class="de.ims.fraunhofer.amigo.tutorial.ans.tests.ExampleContextSource"> <requires service="nl.telin.amigo.contextmanagement.csmw.ContextSourceManager" filter="" cardinality="1..n" policy="dynamic" bind method="bindContextSourceManager" unbindmethod="unbindContextSourceManager" /> </component> <component class="de.ims.fraunhofer.amigo.tutorial.ans_client.MainComponent"> <requires service="com.francetelecom.amigo.core.AmigoServiceExporter" filter="" cardinality="1..n" policy="dynamic" bind-method="bindServiceExporter" unbind-method="unbindServiceExporter" /> <requires service="com.francetelecom.amigo.core.AmigoLdapLookup" filter="" cardinality="1..1" policy="dynamic" bind-method="bindLookupService" unbind-method="unbindLookupService" /> </component> </bundle> 3.1.7 Client bundle manifest Each OSGi bundle requires a “manifest”. This a plain text file that stores some general information about the bundle. For example, it also includes the name of the metadata file: Amigo IST-2004-004182 16/22 June 2007 Confidential Manifest-Version: 1.0 Bundle-Description: Bundle demonstrates the use of the ANS IUS Bundle-Name: Tutorial-ANS-Client Bundle-Activator: de.ims.fraunhofer.amigo.tutorial.ans_client.Activator Bundle-Vendor: Fraunhofer IMS Import-Package: com.francetelecom.amigo.core, org.ungoverned.gravity.servicebinder, org.apache.log4j, amigo.ans.api, nl.telin.amigo.contextmanagement.csmw, com.hp.hpl.jena.ontology, com.hp.hpl.jena.rdf.model, com.hp.hpl.jena.vocabulary, com.hp.hpl.jena.graph, com.hp.hpl.jena.query, org.amigo.context Bundle-Version: 1.0.0 Bundle-Copyright: Less General Public License Bundle-ClassPath: . Metadata-location: metadata.xml This manifest (named manifest.mf) is stored in the same directory as the metadata file. 3.2 Writing a context source for testing In order to test the application, an appropriate context source is needed. The source code for the context source is in “Code\Java\tutorial_ansclient\src\de\ims\fraunhofer\amigo\tutorial\ans\tests”: package de.ims.fraunhofer.amigo.tutorial.ans.tests; import import import import java.text.SimpleDateFormat; java.util.Calendar; java.util.Enumeration; java.util.Hashtable; import nl.telin.amigo.contextmanagement.csmw.ContextSourceFront; import nl.telin.amigo.contextmanagement.csmw.ContextSourceManager; import import import import org.amigo.context.AmigoICCS; org.amigo.context.ContextTransport; org.apache.log4j.Logger; org.ungoverned.gravity.servicebinder.Lifecycle; import com.hp.hpl.jena.ontology.Individual; import com.hp.hpl.jena.ontology.OntModel; import com.hp.hpl.jena.shared.LockMRSW; /** * A context source that provides information about the user location * */ public class ExampleContextSource implements Lifecycle { private Logger logger = Logger.getLogger(this.getClass().getName()); private ContextSourceManager manager = null; private ContextSourceFront csf = null; /** The GUI client for setting the position of the user */ private ManualLocationUI mlu = null; Amigo IST-2004-004182 17/22 June 2007 Confidential /** The current model of the source */ private OntModel model = null; /** The RDF capabilities of the context source provided during registration */ private String rdfCaps = "" + "<?xml version=\"1.0\"?>" + "<rdf:RDF" + " xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\"" + " xmlns:rdfs=\"http://www.w3.org/2000/01/rdf-schema#\"" + " xmlns:owl=\"http://www.w3.org/2002/07/owl#\"" + " xmlns:j.0=\"http://amigo.gforge.inria.fr/owl/AmigoICCS.owl#\"" + " xmlns:daml=\"http://www.daml.org/2001/03/daml+oil#\"" + " xmlns:j.1=\"http://amigo.gforge.inria.fr/owl/ContextTransport.owl#\">" + " <j.1:ContextSourceRegistration>" + " <j.1:accuracy>5</j.1:accuracy>" + " <j.1:timeliness>current</j.1:timeliness>" + " <j.1:contextType>UserLocation</j.1:contextType>" + " </j.1:ContextSourceRegistration>" + "</rdf:RDF>"; public void bindContextSourceManager(ContextSourceManager manager) { logger.debug("bindContextSourceManager()"); this.manager = manager; } public void unbindContextSourceManager(ContextSourceManager manager) { logger.debug("unbindContextSourceManager()"); if (this.manager == manager) { this.manager = null; } } public void activate() { logger.debug("activate"); csf = manager.registerContextSource(rdfCaps); logger.debug("My CS at URL: " + csf.getAmigoReference().getUrl()); model = csf.getOntModel(); mlu = new ManualLocationUI(this); } public void deactivate() { logger.debug("deactivate"); if (mlu != null) { mlu.deactivate(); mlu = null; } if (csf != null) { csf.deregisterContextSource(); } } /** * Called by the GUI to indicate that new model parameters are * available */ void contextChanged(Hashtable<String, String> ht) { Enumeration<String> en = ht.keys(); // Build a new model based on this context Amigo IST-2004-004182 18/22 June 2007 Confidential // // // // We will exchange the model in one go after building, since the model can be accessed by different threads Note that we re-use the model by emptying it just before rebuilding. model.enterCriticalSection(LockMRSW.WRITE); model.removeAll(); while (en.hasMoreElements()) { String newPerson = (String) en.nextElement(); /** * Create the user whose location is specified and add it * as an object property */ Individual newUser = model.createIndividual(AmigoICCS.User); /** * We shouldn't use identifier for this but another * property, but it will have to do for the moment... */ newUser.addProperty( ContextTransport.identifier, newPerson); /** * Create the location where the user is, and add it as * an object property */ Individual newRoom = model.createIndividual(AmigoICCS.Room); newRoom.addProperty(ContextTransport.identifier, (String) ht.get(newPerson)); Individual newUserLocation = model .createIndividual(ContextTransport.UserLocation); newUserLocation.addProperty(ContextTransport.probability, "0.9"); newUserLocation.addProperty(ContextTransport.isLocationOf, newUser); newUserLocation.addProperty(ContextTransport.isLocatedIn, newRoom); // Add the timestamp Calendar now = Calendar.getInstance(); SimpleDateFormat df = new SimpleDateFormat( "yyyy-MM-dd'T'HH:mm:ss.SSSZ"); newUserLocation.addProperty(ContextTransport.timestamp, df .format(now.getTime())); } model.leaveCriticalSection(); System.out.println("---------------------------------------"); System.out.println("Current model:"); model.write(System.out, "RDF/XML-ABBREV"); System.out.println("---------------------------------------"); System.out.println(); /** * (Re)setting the model will trigger processing of * subscriptions */ Amigo IST-2004-004182 19/22 June 2007 Confidential csf.setModel(model); } } The code to implement a simple GUI for the context source, which allows to manually control the location a user is currently in is: package de.ims.fraunhofer.amigo.tutorial.ans.tests; import import import import import import java.awt.Component; java.awt.Frame; java.awt.GridLayout; java.awt.event.ActionEvent; java.awt.event.ActionListener; java.util.Hashtable; import import import import import javax.swing.BorderFactory; javax.swing.JButton; javax.swing.JLabel; javax.swing.JPanel; javax.swing.JTextField; /** * GUI for setting the location of the user * */ class ManualLocationUI { /** The frame to be displayed */ private Frame frame = null; /** The context source to be notified when location of the * user changes */ private ExampleContextSource m_parent = null; public ManualLocationUI(ExampleContextSource parent) { m_parent = parent; // Create the top-level container and add contents to it. frame = new Frame("User Location"); Component contents = this.createComponents(); // frame.getContentPane().add(contents, BorderLayout.CENTER); frame.add(contents); // Finish setting up the frame, and show it. frame.pack(); frame.setVisible(true); } public void deactivate() { if (frame != null) { frame.dispose(); frame = null; } } private Component createComponents() { final JLabel labelPerson = new JLabel("Person:"); final JLabel labelRoom = new JLabel("Room:"); final JTextField person = new JTextField("John"); Amigo IST-2004-004182 20/22 June 2007 Confidential final JTextField room = new JTextField("Kitchen"); JButton button = new JButton("Send Update"); button.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { Hashtable<String, String> ht = new Hashtable<String, String>(); ht.put(person.getText(), room.getText()); m_parent.contextChanged(ht); } }); labelPerson.setLabelFor(person); labelRoom.setLabelFor(room); /** * An easy way to put space between a top-level container and * its contents is to put the contents in a JPanel that has an * "empty" border. */ JPanel pane = new JPanel(); pane.setBorder(BorderFactory.createEmptyBorder(5, // top 5, // left 5, // bottom 5) // right ); pane.setLayout(new GridLayout(0, 2)); pane.add(labelPerson); pane.add(person); pane.add(labelRoom); pane.add(room); pane.add(button); pane.add(button); return pane; } } When the example context source is started, the following GUI will show up: Amigo IST-2004-004182 21/22 June 2007 Confidential 4 Recommended next steps Now that you have learned about ANS you may be interested in how to continue in the most efficient way in order to become more familiar with the Amigo middleware. To this end this document gives some recommended training documents you should consider to read: o Using Amigo Security Services: This document is a tutorial about gives an introduction on how to use the Amigo Security Services in order to setup secure communication channels between client and services. The tutorial will show how to write a secured service, how to write a client that makes use of a secured service. Further, it will explain how to authenticate a user/device within the Amigo network. o User Modeling and Profiling Services: As the name suggests, you will learn how to describe and manage the preferences of the different users in the Amigo middleware. Amigo IST-2004-004182 22/22