Apache Felix Event Admin

The Event Admin Service Specification, part of the OSGi Compendium specification, defines a general inter-bundle communication mechanism. The communication conforms to the popular publish/subscribe paradigm and can be performed in a synchronous or asysnchronous manner.

The main components in a publish/subscribe communication are:

  • Event Publisher - sends events or messages related to a specific topic

  • Event Handler (or Subscriber) - expresses interest in one or more topics and receives all the messages belonging to such topics.

Events are composed of two attributes:

  • a topic defining the nature of the event; topic names are usually arranged in a hierarchical namespace, where slashes are used to separate the levels (i.e. "org/osgi/framework/FrameworkEvent/STARTED") and

  • a set of properties describing the event.

Creating an Event Publisher

An event publisher is a simple Java class that creates events and sends them using the EventAdmin service interface, for example:

public void reportGenerated(Report report, BundleContext context)
{
    ServiceReference ref = context.getServiceReference(EventAdmin.class.getName());
    if (ref != null)
    {
        EventAdmin eventAdmin = (EventAdmin) context.getService(ref);
Dictionary properties = new Hashtable();
properties.put("title", report.getTitle());
properties.put("path" , report.getAbsolutePath());
properties.put("time", System.currentTimeMillis());
Event reportGeneratedEvent = new Event("com/acme/reportgenerator/GENERATED", properties);
        eventAdmin.sendEvent(reportGeneratedEvent);
    }
}

The EventAdmin.sendEvent() method sends the Event object synchronously. To send it asynchronously, use the EventAdmin.postEvent() method, such as:

//..
Event reportGeneratedEvent = new Event("com/acme/reportgenerator/GENERATED", properties);
eventAdmin.postEvent(reportGeneratedEvent);

Creating an Event Handler

Creating an event handler is as simple as implementing the EventHandler interface:

public class ReportEventHandler implements EventHandler
{
    public void handleEvent(Event event)
    {
        String reportTitle = (String) event.getProperty("title");
        String reportPath = (String) event.getProperty("path");
    sendReportByEmail(reportTitle, reportPath);
}
//..

Registering an Event Handler

To receive event notifications, the event handler must be registered as a OSGi service under the object class org.osgi.service.event.EventHandler. When registering the service, a String\[\]({{ refs..path }}) property named EVENT_TOPIC must be specified; this property describes the list of topics in which the event handler is interested. For example:

String[] topics = new String[] {
    "com/acme/reportgenerator/GENERATED"
};
Dictionary props = new Hashtable();
props.put(EventConstants.EVENT_TOPIC, topics);
bundleContext.registerService(EventHandler.class.getName(), new ReportEventHandler() , props);

It is possible to use '*' as a wildcard in the final character of the EVENT_TOPIC, like in this example:

String[] topics = new String[] {
    "com/acme/reportgenerator/*"
};
Dictionary props = new Hashtable();
props.put(EventConstants.EVENT_TOPIC, topics);
bundleContext.registerService(EventHandler.class.getName(), new ReportEventHandler() , props);

Finally, it is possible to specify an additional EVENT_FILTER property to filter event notifications; the filter expression follows, the normal LDAP syntax:

String[] topics = new String[] {
    "com/acme/reportgenerator/GENERATED"
};
Dictionary props = new Hashtable();
props.put(EventConstants.EVENT_TOPIC, topics);
props.put(EventConstants.EVENT_FILTER, "(title=samplereport)");
bundleContext.registerService(EventHandler.class.getName(), new ReportEventHandler() , props);

OSGi Events

Every OSGi framework sends (asynchronously) a number of events that can be captured by any bundle.

Framework Events

  • org/osgi/framework/BundleEvent/STARTED

  • org/osgi/framework/BundleEvent/ERROR

  • org/osgi/framework/BundleEvent/PACKAGES_REFRESHED

  • org/osgi/framework/BundleEvent/STARTLEVEL_CHANGED

  • org/osgi/framework/BundleEvent/WARNING

  • org/osgi/framework/BundleEvent/INFO

Bundle Events

  • org/osgi/framework/BundleEvent/INSTALLED

  • org/osgi/framework/BundleEvent/STARTED

  • org/osgi/framework/BundleEvent/STOPPED

  • org/osgi/framework/BundleEvent/UPDATED

