Table of Contents

GiraffPlus Middleware

Overview

GiraffPlus is a set of software modules that helps to build so-called “assistive systems” by connecting various, heterogeneous technical devices to a single, unified network. Assistive systems perceive the state of their environment using sensors, consider the perceived state if it is desirable or not and if the latter is the case, they try to find a way of how to influence their environment by way of their actuators to reach a more desirable state.

Of course, a prerequisite for being able to show this kind of behavior is that all devices involved are connected to the same system. In GiraffPlus, a single device that is connected to the system is referred to as being a “node”. In principle, there are two ways of how to integrate a device into GiraffPlus system, assuming that the device in question is networked (can send and receive data using a network protocol, either wired or wireless). The first way is to install a specific piece of the GiraffPlus platform on the device, the so-called “Middleware” (as in the case of the Giraff Robot). The Middleware software contains the communication infrastructure of the GiraffPlus platform and all devices that run the Middleware can actively participate in the communication of the system. The second way of connecting devices to the GiraffPlus system does not require a given device to run the GiraffPlus Middleware (as in the case of Tunstall and Intellicare sensors). The device in question is rather connected to a node that runs this Middleware, and this node is used as an intermediary by the system in order to control the additional device. For many devices, such as low-power wireless sensors, this is the only way of connecting them to the system, simply because they cannot run any additional software beyond their firmware. And although these slave-devices cannot actively participate in the communication with the rest of the system (as they are just queried for data), their advantage over regular nodes is that they can (oftentimes) simply be “plug-and-played” into a running system.

Besides the Middleware, the GiraffPlus platform is made up of various other software parts which we will refer to as “higher level components”. The Middleware is the basis for all of these higher level components, meaning that you cannot run any of them if the Middleware is not available. The Middleware, however, does not provide a functionality that an end-user would find very useful. It is rather the basis for the higher level platform components to provide application functionalities. Components relies upon it, as the Middleware is capable of hiding the distribution and heterogeneity of the diverse devices that make up the system at its core. From an application programmer's perspective, this means that you do not need to worry about the fact that some of the applications (and higher level platform components) that your application talks to may actually be running on other devices than the one your application is. You will simply forward all of your application's messages and requests to the Middleware component, which will take it from there, making sure that each message reaches its recipient. Note that the Middleware does of course not hinder your application from accessing a device's operating system API. It simply takes the hassle of resolving dependencies off your shoulders.

Hiding the distribution and heterogeneity of the devices is actually just part of the Middleware's job. Its main task lies in what is usually summarized as “seamless connectivity and goal-based interoperability”. As at its core, an assistive system is nothing else but a local private network of technical devices. When additional nodes try to (re-)join the system, the discovery mechanisms of the Middleware automatically recognize and integrate all qualified nodes within reach. The GiraffPlus Middleware has two mediators to discover nodes and reach them, and each of them is responsible for the delivery of a certain message category: the buses.

Getting Started

This section provides information about how to setup the development environment and about how to execute and run the GiraffPlus middleware.

Setting up the Development Environment

There are a few steps you need to perform before you can actually start with setting up your development environment for GiraffPlus and with writing your first application. Please note that we will implicitly assume that you have a Windows 7 system, although deriving the installation steps for other versions of the Windows OS should not be very difficult. Also be aware that you will need to have administrator rights on your PC to be able to perform many of the steps as described below.

Installing an SVN client


When multiple programmers work on a software project, it is always a good idea to have a revision control system in place that tracks changes to shared documents (such as the source code files) and which allows to coordinate parallel editing, to resolve possible conflicts, or even to revert a document to a former version if that should become necessary. One of the most widespread revision control systems is certainly Apache Subversion. Subversion, usually abbreviated to SVN, allows a team to create shared repositories of files on a server, from which programmers can “pull” a file to have its latest version locally available, manipulate it, and then “push” the updated file back to the repository to make it available to the rest of the team. Each of the GiraffPlus project's work packages has its own SVN repository. From these repositories, application developers can pull the source code files to have them locally available. One way of doing this is via a Subversion-Client, which we will install now.

