The WireAdmin Bundle provides implementation of the OSGi Wire Admin Service. This service manages the wiring topology of the OSGi framework providing connections between producer and consumer services.
Contents:
The JAR file of this bundle is wireadmin.jar, located in the bundles folder.
|
Note: When the bundle is installed on ProSyst
mBS framework, the com.prosyst.util.ref and the com.prosyst.util.pcommands
packages are exported by the ProSyst
Util Bundle. If the bundle is installed on another vendor's framework, the
packages are provided by the ProSyst Util Full Bundle.
The WireAdmin bundle exports the org.mbs.util.wireadmin package,
which delivers the ProSyst WireAdmin Utility API.
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.
Figure 1: A typical wiring system in the OSGi framework
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.
This service is registered with the framework under the org.osgi.service.wireadmin.WireAdmin
interface. It manages the connections between consumer services and producer
services as described in the OSGi Specification.
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 producerWireConstants.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.
import org.osgi.service.wireadmin.*;
import org.osgi.framework.*;
import java.util.Hashtable;
public class ProducerTest implements Producer, BundleActivator {
private ServiceRegistration reg;
Object output;
public void start (BundleContext bc) throws BundleException {
Hashtable props = new Hashtable();
//the producer will be sending String data (flavors)
Class[] flavors = new Class[] {String.class};
props.put(WireConstants.WIREADMIN_PRODUCER_FLAVORS, flavors);
//the producer PID property
props.put("service.pid", "producer.all");
reg = bc.registerService(Producer.class.getName(), this, props);
}
public void stop (BundleContext bc) throws BundleException {
reg.unregister();
}
/** If there are connected wires, updates them with the produced values */
public void consumersConnected(Wire[] wires) {
if (wires != null) {
for (int i = 0; i < wires.length; i++) {
wires[i].update(polled(wires[i]));
}
}
}
/** This method is responsible for creating the output */
public Object polled(Wire wire) {
String output = "Hello there! This is the producer speaking!";
return output;
}
}
|
The produced output can be filtered in two ways:
polled method should be implemented
so as to produce only values corresponding to the necessary filter). In this
case, it must be registered with the WireConstants.WIREADMIN_PRODUCER_FILTERS
property. Wire with the WireConstants.WIREADMIN_FILTER
property; the producer must NOT have the WireConstants.WIREADMIN_PRODUCER_FILTERS
property simultaneously!As mentioned earlier in this document, the data filtering can be time-based
or value-based. Value-based filtering can be applied for Number
data only.
For constructing value-based filters, the following wire constants can be used:
WireConstants.WIREVALUE_CURRENT ("wirevalue.current")
- Indicates the current value available on the wireWireConstants.WIREVALUE_PREVIOUS ("wirevalue.previous")
- Indicates the previous value passed across the wireWireConstants.WIREVALUE_DELTA_ABSOLUTE ("wirevalue.delta.absolute")
- The absolute (always positive) difference between the last update and the
current valueWireConstants.WIREVALUE_DELTA_RELATIVE ("wirevalue.delta.relative")
- The relative difference is (current_value - previous_value ) / current.For constructing time-based filters, the WireConstants.WIREVALUE_ELAPSED
("wirevalue.elapsed") constant can be used. It represents
the elapsed time in milliseconds between the current value and the previous
value sent by the producer.
Listing 1.2 illustrates producer-made output filtering. It provides value-based
filtering in the producer's polled method. It sends information
about the current temperature only if it is higher than 25 degrees.
import org.osgi.framework.*;
import org.osgi.service.wireadmin.*;
import java.util.Hashtable;
public class ProducerThatFilters implements Producer {
BundleContext bc;
private double currentTemperature;
public ProducerThatFilters(BundleContext bc) {
this.bc = bc;
Hashtable props = new Hashtable(3);
Class[] flavors = new Class[] {Double.class};
//the producer registers for Double data output
props.put(WireConstants.WIREADMIN_PRODUCER_FLAVORS, flavors);
props.put(WireConstants.SERVICE_PID, "producer.that.filters");
// set this registration property with some value
//to indicate that filtering is performed by the producer
props.put(WireConstants.WIREADMIN_PRODUCER_FILTERS, "some.value");
bc.registerService(Producer.class.getName(), this, props);
}
public void consumersConnected(Wire[] wires) {
...
}
//the data is sent only if it is no smaller than 25
public Object polled(Wire wire) {
return (currentTemperature >= 25.d) ? new Double(currentTemperature) : null;
}
}
|
Filtering data through the Wire itself is illustrated in Listing
5 from the Getting the WireAdmin Service part.
A consumer service must implement and register the org.osgi.service.wireadmin.Consumer
interface. It must have the following list of registration properties:
org.osgi.framework.Constants.SERVICE_PID - The service PID
of the consumerWireConstants.WIREADMIN_CONSUMER_FLAVORS - The consumed data
object classes (flavors)WireConstants.WIREADMIN_CONSUMER_COMPOSITE - (Only for composite
consumers) the service PIDs of the producers this service will communicate
withWireConstants.WIREADMIN_CONSUMER_SCOPE - (Only for composite
consumers) the list of descriptive data types consumed by the service.The updated(Wire, Object) method of the consumer is responsible
for actualizing the received data. It is called by the connected wires whenever
new data is available. The producersConnected(Wire[]) method updates
the list of connected wires if new wires are available, or already known wires
are updated/removed.
Note: A consumer service will be able to receive data only if there is at least one connected wire with a producer!
The following simple example creates a consumer service ready to accept any
data types. Its service PID is consumer.all.
import java.util.Hashtable;
import org.osgi.framework.BundleContext;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.ServiceRegistration;
import org.osgi.framework.BundleException;
import org.osgi.service.wireadmin.*;
public class ConsumerImpl implements Consumer, BundleActivator {
private ServiceRegistration reg;
public void start(BundleContext bc) throws BundleException {
Hashtable prop = new Hashtable();
//this property shows that the consumer will accept any data types
prop.put(WireConstants.WIREADMIN_CONSUMER_FLAVORS, new Class[] {Object.class});
//the identifier property of the consumer
prop.put("service.pid", "consumer.all");
//registering the service on the framework
reg = bc.registerService(Consumer.class.getName(), this, prop);
}
public void stop(BundleContext bc) throws BundleException {
reg.unregister();
}
/** Watches the list of wires*/
public void producersConnected(Wire[] wires) {
if (wires == null) {
System.out.println("Not connected to any wires");
} else {
System.out.println("Connected to " + wires.length + " wires");
}
}
/** Receives the new data whenever such are available */
public void updated(Wire wire, Object value) {
System.out.println("Updated " + wire + " with value " + value);
}
}
|
The ways of creating wires are presented later in this document.
Composite consumers and producers have additional registration properties besides those for ordinary producers and consumers. They were listed in the Creating a Producer Service and Creating a Consumer Service parts.
Such composite services exchange data in the form of org.osgi.service.wireadmin.Envelope
objects (flavors). An Envelope wraps a number of data types, for
example: "front left door status", "rear left door status"
and "airbag status". The org.osgi.service.wireadmin package
provides the following class implementing the Envelope interface:
BasicEnvelope - This class can be used as a basic implementation
of the Envelope interface.The org.mbs.util.wireadmin package provides ProSyst's implementations
of the Envelope interface. They serve for transferring primitive
data.There are three implementation classes:
Primitive - This is a generic abstract class that offers methods
for handling primitives. Initially, these methods are empty. Extending classes
should take care of supplying them with the necessary actions.MeasurementEnvelope - This abstract class extends Primitive.
It is fitted for working with org.osgi.util.measurement.Unit
objects.StateEnvelope - This is an abstract class extending Primitive
too. It is fitted for transferring device status information.The following example illustrates implementing a composite producer service.
The consumersConnected method is skipped because there is nothing
interesting in its implementation.
. . .
private String[] scope = new String[] {"current.date", "hello", "bye"};
private Class[] flavors = new Class[] {Envelope.class};
. . .
/** Registering the service with the necessary props */
java.util.Hashtable props = new java.util.Hashtable();
//the data types transmitted by this producer
props.put(WireConstants.WIREADMIN_PRODUCER_SCOPE, scope);
props.put(org.osgi.framework.Constants.SERVICE_PID, "test.producer");
//this property indicates the PIDs of the consumers
|
The WireAdminListener interface allows you to receive WireAdminEvent-s
notifying of changes in the state of the wire. The WireAdminEvent
class provides the following types of events and their correspondent class fields:
Wire object - WIRE_CREATEDWire object - WIRE_CONNECTEDWire object with new properties - WIRE_UPDATEDWire object - WIRE_TRACEWire object - WIRE_DISCONNECTEDWIRE_DELETEDPRODUCER_EXCEPTIONCONSUMER_EXCEPTIONWireAdminListener objects must be registered as a service by using
the WireConstants.WIREADMIN_EVENTS service property. The value
of this property represents a bitwise OR of all the event types the listener
is interested in. If a WireAdminListener object is registered without
a service property WireConstants.WIREADMIN_EVENTS, then the WireAdminListener
will receive no events.
The following example registers a Wire Admin Listener for exceptions generated by producers and consumers.
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceRegistration;
import org.osgi.service.wireadmin.*;
import java.util.Hashtable;
public class ExceptionsListener implements BundleActivator, WireAdminListener {
private ServiceRegistration reg;
public void start(BundleContext bc) {
//bitwise OR of the event types
Integer bitmask = new Integer(WireAdminEvent.PRODUCER_EXCEPTION |
|
A com.prosyst.util.pcommands.PluggableCommands service is registered
by the bundle. It serves for plugging a new console command group. This service
cannot be used in a programming way. It is used through the console commands
created by it. More information about them is available in Using
the wa Console Command Group.
The org.osgi.service.cm.ManagedServiceFactory interface is registered
with the framework. It allows the Wire Admin Service to store configuration
properties with the Configuration Admin Service. It could be obtained and used
in a programming way or through its property editor in mConsole (MC) from the
Framework Professional Edition Package .
The FPID of this Managed Service Factory is: mbs.wireadmin.fpid.
A wire is represented by an org.osgi.service.wireadmin.Wire object.
It can be used by producers to update the data objects available in it through
its update(Object) method. Consumers can request the updated information
by invoking the wire's poll() method. More than a single wire can
connect a consumer and a producer.
With regard to the established connection, a wire has two states:
Wire object is deleted.With regard to its validity, a wire can be:
deleteWire method. There are three ways in which you can create a wire: using the server runtime console, using the property editor of the Wire Admin Service in the mConsole administrator, or programmatically by getting and using the Wire Admin Service.
Note: Initially, the Wire Admin service contains no default wires. Such have to be created by the developers needing them.
Note: For each created wire, no matter the way in which it is created, the Wire Admin creates a new configuration instance representing the wire.
The wa console command group allows managing wires available in the
Wire Admin. To enter this group, type "wa/" in the server's
runtime console.
The following commands are available:
|
mConsole allows easy management of available wires through the GUI provided by the mConsole administrator. To enter the property editor of the WireAdmin Configuration, unfold the WireAdmin Bundle from the bundles tree and enter its node called "WireAdmin Configuration". The main pane contains the properties contained in this factory configuration and allows you to administer them. Description of the properties is available in the Configuration Resources part.

Figure 2: The property editor of the WireAdmin Bundle
Note: Initially, the WireAdmin Bundle contains no configuration instances because it contains no default wires.
To create a new wire, you need to create a new instance of the factory configuration. This is done with the following steps:
Figure 3: Creating a new configuration (wire)
To create a new wire in a programming way, get reference to the Wire Admin
Service and invoke its createWire method. The parameters needed
for this method are: producer PID, consumer PID and a Dictionary
of the properties of this wire. The following properties are implicitly
added to the Dictionary of properties by the Wire Admin Service:
WireConstants.WIREADMIN_CONSUMER_PID - The PID identifying
the wire's consumerWireConstants.WIREADMIN_PRODUCER_PID - The PID identifying
the wire's producer.Note:You should not include these properties when creating the wire because they are automatically overridden by the Wire Admin Service.
The following properties can optionally be supplied to create a wire filter
that will be passed as a value to the WireConstants.WIREADMIN_FILTER
property:
WireConstants.WIREVALUE_CURRENT - The current value in the
wireWireConstants.WIREVALUE_PREVIOUS - The previous value in the
wireWireConstants.WIREVALUE_DELTA_ABSOLUTE - The absolute difference
between the previous and the current values in the wire (valid for numeric
values only)WireConstants.WIREVALUE_DELTA_RELATIVE - The relative difference
between the previous and the current values in the wire (equals (current -
previous)/current)WireConstants.WIREVALUE_ELAPSED - The time in milliseconds
between the checking of the filter and the previous request for update of
the consumer.The following example invokes the Wire Admin Service to create a wire with a temperature filter based on both value and time criteria. It will allow sending data only if the following three conditions are true: the values are between 0 and 100, the time interval between two produced values is greater than 500 ms and the absolute delta between the current and the previous value is less than 20.
import org.osgi.framework.*;
import org.osgi.service.wireadmin.*;
import java.util.Hashtable;
public class WATest implements BundleActivator {
private ServiceReference waRef;
private WireAdmin wa;
private Wire wire;
public void start(BundleContext bc) throws BundleException {
// getting a WireAdmin service reference
waRef = bc.getServiceReference(WireAdmin.class.getName());
if (waRef == null) {
throw new BundleException("Unable to get WireAdmin service reference!");
}
WA = (WireAdmin) bc.getService(waRef);
if (WA == null) {
throw new BundleException("WireAdmin service has not been registered!");
}
Hashtable wireProps = new Hashtable();
// A temperature filter (considering
|
As mentioned in the beginning, the WireAdmin Bundle stores configuration resources with the OSGi Configuration Admin. It owns a factory configuration through which you can create and manage wires. Each single configuration produced from the factory corresponds to a separate wire. Thus, you can create a new wire by creating a new configuration instance.
A configuration (i.e. a wire) can contain the following properties:
|
The above configuration properties can be administrated through the property editor of the WireAdmin Bundle in the mConsole application from the Framework package. See Using the Property Editor.
The WireAdmin Bundle uses the following system properties:
|
To use successfully the above system properties, you have to specify them:
For more information about using system properties, refer to the "System Properties" document from "Getting Started".