  • org/osgi/framework/BundleEvent/UNINSTALLED

  • org/osgi/framework/BundleEvent/RESOLVED

  • org/osgi/framework/BundleEvent/UNRESOLVED

The followig properties are always present in a bundle event object:

  • bundle.id

  • bundle.symbolicName

Service Events

  • org/osgi/framework/ServiceEvent/REGISTERED

  • org/osgi/framework/ServiceEvent/MODIFIED

  • org/osgi/framework/ServiceEvent/UNREGISTERING

The following properties are always present in a service event object:

  • service

  • service.id

  • service.pid

Each of the aforementioned events actually contains a wider set of properties. Check the OSGi Compendium specification, section 113.6, for a complete list.

Configuration

The Apache Felix Event Admin implementation is trying the deliver the events as fast as possible. Events sent from different threads are sent in parallel. Events from the same thread are sent in the order they are received (this is according to the spec). A timeout can be configured which is used for event handlers. If an event handler takes longer than the configured timeout to process an event, it is denied. Once a handler is in a denylist, it doesn’t get sent any events anymore. The Felix Event Admin can be configured either through framework properties or through the configuration admin using PID org.apache.felix.eventadmin.impl.EventAdmin. This is a list of configuration properties:


Thread Pool Size

Property: org.apache.felix.eventadmin.ThreadPoolSize + Default: 20 + Type: Integer

The size of the thread pool used for event delivery. The default value is 20. Increase in case of a large amount of events. A value of less then 2 triggers the default value. If the pool is exhausted, event delivery is blocked until a thread becomes available from the pool. Each event is delivered in a thread from the pool unless the ignore timeouts is configured for the receiving event handler.


Async/sync Thread Pool Ratio

Property: org.apache.felix.eventadmin.AsyncToSyncThreadRatio + Since: Release 1.4.2 + Default: 0.5 + Type: Double

The ratio of asynchronous to synchronous threads in the internal thread pool. Ratio must be positive and may be adjusted to represent the distribution of post to send operations. Applications with higher number of post operations should have a higher ratio.


Timeout

Property: org.apache.felix.eventadmin.Timeout + Default: 5000 + Type: Integer

The deny-listing timeout in milliseconds. The default value is 5000. Increase or decrease at own discretion. A value of less then 100 turns timeouts off. Any other value is the time in milliseconds granted to each event handler before it gets denied.


Require Topic

Property: org.apache.felix.eventadmin.RequireTopic + Default: true + Type: Boolean

Are event handlers required to be registered with a topic? This is enabled by default. The specification says that event handlers must register with a list of topics they are interested in. Disabling this setting will enable that handlers without a topic are receiving all events (i.e., they are treated the same as with a topic=*).


Ignore Timeouts

Property: org.apache.felix.eventadmin.IgnoreTimeout + Default: empty + Type: String

Configure event handlers to be called without a timeout. If a timeout is configured by default all event handlers are called using the timeout. For performance optimization it is possible to configure event handlers where the timeout handling is not used - this reduces the thread usage from the thread pools as the timout handling requires an additional thread to call the event handler. However, the application should work without this configuration property. It is a pure optimization! The value is a list of strings. If a string ends with a dot, all handlers in exactly this package are ignored. If the string ends with a star, all handlers in this package and all subpackages are ignored. If the string neither ends with a dot nor with a start, this is assumed to define an exact class name.


Ignore Topics

Property: org.apache.felix.eventadmin.IgnoreTopic + Since: Release 1.4.0 + Default: empty + Type: String

For performance optimization it is possible to configure topics which are ignored by the event admin implementation. In this case, a event is not delivered to registered event handlers. The value is a list of strings (separated by comma). " +If a single value ends with a dot, all topics in exactly this package are ignored. If a single value ends with a star, all topics in this package and all sub packages are ignored. If a single value neither ends with a dot nor with a start, this is assumed to define an exact topic. A single star can be used to disable delivery completely.


Log Level

Property: org.apache.felix.eventadmin.LogLevel + Note: This property can’t be set through the OSGi configuration. + Default: 2 (=WARNING) + Type: Integer

This sets the log level used for messages outputted by the event admin implementation. Valid values are 1 (=ERROR), 2 (=WARNING), 3 (=INFO), and 4 (=DEBUG). The default is 2 and an invalid value sets the level to the default value.