First of all, you need software for talking to Subversion repositories. You may want to use one that comes with a graphical user interface, such as TortoiseSVN. Go to http://tortoisesvn.net/downloads.html and download the TortoiseSVN installer (a thing you obviously do not need to do if you already have TortoiseSVN installed on your system). The great thing about TortoiseSVN is that it hooks itself up to your Windows explorer, which means a right click on a folder will give you the additional option of matching it against a certain online repository (thus checking for updated files within both your local folder and the online repository). Once its downloaded, just double click the installer and follow the instructions to install TortoiseSVN to its default path. You will then be asked to restart the system, which you should do.

Getting the sources


Once you have access to the GiraffPlus project, the next step is to download all files from these repositories to your PC. This will allow you to work with the tester application provided by the WP2. The Middleware project, on the other hand, has the sources for the Middleware component of the GiraffPlus platform. While you may not need these initially, at a later point in time you will probably find that having access to the classes that make up GiraffPlus's Middleware will help you when writing more sophisticated applications. The first thing you need to do now is to create the folder that will serve as your local mirror of the online repository, then right click the folder and from the context-menu, select “SVN Checkout…”.

For the Middleware project, the address is https://giraff.xlab.si/svn/giraff/src/WP2/ . After clicking OK, you will be asked to identify yourself by entering your username and password. Do so, and the checkout process should start.

Once you finished downloading, in your folder there will be three subfolders: Android, OSGi, and util.

Installing Java


The GiraffPlus platform is based on the programming language Java. Consequently we need to install the Java programming libraries to your system, so that you can work with these (the so-called Java Development Kit, or JDK for short). Please go to JDK 6 download page and download it to your system. If you are not sure whether to download the 32-bit version or the 64-bit version of the JDK, just choose the one for 32-bit systems.

Once the JDK has successfully been installed, the installer may ask you to where it should install an additional JRE to. Simply install this “public JRE” to its default installation path, as it will not be part of the GiraffPlus development environment. Afterwards, the installer may also want to install the “JavaFX SDK”. Again, simply click through the installation wizard without changing any of the default settings.

Installing Maven


GiraffPlus uses Apache Maven as software project management and comprehension tool. Based on the concept of a project object model (POM), Maven can manage a project's build, reporting and documentation from a central piece of information.

Maven is distributed in several formats for your convenience. Use a source archive if you intend to build Maven yourself. Otherwise, simply pick a ready-made binary distribution from the download page. To install Maven follow these steps:

  1. Unzip the distribution archive, i.e. apache-maven-3.0.5-bin.zip to the directory you wish to install Maven 3.0.5. These instructions assume you chose C:\Program Files\Apache Software Foundation. The subdirectory apache-maven-3.0.5 will be created from the archive.
  2. Add the M2_HOME environment variable by opening up the system properties (WinKey + Pause), selecting the “Advanced” tab, and the “Environment Variables” button, then adding the M2_HOME variable in the user variables with the value C:\Program Files\Apache Software Foundation\apache-maven-3.0.5. Be sure to omit any quotation marks around the path even if it contains spaces. Note: For Maven 2.0.9, also be sure that the M2_HOME doesn't have a '\' as last character.
  3. In the same dialog, add the M2 environment variable in the user variables with the value %M2_HOME%\bin.
  4. Optional: In the same dialog, add the MAVEN_OPTS environment variable in the user variables to specify JVM properties, e.g. the value -Xms256m -Xmx512m. This environment variable can be used to supply extra options to Maven.
  5. In the same dialog, update/create the Path environment variable in the user variables and prepend the value %M2% to add Maven available in the command line.
  6. In the same dialog, make sure that JAVA_HOME exists in your user variables or in the system variables and it is set to the location of your JDK and that %JAVA_HOME%\bin is in your Path environment variable.
  7. Open a new command prompt (Winkey + R then type cmd) and run mvn –version to verify that it is correctly installed.

Running a Middleware Instance

The Middleware implementation is based on Java/OSGi and uses Maven as software project management and comprehension tool. For this reason in the checked-out folder from the svn there is a subfolder called OSGi. To build and run a Middleware instance let's move to that folder where we should have:

as well as other bundles that will be analyzed in the next sections. You can now compile the Middleware by using the Maven tool. Move to the giraff.pom directory and type:

mvn install

If you want to skip the tests you can also type the following:

mvn install -DskipTests

After this, the GiraffPlus middleware has been installed in your local maven repository (look inside your .m2 dir).

Middleware configurations


We use the Config Admin Specification for the configuration stuff of GiraffPlus Middleware. In the folder \rundir\confadmin\services you can find a set of files containing the configuration properties for each bundle. You need to set properties for the connectors (MQTT and Rest) and the middleware in order to run your Middleware instance.

