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[]
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 blacklisted. Once a handler is in a blacklist, it doesn't get sent any events anymore.
The Felix Event Admin can be configured either through framework properties or through the configuration admin. This is a list of configuration properties:
Function |
Property Name |
Type and Default |
Description |
---|---|---|---|
Cache Size |
org.apache.felix.eventadmin.CacheSize |
Integer, 30 |
The size of various internal caches. The default value is 30. Increase in case of a large number (more then 100) of services. A value less then 10 triggers the default value. |
Thread Pool Size |
org.apache.felix.eventadmin.ThreadPoolSize |
Integer, 10 |
The size of the thread pool. The default value is 10. Increase in case of a large amount of synchronous events where the event handler services in turn send new synchronous events in the event dispatching thread or a lot of timeouts are to be expected. A value of less then 2 triggers the default value. A value of 2 effectively disables thread pooling. |
Timeout |
org.apache.felix.eventadmin.Timeout |
Integer, 5000 |
The black-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 blacklisted. |
Require Topic |
org.apache.felix.eventadmin.RequireTopic |
Boolean, true |
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 |
org.apache.felix.eventadmin.IgnoreTimeout |
String, empty |
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. |