OSGi DevCon 2008
OSGi defines s huge set of services that are not well known to the application developers. Some of these services are Wire Admin, IO Connector, Initial Provisioning and Declarative Services. These services are donated to Eclipse in 2007 from ProSyst and it is expected to be included in the next Eclipse major release.
This tutorial will focus on main problems, solutions and code snippets related to the usage of the OSGi services. Some topics which will be addressed are:
OSGi Wire Admin Service Specification
OSGi IO Connector Service Specification
OSGi Initial Provisioning
OSGi Declarative Services Specification
Example Usage
The tutorial will include set of programming examples and demonstrations involving different OSGi services.
The goal of the OSGi Wire Admin Service is to enable services that generate some sort of data to send it to the services interested in the same data. The data can be updated dynamically so that the interested services can receive the new values regularly. The Wire Admin Service provides configuration data (in the OSGi Configuration Admin Service) through which new virtual connections (known as wires) can be established when a new service needs to receive the data output. Useless wires can easily be removed. The main advantage of using the Wire Admin service is that it decreases the need for wired bundles to have context-specific knowledge about the opposite party. They never need to communicate with each other directly but through the Wire Admin Service.
A typical data-producing service can be, for example, one that represents some physical device. It produces information about its current status. Typical data-consumers can be detectors, gauges, user interfaces, etc.
Each service which is supposed to produce some data output is referred to as producer. A producer must register the org.osgi.service.wireadmin.Producer interface. Details about creating producers and working with them are available in the Creating a Producer Service part.
The service which is supposed to consume the produced data is called consumer. A consumer must be registered under the org.osgi.service.wireadmin.Consumer interface. A consumer for some data type can also be a producer for another data type. More information about consumers is available in Creating a Consumer Service.
In the most common case, there should be a separate producer/consumer couple for each type of transferred information. However, when there are too many data flows to be handled, it is possible for a producer to be responsible for the generation of several data types, and for a consumer to receive more than one information type. These are called composite producer and composite consumer respectively. They are described in more details in the Creating Composite Producers and/or Consumers part of this document.
Note: Data type does not mean the Java object class of the transferred information! Data type refers to the logical description of the information, for example: door lock status, camera status, etc. The Java object classes that wrap the data are known as flavors.
The wire between a consumer and producer couple is represented by an org.osgi.service.wireadmin.Wire object, created by the Wire Admin. A wire is never opened automatically but when the user explicitly requests it (see Creating Wires for details). More than one wire may be opened between a producer/consumer couple. By default, the data sent across the wire is filtered by the Wire object itself. Filtering in this case implies the rate at which new data will be delivered (there could be time-based and value-based filters with LDAP syntax). The filtering can also be handled by the producer itself. In such case, the Wire object does not perform any filtering. Both filtering ways are described in the Filtering the Data Output part.
All wires are managed by the Wire Admin service. It is the sole party that can create, delete or update wires. Producers and consumers do not have the right to manage wires.
Producers, consumers and wires can have different registration properties which distinguish them and allow them to be obtained through LDAP filtering. These properties are defined as constants in org.osgi.service.wireadmin.WireConstants. In addition, both consumers and producers must have the org.osgi.framework.Constants.SERVICE_PID ("service.pid") property.
A producer service must implement and register the org.osgi.service.wireadmin.Producer interface. Its polled(Wire) method should return the data output sent across the wires. The consumersConnected(Wire[]) method actualizes the list of connected wires.
Each producer must be registered with the following properties:
org.osgi.framework.Constants.SERVICE_PID - The service PID of the producer
WireConstants.WIREADMIN_PRODUCER_FLAVORS - The object classes created by the producer. It takes Class[] values.
WireConstants.WIREADMIN_PRODUCER_FILTERS - (If the producer will handle the filtering) the data filters.
WireConstants.WIREADMIN_PRODUCER_COMPOSITE - (For composite producers only) the service PIDs of the composite consumers it will communicate with.
WireConstants.WIREADMIN_PRODUCER_SCOPE - (For composite producers only) the data types the producer will create.
The following example creates a producer for String output. This is indicated by the value of the org.osgi.service.wireadmin.WireConstants.WIREADMIN_PRODUCER_FLAVORS registration property. The service is also registered with the producer.all PID. The only output it sends is a single String. It will be received by consumers connected with wires to this producer.
OSGi Communication API Overview
The communication API of OSGi is defined for all bundles that require connectivity to external computers or devices. It uses the J2ME Connection Framework, represented by the javax.microedition.io API. This model is based on a Connector class which manages many different connection implementors.
The OSGi Communication API replaces the javax.microedition.io.Connector class from J2ME with its own ConnectorService interface (org.osgi.service.io.ConnectorService) available as a service in the framework. This is necessary for the needs of the OSGi Service Framework model. The OSGi IO Connector Service manages the available connection implementations and creates connections requested by bundles. Services which need to create connections must use the IO Connector Service. They need NOT work directly with the connection implementors.
The communication implementations are registered as services called "connection factories". They are represented by the org.osgi.service.io.ConnectionFactory interface. Each connection factory declares the types of connections it implements by registering for a particular scheme. A scheme is the protocol or pattern of communication implemented. A bundle which demands a connection must pass to the IO Connector Service a valid Uniform Resource Identifier (URI) starting with the expected scheme. The scheme is the part of the URI before the first ":". When the IO Connector Service receives the URI, it parses it and then redirects the URI to the appropriate connection factory.
Each bundle that needs to communicate must invoke some of the open methods of the IO Connector Service. The connection factory found by the Connector Service will create a javax.microedition.io.Connection object.
The IO Connector Service creates each connection by invoking the connection factory's createConnection method. Before the connection is initiated, the Connector Service parses the requested URI and then places its components into a Dictionary, so that the ConnectionFactory will be able to get only the components it needs.
A connection has three modes: read, write and read&write. They are defined as constants in the ConnectorService interface and can be passed as a parameter to the open method. If no mode is passed, the read&write mode is implied.
Connection Types
The generic connection interface obtained through the IO Connector Service is javax.microedition.io.Connection. However, this interface is not convenient to use because it contains only one method: the close() method. The open method is not defined here because the opening of a connection is always handled by the IO Connector Service.
The javax.microedition.io package contains a set of much more convenient connections extending the generic interface. The figure shows the connection hierarchy in the package.