giraff.mqtt.pid.properties
host = 146.48.81.82
port = 1883
user = MQTTuser
pwd = MQTTpwd
giraff.rest.pid.properties
interfaces = *
configs = org.apache.cxf.rs
intents = HTTP
address = http://146.48.81.82/
giraff.middleware.pid.properties
location = /isti
address = 146.48.81.82

In the above properties we are setting up an host:port and user:pwd for the MQTT broker (you can leave as it if you want to use the CNR broker instance), the ip of the jetty engine of the Middleware instance (the local ip of the machine where the instance is running, leave other properties as it), and the location identifier of your GiraffPlus system.

N.B. You need to set up these properties temporarly. As soon as the autoconfiguration bundle will be ready, the only properties needed will be username, password and location.

In the rundir\confadmin\services folder there is a properties file for the logging service. Loggers for connectors and middleware are already configured. Logging messages will be stored in a “logs” directory containing one file for each configured bundle. We will see later how to append the logger for our example applications.

Running the Middleware

Once you have build and configured your Middleware instance you can run it creating a tester configuration. We have created a run configuration for Apache Felix. You can move to the giraff.tester folder and configure the pax.args file:

#
# PAX-RUNNER OPTIONS
#
--profiles=log,config
--executor=script
--org.ops4j.pax.runner.platform.downloadFeedback=false
--log=DEBUG

#
# BUNDLE LIST
#

# OSGi Tool 
mvn:org.apache.felix/org.apache.felix.configadmin/1.2.4
mvn:org.ops4j.pax.confman/pax-confman-propsloader/0.2.2

# MQTT TOOLS
mvn:org.fusesource.mqtt-client/mqtt-client/1.2   
mvn:org.fusesource.hawtbuf/hawtbuf/1.9
mvn:org.fusesource.hawtdispatch/hawtdispatch/1.11
mvn:org.fusesource.hawtdispatch/hawtdispatch-transport/1.11

# REST TOOLS
mvn:org.apache.cxf.dosgi/cxf-dosgi-ri-singlebundle-distribution/1.2
mvn:org.apache.cxf/cxf-bundle/2.7.5
mvn:javax.mail/mail/1.4.7
mvn:org.apache.servicemix.bundles/org.apache.servicemix.bundles.wsdl4j/1.6.3_1
mvn:org.apache.servicemix.bundles/org.apache.servicemix.bundles.xmlresolver/1.2_5
mvn:org.codehaus.woodstox/woodstox-core-asl/4.2.0
mvn:org.codehaus.woodstox/stax2-api/3.1.1
mvn:org.apache.neethi/neethi/3.0.2
mvn:org.apache.ws.xmlschema/xmlschema-core/2.0.3

# JSON TOOLS
mvn:org.codehaus.jettison/jettison/1.3.3
mvn:com.googlecode.json-simple/json-simple/1.1.1
mvn:com.google.code.gson/gson/1.7.1

# LOG4J TOOLS
mvn:org.ops4j.pax.logging/pax-logging-service/1.7.0
mvn:org.ops4j.pax.logging/pax-logging-api/1.7.0

# GiraffPlus API
mvn:it.cnr.isti.giraff/giraff.api

# GiraffPlus UTIL
mvn:it.cnr.isti.giraff/giraff.util

# GiraffPlus MQTT
mvn:it.cnr.isti.giraff/giraff.mqtt

# GiraffPlus REST
mvn:it.cnr.isti.giraff/giraff.rest

# GiraffPlus MIDDLEWARE
mvn:it.cnr.isti.giraff/giraff.middleware

# launch options
--vmOptions=-Dosgi.noShutdown=true -Dbundles.configuration.location=..//..//rundir//confadmin -Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=5005

we will use this file to add our example applications in the bundle list. If you don't want to launch the middleware in DEBUG mode change the launch options section to this:

--vmOptions=-Dosgi.noShutdown=true -Dbundles.configuration.location=..//..//rundir//confadmin

Afther that you can open a terminal, move to giraff.tester and type:

mvn pax:run

then change directory to the newly created runner directory (cd runner) and type:

run.bat

Your base Middleware instance is now up and running. Logging files will be stored in the runner\logs directory. We will use this Middleware instance to test our example applications.

Example Applications

To show you how easy is it for high level components to interact with each other through the Middleware, we'll see how to implement:

The sample code for each application is available on the svn in the OSGi/samples directory.

sensorsPub


Create a new maven project using a quickstart archetype (maven-archetype-quickstart) with your preferred Group Id, Artifact Id, Version, and package. Following an example:

    Group Id = it.cnr.isti.giraffPlus
    Artifact Id = sensorsPub
    Version = 0.0.1-SNAPSHOT
    package = giraff.sensorsPub

When done, let's do some changes to the pom.xml in order to use the maven-bundle-plugin:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
 
  <groupId>it.cnr.isti.giraffPlus</groupId>
  <artifactId>sensorsPub</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>bundle</packaging>
 
  <name>sensorsPub</name>
  <url>http://maven.apache.org</url>
 
  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>
  <organization>
    <url>http://giraffplus.eu/</url>
    <name>GiraffPlus</name>
  </organization>
 
  <dependencies>
    <dependency>
      <groupId>it.cnr.isti.giraff</groupId>
      <artifactId>giraff.api</artifactId>
      <version>1.0.0-SNAPSHOT</version>
    </dependency>
  </dependencies>
 
  <build>
    <plugins>
      <plugin>
	<groupId>org.apache.felix</groupId>
	<artifactId>maven-bundle-plugin</artifactId>
	<extensions>true</extensions>
	<configuration>
	  <instructions>
	    <Bundle-Author><![CDATA[Filippo Palumbo <filippo.palumbo@isti.cnr.it>]]></Bundle-Author>
	    <Bundle-Name>${project.name}</Bundle-Name>
	    <Bundle-Description>${project.description}</Bundle-Description>
	    <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
	    <Bundle-Provider>ISTI-CNR</Bundle-Provider>
	    <Import-Package>
	      org.osgi.framework;version="1.3.0",
	      org.osgi.service.cm;version="1.2.0",
	      org.osgi.service.log;version="1.3.0",
	      it.cnr.isti.giraff.api
	    </Import-Package>
	    <Bundle-Activator>it.cnr.isti.giraffPlus.sensorsPub.Activator</Bundle-Activator>
	  </instructions>
	</configuration>
      </plugin>
    </plugins>
  </build>
 
</project>

In this way we can package our application as an OSGi bundle using Maven and use the Middleware as a dependency. Now that we have declared it.cnr.isti.giraffPlus.sensorsPub.Activator as our bundle activator, we create it. In this example application, we are going to create an exporter of a set of fake sensors: a PIR for each room: entrance, living room and kitchen. For sake of simplicity, we'll manage everything in the Activator class:

package it.cnr.isti.giraffPlus.sensorsPub;
 
import it.cnr.isti.giraff.api.ErrorHandler;
import it.cnr.isti.giraff.api.Middleware;
import it.cnr.isti.giraff.api.ServiceDescriptor;
 
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
 
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
 
public class Activator implements BundleActivator, ErrorHandler {
 
    BundleContext bc;
    Set<Sensor> sensors = new HashSet<Sensor>();
    Map<Sensor, ServiceDescriptor> map = new HashMap<Sensor, ServiceDescriptor>();
    boolean publishing = true;
    Thread t;
 
    public void start(BundleContext bc) throws Exception {		
        this.bc = bc;		
	// The fake set of sensors:
	sensors.add(new Sensor("PIR-1", "sensor", "presence-detector", "entrance"));
	sensors.add(new Sensor("PIR-2", "sensor", "presence-detector", "living-room"));
	sensors.add(new Sensor("PIR-3", "sensor", "presence-detector", "kitchen"));
	// we get the service reference for the Middleware instance
	ServiceReference sr = bc.getServiceReference(Middleware.class.getName());
	if (sr != null) {			
	    Middleware mw = (Middleware) bc.getService(sr);		
	    if (mw != null) {
	        // for each sensor a ServiceDescriptor announced to the service bus
                for (Sensor s : sensors) {
		    // the service bus topic used by the application to easily identify the sensor
		    String serviceBusTopic = s.getRoom() + "/" + s.getType() + "/" 
                                                     + s.getCategory() + "/" + s.getId();
		    // the context bus topic used by the application to publish fake sensors events
		    String contextBusTopic = s.getRoom() + "/" + s.getType() + "/" 
                                                     + s.getCategory() + "/" + s.getId();
		    // the URI used to reach the REST API for each sensor (in this case there is no API)
		    String uri = "";
		    // creation of the ServiceDescriptor
		    ServiceDescriptor descriptor = new ServiceDescriptor(
                                                        serviceBusTopic, 
							s.getId(), 
							s.getType(),
							s.getCategory(), 
							s.getRoom(),
							contextBusTopic, 
							uri);
		    map.put(s, descriptor);
		    // call announce on Middleware, send a descriptor to the service bus
		    mw.announce(descriptor, this);
	        }
	        bc.ungetService(sr);
	        startPublishingFakeSensorEvents();			
            }
        }		
    }
 
    private void startPublishingFakeSensorEvents() throws InterruptedException {
	t = new Thread(new Runnable() {
	    public void run() {
		ServiceReference sr = bc.getServiceReference(Middleware.class.getName());
		if (sr != null) {
		    Middleware mw = (Middleware) bc.getService(sr);
		    if (mw != null) {
		        while (publishing) {
			    SimpleDateFormat sdfDate = new SimpleDateFormat("yyyy.MM.dd.HH.mm.ss.SSS", 
                                                                        Locale.ENGLISH);
			    try {
    			        Thread.sleep(4000);
			    } catch (InterruptedException e) {
				e.printStackTrace();
			    }
			    for (Sensor s : sensors) {
				String message = "{ \n\"value\":\"off\",\n\"timestamp\":\""
										  + sdfDate.format(new Date())
                                                                                  + "\"\n}";
				mw.publish(map.get(s).getContextBusTopic(), message, false, null);
			    }
			}
		    }
		}
	    }
	});
	t.start();
    }
 
    public void stop(BundleContext bc) throws Exception {
	publishing = false;
	t.join();
	ServiceReference sr = bc.getServiceReference(Middleware.classgetName());
	if (sr != null) {
	    Middleware mw = (Middleware) bc.getService(sr);
	    if (mw != null) {
	        // remove descriptors from service bus
		for (Sensor s : sensors) {
		    mw.remove(map.get(s), this);
		}
	    }
	}
    }
 
    @Override
    public void handleError(String error) {
        // Handling method for announcing and publishing errors
    }
}

As written in the inline comments, we have first created a ServiceDescriptor for each of our fake sensors, then we announced it on the service bus, and finally we started publishing fake events on the context bus.

Tu run our application, we need to install it. So, let's move to the folder that contains the pom.xml and launch:

mvn install

After that, we add the mvn url to the list of bundle in our test configuration. To do this, let's open the pax.args file contained in the giraff.tester folder and append the following line:

mvn:it.cnr.isti.giraffPlus/sensorsPub@nostart

Then we build our test configuration with:

mvn pax:run

in the giraff.tester folder. We now move to the runner dir and launch the system with the run.bat command. The command window will look now like this:

START LEVEL 6
   ID   State         Level  Name
[   0] [Active     ] [    0] System Bundle (2.0.2)
[   1] [Active     ] [    5] Commons Codec (1.4)
[   2] [Active     ] [    5] OSGi R4 Core Bundle (4.1)
[   3] [Active     ] [    5] OSGi R4 Compendium Bundle (4.1.0)
[   4] [Active     ] [    5] Apache Felix Configuration Admin Service (1.2.4)
[   5] [Active     ] [    5] OPS4J Pax ConfMan - Properties Loader (0.2.2)
[   6] [Active     ] [    5] mqtt-client (1.2)
[   7] [Active     ] [    5] hawtbuf (1.9.0)
[   8] [Active     ] [    5] hawtdispatch (1.11.0)
[   9] [Active     ] [    5] hawtdispatch-transport (1.11.0)
[  10] [Active     ] [    5] Distributed OSGi Distribution Software Single-Bundle Distribution (1.2)
[  11] [Active     ] [    5] Apache CXF Bundle Jar (2.7.5)
[  12] [Active     ] [    5] JavaMail API (compat) (1.4.7)
[  13] [Active     ] [    5] Apache ServiceMix :: Bundles :: wsdl4j (1.6.3.1)
[  14] [Active     ] [    5] Apache ServiceMix :: Bundles :: xmlresolver (1.2.0.5)
[  15] [Active     ] [    5] Woodstox XML-processor (4.2.0)
[  16] [Active     ] [    5] Stax2 API (3.1.1)
[  17] [Active     ] [    5] Apache Neethi (3.0.2)
[  18] [Active     ] [    5] XmlSchema Core (2.0.3)
[  19] [Active     ] [    5] jettison (1.3.3)
[  20] [Active     ] [    5] JSON.simple (1.1.1)
[  21] [Active     ] [    5] Gson (1.7)
[  22] [Active     ] [    5] OPS4J Pax Logging - Service (1.7.0)
[  23] [Active     ] [    5] OPS4J Pax Logging - API (1.7.0)
[  24] [Active     ] [    5] giraff.api (1.0.0.SNAPSHOT)
[  25] [Active     ] [    5] giraff.util (1.0.0.SNAPSHOT)
[  26] [Active     ] [    5] giraff.mqtt (1.0.0.SNAPSHOT)
[  27] [Active     ] [    5] giraff.rest (1.0.0.SNAPSHOT)
[  28] [Active     ] [    5] giraff.middleware (1.0.0.SNAPSHOT)
[  29] [Installed  ] [    5] sensorsPub (0.0.1.SNAPSHOT)
[  30] [Active     ] [    1] Apache Felix Shell Service (1.4.1)
[  31] [Active     ] [    1] Apache Felix Shell TUI (1.4.1)
->

Our application has the ID 29, so let's start it with:

start 29

Now our application is started and has announced the fake sensor on the service bus. From now on, every 4 seconds it will publish fake sensors data to the context bus. These events will travel through MQTT protocol. If we take a look at those with one of the many MQTT standalone subscribers available, we can see the announcing phase:

/isti/serviceBus/entrance/sensor/presence-detector/PIR-1 {"serviceBusTopic":"entrance/sensor/presence-detector/PIR-1","id":"PIR-1","type":"sensor","category":"presence-detector","room":"entrance","contextBusTopic":"entrance/sensor/presence-detector/PIR-1","uri":""}
/isti/serviceBus/living-room/sensor/presence-detector/PIR-2 {"serviceBusTopic":"living-room/sensor/presence-detector/PIR-2","id":"PIR-2","type":"sensor","category":"presence-detector","room":"living-room","contextBusTopic":"living-room/sensor/presence-detector/PIR-2","uri":""}
/isti/serviceBus/kitchen/sensor/presence-detector/PIR-3 {"serviceBusTopic":"kitchen/sensor/presence-detector/PIR-3","id":"PIR-3","type":"sensor","category":"presence-detector","room":"kitchen","contextBusTopic":"kitchen/sensor/presence-detector/PIR-3","uri":""}

the publishing phase:

...
/isti/contextBus/kitchen/sensor/presence-detector/PIR-3 { 
    "value":"off",
    "timestamp":"2013.05.28.12.00.07.312"
}
/isti/contextBus/living-room/sensor/presence-detector/PIR-2 { 
    "value":"off",
    "timestamp":"2013.05.28.12.00.07.312"
}
/isti/contextBus/entrance/sensor/presence-detector/PIR-1 { 
    "value":"off",
    "timestamp":"2013.05.28.12.00.07.312"
}
...

When the bundle is stopped we remove the descriptors from the service bus to let other components, that maybe were using our data, that the sensors are no more available. This is what happens in the underlying MQTT protocol:

/isti/serviceBus/kitchen/sensor/presence-detector/PIR-3 (null)
/isti/serviceBus/living-room/sensor/presence-detector/PIR-2 (null)
/isti/serviceBus/entrance/sensor/presence-detector/PIR-1 (null)

sensorsSub


ToDo.

sampleRestServiceProducer


ToDo.

sampleRestServiceConsumer


package it.cnr.isti.giraffPlus.sampleRestServiceConsumer;
 
import it.cnr.isti.giraff.api.Middleware;
import it.cnr.isti.giraff.api.ServiceDescriptor;
import it.cnr.isti.giraff.api.ServiceListener;
 
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
 
public class Activator implements BundleActivator {
 
	public void start(BundleContext bc) throws Exception {
		// Create the service descriptor that will act as filter, we want for
		// example a service of category example (the first one available).
		ServiceDescriptor filter = new ServiceDescriptor(null, null, "service",
				"example", null, null, null);
		ServiceListener listenerImpl = new ServiceListenerImpl();
		// we get the service reference for the Middleware instance
		ServiceReference sr = bc
				.getServiceReference(Middleware.class.getName());
		if (sr != null) {
			Middleware mw = (Middleware) bc.getService(sr);
			if (mw != null) {
				// Add a service listener on that filter, when a service with
				// the required characteristics will be available, we will be
				// notified through the serviceFound callback
				mw.addServiceListener(filter, listenerImpl, null);
			}
			bc.ungetService(sr);
		}
	}
 
	public void stop(BundleContext bc) throws Exception {
		// TODO Auto-generated method stub
	}
 
}
package it.cnr.isti.giraffPlus.sampleRestServiceConsumer;
 
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
 
import it.cnr.isti.giraff.api.ServiceDescriptor;
import it.cnr.isti.giraff.api.ServiceListener;
 
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.log4j.Logger;
 
public class ServiceListenerImpl implements ServiceListener {
 
	private static final Logger logger = Logger
			.getLogger(ServiceListenerImpl.class);
 
	@Override
	public void serviceFound(ServiceDescriptor descriptor) {
		// This is the callback used when a service that matches the required
		// filter is found
		logger.debug("Service found: \n\tservice bus topic: "
				+ descriptor.getServiceBusTopic() + "\n\t ID: "
				+ descriptor.getId() + "\n\t type: " + descriptor.getType()
				+ "\n\t category: " + descriptor.getCategory()
				+ "\n\t context bus topic: " + descriptor.getContextBusTopic()
				+ "\n\t URI: " + descriptor.getUri());	
		HttpClient client = new DefaultHttpClient();
                // We are interested in the URI field for routing and we want to list
                // all the sensors in the kitchen
		HttpGet request = new HttpGet(descriptor.getUri() + "sensors/kitchen");
		HttpResponse response;
		try {
			response = client.execute(request);
			// Get the response
			BufferedReader rd = new BufferedReader(new InputStreamReader(
					response.getEntity().getContent()));
			String line = "";
			while ((line = rd.readLine()) != null) {
				System.out.println(line);
			}
		} catch (ClientProtocolException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
 
	@Override
	public void serviceRemoved(ServiceDescriptor descriptor) {
		// TODO Auto-generated method stub
	}
 
	@Override
	public void serviceChanged(ServiceDescriptor descriptor) {
		// TODO Auto-generated method stub
	}
 
}
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
 
  <groupId>it.cnr.isti.giraffPlus</groupId>
  <artifactId>sampleRestServiceConsumer</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>bundle</packaging>
 
  <name>sampleRestServiceConsumer</name>
  <url>http://maven.apache.org</url>
 
  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>
  <organization>
    <url>http://giraffplus.eu/</url>
    <name>GiraffPlus</name>
  </organization>
 
  <dependencies>
    <dependency>
      <groupId>it.cnr.isti.giraff</groupId>
      <artifactId>giraff.api</artifactId>
      <version>1.0.0-SNAPSHOT</version>
    </dependency>
	<dependency>
	  <groupId>org.ops4j.pax.logging</groupId>
	  <artifactId>pax-logging-service</artifactId>
	  <version>1.7.0</version>
	</dependency>   
	<dependency>
	  <groupId>org.apache.httpcomponents</groupId>
	  <artifactId>httpclient-osgi</artifactId>
	  <version>4.2.4</version>
    </dependency>       
  </dependencies>
 
  <build>
	<plugins>
	  <plugin>
	    <groupId>org.apache.felix</groupId>
		<artifactId>maven-bundle-plugin</artifactId>
		<extensions>true</extensions>
		<configuration>
		  <instructions>
			<Bundle-Author>
                          <![CDATA[Filippo Palumbo <filippo.palumbo@isti.cnr.it>]]>
                        </Bundle-Author>
			<Bundle-Name>${project.name}</Bundle-Name>
			<Bundle-Description>${project.description}</Bundle-Description>
			<Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
			<Bundle-Provider>ISTI-CNR</Bundle-Provider>
			<Import-Package>
			  org.osgi.framework;version="1.3.0",
			  org.osgi.service.cm;version="1.2.0",
		          org.apache.log4j,
			  it.cnr.isti.giraff.api,
			  org.apache.http.*
			</Import-Package>
			<Bundle-Activator>
                          it.cnr.isti.giraffPlus.sampleRestServiceConsumer.Activator
                        </Bundle-Activator>
		  </instructions>
		</configuration>
	  </plugin>
	</plugins>
  </build>
 
</project>