157 Typed Event Service Specification

157.1 Introduction

Eventing systems are a common part of software programs, used to distribute information between parts of an application. To address this, the Event Admin Service Specification was created as one of the earliest specifications defined by the OSGi Compendium. The design and usage of the Event Admin specification, however, makes certain trade-offs that do not fit well with modern application design:

  • Type Safety - Events are sent and received as opaque maps of key-value pairs. The “schema” of an event is therefore ill-defined and relies on “magic strings” being used correctly to locate data, and on careful handling of data values with unknown types.

  • Unhandled Events - Events that are sent but have no interested Event Consumers are silently discarded. There is no way to know that an event was not handled, short of disrupting the system by registering a handler for all events.

  • Observability - There is no simple, non-invasive way to monitor the flow of events through the system. The ability to monitor and profile applications using Event Admin is therefore relatively limited.

Adding these features to the original Event Admin Service Specification specification is not feasible without breaking backward compatibility for clients. Therefore this specification exists to provide an alternative eventing model which supports these different requirements by making different design trade-offs.

157.1.1 Essentials

  • Event - A set of data created by an Event Source, encapsulated as an object and delivered to one or more Event Consumers.

  • Event Schema - A definition of the expected data layout within an event, including the names of data fields and the types of data that they contain.

  • Event Topic - A String identifying the topic of an Event, effectively defining the Event Schema and the purpose of the event.

  • Event Source - A software component which creates and sends events.

  • Event Consumer - A software component which receives events.

  • DTO - A Data Transfer Object as per the OSGi DTO Specification.

  • Event Bus - A software component used by an Event Source and responsible for delivering Events to Event Consumers.

Figure 157.1 Class and Service overview

Class and Service overview

157.1.2 Entities

  • Typed Event Bus - A service registered by the Typed Event implementation that can be passed an Event object and that will distribute that event to any suitable Event Handler Services.

  • Event Handler - A service registered by an Event Consumer suitable for receiving Event data from the Typed Event Bus.

157.2 Events

In this specification an Event is a set of string keys associated with data values. The defined set of allowable keys and permitted value types for the keys in an Event is known as the Event Schema. Both the Event Source and Event Consumers must agree on a schema, or set of compatible schemas, in order for events to be consumed correctly.

157.2.1 Type Safe Events

A Type Safe Event is one in which the Event Schema is defined as a Java class. Using a Java class provides a formal definition of the schema - event data uses field names in the class as the keys, and each field definition defines the permitted type of the value.

Type Safe Event classes are expected to conform to OSGi DTO rules. The architecture of OSGi DTOs is described in OSGi Core Release 8. All methods, all static fields, and any non public instance fields of an event object must be ignored by the Typed Event Service when processing the Event data.

Some implementations of the Typed Event Service may support Type Safe Event classes that do not conform to the DTO rules, transforming them as needed in an implementation specific way. This is permitted by this specification, however consumers which rely on this behaviour may not be portable between different implementations of this specification.

157.2.1.1 Nested Data Structures

OSGi DTOs are permitted to have data values which are also DTOs, allowing nested data structures to be created. This is also allowed for Type Safe Events, but with the same restriction that the event data must be a tree. There is no restriction on the depth of nesting permitted.

157.2.2 Untyped Events

An Untyped Event is one in which there is no Java class defining the Event Schema. In this case the event data is defined using a Map type with String keys and values limited to types acceptable as fields in a DTO, excepting:

  • DTO types - an untyped event may not have DTOs inside it as these form part of a typed schema.

  • Maps are only permitted if they follow the rules for Untyped events, that is having String keys and DTO restricted value types excluding DTOs.

Untyped Event instances are capable of representing exactly the same data as present in a Type Safe Event instance, and are also subject to the same restrictions, that is the data must be a tree. Nested data should be included as sub-maps within the event map, and these sub-maps may in turn contain nested data.

157.2.3 Non Standard Type Safe Events

Some Event schemas may be represented by an existing type which does not match the OSGi DTO rules. In this case there are two main options:

  • Create a DTO representation of the event schema, and convert from the existing type into the DTO representation in code.

  • Convert the event data into an Untyped Event representation using nested Maps.

For example, the following code demonstrates how an object following the JavaBeans pattern can be converted into a DTO type or an untyped map:

public class ExampleJavaBean {
    private String message;
    
    public String getMessage() { return message; }

    public void setMessage(String message) { this.message = message; }
}
      
public class ExampleEvent {
    public String message;
}
                       
@Component
public class ExampleEventSource {
    private ExampleEvent createEventFromJavaBean(ExampleJavaBean bean) {
        return Converters.standardConverter().convert(bean)
                .to(ExampleEvent.class);
    }
    
    private Map<String, Object> createMapFromJavaBean(ExampleJavaBean bean) {
        return Converters.standardConverter().convert(bean)
                .to(new TypeReference<Map<String, Object>>(){});
    }
}

157.2.4 Event Mutability and Thread Safety

The Typed Event Service is inherently multi-threaded. Events may be published from multiple threads, and event data may be delivered to consumers on multiple threads. Event Sources and Event Consumers must therefore assume that event data is shared between threads from the moment that it is first passed to the TypedEventBus.

157.2.4.1 Typed Event Mutability

Typed Events, and in particular DTO types, provide a simple yet powerful mechanism for defining an Event Schema in a type-safe way. However their use of mutable public fields means that they are potentially dangerous when shared between threads. Event Sources and Event Consumers should assume that their event instances are shared between threads and therefore not mutate the event data after publication or receipt.

If an Event Handler does need to make changes to an incoming event then it must copy the event data into a new DTO instance. Note that any nested DTO values in the event data must also be copied if they are to be mutated.

157.2.4.2 Untyped Event Mutability

When an event source publishes untyped event data, it passes a Map instance to the Typed Event Bus. The Typed Event Bus is not required to take a copy of this Map, and therefore the event source must not change the Map, or any data structures within the Map, after the call to deliverUntyped(String,Map).

Untyped Events are delivered as implementations of the Map interface. Bundles consuming untyped events should not rely on the event object being any particular implementation of Map, and should treat the event object as immutable. The Typed Event Bus implementation may make copies of the event data, or enforce the immutability of the map, before passing the event data to an Event Handler.

157.3 Publishing Events

To publish an event, the Event Source must retrieve the Typed Event Bus service from the OSGi service registry. The Event Source then creates an event object and calls one of the Typed Event Bus service's methods to publish the event. Event publication is asynchronous, meaning that when a call to the Typed Event Bus returns there is no guarantee that all, or even any, listeners have been notified.

157.3.1 Event Topics

Events are always published to a topic. The topic of an event defines the schema of the event. Topics exist in order to give Event Consumers information about the schema of the event, and the opportunity to register for just the events they are interested in. When a topic is designed, its name should not include any other information, such as the publisher of the event or the data associated with the event, those parts are intended to be stored in the event properties.

The topic therefore serves as a first-level filter for determining which handlers should receive the event. Typed Event service implementations use the structure of the topic to optimize the dispatching of the events to the handlers. The following example code demonstrates how to send an event to a topic.

public class ExampleEvent {
    public String message;
}         
            
@Component
public class ExampleEventSource {
    @Reference
    TypedEventBus bus;

    public void sendEvent() {
        ExampleEvent event = new ExampleEvent();
        event.message = "The time is " + LocalDateTime.now();

        bus.deliver("org/osgi/example/ExampleEvent", event);
    }
}

Topics are arranged in a hierarchical namespace. Each level is defined by a token and levels are separated by solidi ('/' \u002F). More precisely, the topic must conform to the following grammar:

// For further information see General Syntax Definitions in Core

topictoken  :: ( jletterordigit | '-' ) +
      
topic       ::= topictoken ( '/' topictoken ) *

Topics should be designed to become more specific when going from left to right. Consumers can provide a prefix that matches a topic, using the preferred order allows a handler to minimize the number of prefixes it needs to register.

Topics are case-sensitive. As a convention, topics should follow the reverse domain name scheme used by Java packages to guarantee uniqueness. The separator must be a solidus ('/' \u002F) instead of the full stop ('.' \u002E).

This specification uses the convention fully/qualified/package/ClassName/ACTION. If necessary, a pseudo-class-name is used.

157.3.2 Automatically Generated Topics

In many cases the name of a topic contains no information other than defining the schema of the events sent on that topic. Therefore, when publishing a Typed Event to the Typed Event Bus, the Typed Event implementation is able to automatically generate a topic name based on the the type of the event object being published.

For the deliver(Object) method on the Typed Event Bus where no topic string is provided, the implementation must create a topic string using the fully qualified class name of the event object. To convert the class name into a valid topic the full stop . separators must be converted into solidus / separators. A non-normative example implementation follows:

public void deliver(Object event) {
    String topicName = event.getClass().getName().replace('.', '/');
    
    this.deliver(topicName, event);
}

The following example demonstrates how an Event Source can make use of an automatically generated topic name.

package org.osgi.example;

public class ExampleEvent {
    public String message;
}          
            
@Component
public class ExampleEventSource {
    @Reference
    TypedEventBus bus;

    public void sendEvent() {
        ExampleEvent event = new ExampleEvent();
        event.message = "The time is " + LocalDateTime.now();

        // This event will be delivered to the 
        // topic "org/osgi/example/ExampleEvent"
        bus.deliver(event);
    }
}

157.3.3 Thread Safety

The TypedEventBus implementation must be thread safe and allow for simultaneous event publication from multiple threads. For any given source thread, events must be delivered in the same order as they were published by that thread. Events published by different threads, however, may be delivered in a different order from the one in which they were published.

For example, if thread A publishes events 1, 2 and 3, while thread B publishes events 4, 5 and 6, then the events may be delivered:

  • 1, 2, 3, 4, 5, 6

  • 4, 1, 2, 5, 6, 3

  • and so on

but events will never be delivered 1, 2, 6, 4, 5, 3

157.4 Receiving Events

Event Consumers can receive events by registering an appropriate Event Handler service in the Service Registry. This is a TypedEventHandler to receive events as type-safe objects, or an UntypedEventHandler to receive events as untyped Map structures.

Published events are then delivered, using the whiteboard pattern, to any Event Handler service which has registered interest in the topic to which the event was published.

157.4.1 Receiving Typed Events

Typed Events are received by registering a TypedEventHandler implementation. This service has a single method notify which receives the String topic name and Object event data. The TypedEventHandler implementation must be registered as a service in the service registry using the TypedEventHandler interface.

The TypedEventHandler interface is parameterized, and so it is expected that the implementation reifies the type parameter into a specific type. In this case the Typed Event implementation must adapt the Event object into the type defined by the TypedEventHandler implementation. Implementations of this specification are free to choose their own adaptation mechanism, however it must guarantee at least the same functionality as Converter Specification.

A simple example of receiving a typed event follows:

public class ExampleEvent {
    public String message;
}         
            
@Component
public class ExampleTypedConsumer implements TypedEventHandler<ExampleEvent> {
    @Override
    public void notify(String topic, ExampleEvent event) {
        System.out.println("Received event: " + event.message);
    }
}

If the TypedEventHandler implementation is unable to reify the type, or the required type is more specific than the reified type, then the Typed Event Handler must be registered with the event.type service property. This property has a string value containing the fully-qualified type name of the type that the Typed Event Handler expects to receive. This type must be loaded by the Typed Event implementation using the classloader of the bundle which registered the Typed Event Handler service. The loaded type must then be used as the target type when converting events. For example:

public class ExampleEvent {
    public String message;
}
            
public class SpecialisedExampleEvent extends ExampleEvent {
    public int sequenceId = Integer.MIN_VALUE;
}
            
@Component
@EventType(SpecialisedExampleEvent.class)
public class ExampleTypedConsumer implements TypedEventHandler<ExampleEvent> {
    @Override
    public void notify(String topic, ExampleEvent event) {
        System.out.println("Received event: " + event.message);
        
        // The event will always be of type SpecialisedExampleEvent
        System.out.println("Event sequence id was " + 
            ((SpecialisedExampleEvent) event).sequenceId);
    }
}

By default the reified type of the TypedEventHandler will be used as the target topic for the Event Handler. If the event.type property is set then this is used as the default topic instead of the reified type. To use a specific named topic the Typed Event Handler service may be registered with an event.topics service property specifying the topic(s) as a String+ value.

public class ExampleEvent {
    public String message;
}
                       
@Component
@EventTopics({"foo", "foo/bar"})
public class ExampleTypedConsumer implements TypedEventHandler<ExampleEvent> {
    @Override
    public void notify(String topic, ExampleEvent event) {
        System.out.println("Event received on topic: " + topic + 
                " with message: " + event.message);
    }
}

157.4.2 Receiving Untyped Events

Untyped Events are received by registering an UntypedEventHandler implementation. This service has a single method notifyUntyped which receives the String topic name and Map event data. The Untyped Event Handler implementation must be registered as a service in the service registry using the UntypedEventHandler interface.

When delivering an event to an Untyped Event Handler the Typed Event Service must, if necessary, convert the event data to a nested map structure.

The event.topics service property must be used when registering an Untyped Event Hander service. If it is not, then no events will be delivered to that Untyped Event Handler service.

public class ExampleEvent {
    public String message;
}
                       
@Component
@EventTopics({"foo", "foo/bar"})
public class ExampleUntypedConsumer implements UntypedEventHandler {
    @Override
    public void notifyUntyped(String topic, Map<String,Object> event) {
        System.out.println("Event received on topic: " + topic
                + " with message: " + event.get("message"));
    }
}

157.4.3 Wildcard Topics

The event.topics property may contain one or more wildcard topics. These are Strings which contain a topic name and append “/*”. This value means that the Event Handler must be called for Events sent to sub-topics of the named topic. For example the component:

@Component
@EventTopics("foo/*")
public class ExampleUntypedConsumer implements UntypedEventHandler {
    @Override
    public void notifyUntyped(String topic, Map<String,Object> event) {
        System.out.println("Event received on topic: " + topic
                + " with message: " + event.get("message"));
    }
}

would receive events sent to the topics foo/bar and foo/baz, but not the topics foo or foobar/fizzbuzz.

The * character in a wildcard topic must always follow a solidus / character, and must be the final character in the topic string, meaning that topic names such as foo* and foo/*/bar are not valid. The only exception to this rule is that it is valid to use the topic name * to receive events on all topics. While it is valid to do so, using the topic * is not typically recommended. For a mechanism to monitor the events flowing through the system see Monitoring Events.

157.4.4 Unhandled Events

Unhandled Events are events sent by an Event Source but which have no Event Handler service listening to their topic. Rather than these events being discarded, the Typed Event implementation will search the service registry for services implementing UnhandledEventHandler.

If any services are found then the Typed Event implementation will call the notifyUnhandled method passing the topic name and event data to all of the registered Unhandled Event Handler services.

public class ExampleEvent {
    public String message;
}
                       
@Component
public class ExampleUnhandledConsumer implements UnhandledEventHandler {
    @Override
    public void notifyUnhandled(String topic, Map<String,Object> event) {
        System.out.println("Unhandled Event received on topic: " + topic);
    }
}

157.4.5 Filtering Events

Sometimes the use of a topic is insufficient to restrict the events received by an event consumer. In these cases the consumer can further restrict the events that they receive by using a filter. The filter is supplied using the event.filter service property, the value of which is an LDAP filter string. This filter is applied to the event data, and only events which match the filter are delivered to the event handler service.

157.4.5.1 Nested Event Data

Complex events may contain nested data structures, such as DTOs, as values in the event data. As LDAP filtering is only designed to match against simple data this means that some event properties cannot be filtered using the event.filter property. The event filter is therefore only suitable for use in matching top-level event properties.

157.4.5.2 Ignored Events

Note that the use of a filter is different from receiving an event and choosing to ignore it based on its data. If an event fails to match the filter supplied by an event handler service then it is not delivered to that event handler. This means that the event data remains eligible to be sent to an UnhandledEventHandler unless another event handler does receive it. An event that is received, but ignored, by an event handler service does count as having been delivered, and so will never be sent to an UnhandledEventHandler.

157.4.6 Failing Event Handlers

Event Handler implementations are called by the Typed Event Bus implementation, and are expected:

  • Not to throw exceptions from their callback method

  • To return quickly - any long running tasks should be moved to another thread

If a Typed Event Bus implementation detects an Event Handler that is behaving incorrectly, either by throwing exceptions, or by taking a long time to process the event, or some other problem, then the implementation may block further event delivery to that Event Handler.

If an Event Handler is blocked by the event implementation then this situation must be logged. Also, if a blocked Event Handler service is updated then the block must be removed by the implementation. If the updated service continues to behave incorrectly then the block may be reinstated.

157.4.7 Event Handler Service Properties

The service properties that can be used to configure an Event Handler service are outlined in the following table.

Table 157.1 Service properties applicable to Event Handler services

Service Property Name Type Description
event.topics String+

Declares the topic pattern(s) for which the service should be called. This service property is required for UntypedEventHandler services, but TypedEventHandler services may omit it if they are only interested in the default topic name for their reified type.

See TYPED_EVENT_TOPICS.

event.type String

Defines the target type into which events should be converted before being passed to the Event Handler service. This service property is forbidden for UntypedEventHandler services, but TypedEventHandler services may use it if they wish to further refine the type of data they wish to receive.

See TYPED_EVENT_TYPE.

event.filter String

Defines an LDAP filter which should be tested against the properties in the event data. Only events which pass the filter will be passed to the the Event Handler service. Ths service property is permitted for both TypedEventHandler and UntypedEventHandler services.

See TYPED_EVENT_FILTER.


157.4.8 Error Handling

There are several possible error scenarios for Event Handlers:

  • TypedEventHandler - If the target event type is not discoverable, that is there is no reified type information, nor is there an event.type property, then the target type for the event is not known. In this situation there is no way for the Typed Event implementation to correctly target an event schema, and the TypedEventHandler must be ignored. The implementation must write a message to the log indicating which service is being ignored.

  • TypedEventHandler - If the target event type is discoverable but cannot be loaded using the class loader of the bundle which registered the Typed Event Handler service then there is no way for the Typed Event implementation to correctly target an event schema, and the Event Handler must be ignored. The implementation must write a message to the log indicating which service is being ignored.

  • All Handler Types - If the event data cannot be adapted to the target type, that is the incoming data cannot be transformed due to badly mismatched property names or values, then that specific Event cannot be submitted to the Handler. The Typed Event implementation must write a message to the log indicating which service failed to receive the event. If this error occurs repeatedly then the Typed Event implementation may choose to deny list and ignore the Event Handler service. Deny listing decisions must be written to the log.

  • All Handler Types - If the event.topics property contains one or more invalid values then the Event Handler service must be ignored. The implementation must write a message to the log indicating which service is being ignored.

157.5 The Typed Event Bus Service

The Typed Event implementation must register a Typed Event Bus service in the service registry. This service must implement and advertise the TypedEventBus interface.

157.5.1 Error Handling

It is not possible to know that an Event cannot be delivered until delivery is attempted. It is therefore not possible (or acceptable, given the asynchronous nature of delivery) to throw an exception to the sender of an event if there are problems delivering the event. The Event Bus service should not throw exceptions from any publication methods except:

  • NullPointerException if the event data is null.

  • IllegalArgumentException if a topic name is supplied and it violates the topic name syntax.

157.6 Monitoring Events

An important part of a software system is the ability to monitor it appropriately to determine whether it is functioning correctly, without having the measurements disrupt the system. To this end the Typed Event implementation must register a TypedEventMonitor service which can be used to monitor the flow of events through the Event Bus.

Events flowing through the Typed Event Bus can be monitored using one of the monitorEvents methods from the TypedEventMonitor service. These methods return a PushStream which delivers MonitorEvent instances each time an event is sent via the TypedEventBus. The monitor events contain the event topic, the event data, and a timestamp indicating when the event was sent.

157.6.1 Event History

In a running system it is often useful for monitoring tools to replay recent data immediately after a problem has occurred. For that reason Typed Event Monitor instances may store past events so that they can be replayed if requested. There are two monitorEvents methods capable of replaying history:

  • monitorEvents(int) takes an int representing the number of past events that should be replayed from the cached history

  • monitorEvents(Instant) takes an Instant, representing the time in the past from which the stream of monitoring events should start.

Note that storing Event History is considered a best-effort option and it is not required that the implementation supply the full set of requested events. If insufficient past events are available then the implementation must provide the maximum amount of history available.

157.7 Capabilities

157.7.1 osgi.implementation Capability

The Typed Event implementation bundle must provide the osgi.implementation capability with the name TYPED_EVENT_IMPLEMENTATION. This capability can be used by provisioning tools and during resolution to ensure that a Typed Event implementation is present. The capability must also declare a uses constraint for the org.osgi.service.typedevent package and provide the version of this specification:

Provide-Capability: osgi.implementation;
 osgi.implementation="osgi.typedevent";
 uses:="org.osgi.service.typedevent";
 version:Version="1.0"

The RequireTypedEvent annotation can be used to require this capability.

This capability must follow the rules defined for the osgi.implementation Namespace.

157.7.2 osgi.service Capability

The bundle providing the Typed Event Bus service must provide capabilities in the osgi.service namespace representing the services it is required to register. This capability must also declare uses constraints for the relevant service packages:

Provide-Capability: osgi.service;
 objectClass:List<String>="org.osgi.service.typedevent.TypedEventBus";
 uses:="org.osgi.service.typedevent",
 osgi.service;
 objectClass:List<String>="org.osgi.service.typedevent.monitor.TypedEventMonitor";
 uses:="org.osgi.service.typedevent.monitor"

This capability must follow the rules defined for the osgi.service Namespace.

157.8 Security

157.8.1 Topic Permission

The TopicPermission class allows fine-grained control over which bundles may post events to a given topic and which bundles may receive those events.

The target parameter for the permission is the topic name. TopicPermission classes uses a wildcard matching algorithm similar to the BasicPermission class, except that solidi ('/' \u002F) are used as separators instead of full stop characters. For example, a name of a/b/* implies a/b/c but not x/y/z or a/b.

There are two available actions: PUBLISH and SUBSCRIBE. These control a bundle's ability to either publish or receive events, respectively. Neither one implies the other.

157.8.2 Required Permissions

Bundles that need to consume events must be granted permission to register the appropriate handler service. For Example: ServicePermission[org.osgi.service.typedevent.TypedEventHandler, REGISTER] or ServicePermission[org.osgi.service.typedevent.UntypedEventHandler, REGISTER] or ServicePermission[org.osgi.service.typedevent.UnhandledEventHandler, REGISTER]. In addition, bundles that consume events require TopicPermission[ <topic>, SUBSCRIBE ] for each topic they want to be notified about.

Bundles that need to publish events must be granted permission to get the TypedEventBus service, that is ServicePermission[ org.osgi.service.typedevent.TypedEventBus, GET] so that they may retrieve the Typed Event Bus and use it. In addition, event sources require TopicPermission[ <topic>, PUBLISH] for each topic they want to send events to. This includes any default topic names that are used when publishing

Bundles that need to monitor events flowing through the bus must be granted permission to get the TypedEventMonitor service, that is ServicePermission[ org.osgi.service.typedevent.monitor.TypedEventMonitor, GET] so that they may retrieve the Typed Event Monitor and use it.

Only a bundle that provides a Typed Event implementation should be granted ServicePermission[ org.osgi.service.typedevent.TypedEventBus, REGISTER] and ServicePermission[ org.osgi.service.typedevent.monitor.TypedEventMonitor, REGISTER] to register the services defined by this specification.

The Typed Event implementation must be granted ServicePermission[org.osgi.service.typedevent.TypedEventHandler, GET], ServicePermission[org.osgi.service.typedevent.UntypedEventHandler, GET], ServicePermission[org.osgi.service.typedevent.UnhandledEventHandler, GET], ServicePermission[org.osgi.service.typedevent.TypedEventBus, REGISTER] and ServicePermission[org.osgi.service.typedevent.monitor.TypedEventMonitor, REGISTER] as these actions are all required to implement the specification.

157.8.3 Security Context During Event Callbacks

During an event notification, the Typed Event implementation's Protection Domain will be on the stack above the handler's Protection Domain. Therefore, if a handler needs to perform a secure operation using its own privileges, it must invoke the doPrivileged method to isolate its security context from that of its caller.

The event delivery mechanism must not wrap event notifications in a doPrivileged call.

157.9 org.osgi.service.typedevent

Version 1.0

Typed Event Package Version 1.0.

Bundles wishing to use this package must list the package in the Import-Package header of the bundle's manifest. This package has two types of users: the consumers that use the API in this package and the providers that implement the API in this package.

Example import for consumers using the API in this package:

Import-Package: org.osgi.service.typedevent; version="[1.0,2.0)"

Example import for providers implementing the API in this package:

Import-Package: org.osgi.service.typedevent; version="[1.0,1.1)"

157.9.1 Summary

157.9.2 public final class TopicPermission
extends Permission

A bundle's authority to publish or subscribe to typed events on a topic.

A topic is a slash-separated string that defines a topic.

For example:

 org / osgi / service / foo / FooEvent / ACTION

Topics may also be given a default name based on the event type that is published to the topic. These use the fully qualified class name of the event object as the name of the topic.

For example:

 com.acme.foo.event.EventData

TopicPermission has two actions: publish and subscribe.

Thread-safe

157.9.2.1 public static final String PUBLISH = "publish"

The action string publish.

157.9.2.2 public static final String SUBSCRIBE = "subscribe"

The action string subscribe.

157.9.2.3 public TopicPermission(String name, String actions)

Topic name.

publish,subscribe (canonical order).

Defines the authority to publish and/or subscribe to a topic within the Typed Event service specification.

The name is specified as a slash-separated string. Wildcards may be used. For example:

    org/osgi/service/fooFooEvent/ACTION
    com/isv/*
    *

A bundle that needs to publish events on a topic must have the appropriate TopicPermission for that topic; similarly, a bundle that needs to subscribe to events on a topic must have the appropriate TopicPermssion for that topic.

157.9.2.4 public boolean equals(Object obj)

The object to test for equality with this TopicPermission object.

Determines the equality of two TopicPermission objects. This method checks that specified TopicPermission has the same topic name and actions as this TopicPermission object.

true if obj is a TopicPermission, and has the same topic name and actions as this TopicPermission object; false otherwise.

157.9.2.5 public String getActions()

Returns the canonical string representation of the TopicPermission actions.

Always returns present TopicPermission actions in the following order: publish,subscribe.

Canonical string representation of the TopicPermission actions.

157.9.2.6 public int hashCode()

Returns the hash code value for this object.

A hash code value for this object.

157.9.2.7 public boolean implies(Permission p)

The target permission to interrogate.

Determines if the specified permission is implied by this object.

This method checks that the topic name of the target is implied by the topic name of this object. The list of TopicPermission actions must either match or allow for the list of the target object to imply the target TopicPermission action.

    x/y/*,"publish" -> x/y/z,"publish" is true
    *,"subscribe" -> x/y,"subscribe"   is true
    *,"publish" -> x/y,"subscribe"     is false
    x/y,"publish" -> x/y/z,"publish"   is false

true if the specified TopicPermission action is implied by this object; false otherwise.

157.9.2.8 public PermissionCollection newPermissionCollection()

Returns a new PermissionCollection object suitable for storing TopicPermission objects.

A new PermissionCollection object.

157.9.3 public interface TypedEventBus

The Typed Event service. Bundles wishing to publish events must obtain this service and call one of the event delivery methods.

Thread-safe

Consumers of this API must not implement this type

157.9.3.1 public void deliver(Object event)

The event to send to all listeners which subscribe to the topic of the event.

Initiate asynchronous, ordered delivery of an event. This method returns to the caller before delivery of the event is completed. Events are delivered in the order that they are received by this method.

The topic for this event will be automatically set to the fully qualified type name for the supplied event object.

Logically equivalent to calling deliver(event.getClass().getName().replace('.', '/'), event)

NullPointerException– if the event object is null

157.9.3.2 public void deliver(String topic, Object event)

The topic to which this event should be sent.

The event to send to all listeners which subscribe to the topic.

Initiate asynchronous, ordered delivery of an event. This method returns to the caller before delivery of the event is completed. Events are delivered in the order that they are received by this method.

NullPointerException– if the event object is null

IllegalArgumentException– if the topic name is not valid

157.9.3.3 public void deliverUntyped(String topic, Map<String, ?> event)

The topic to which this event should be sent.

A Map representation of the event data to send to all listeners which subscribe to the topic.

Initiate asynchronous, ordered delivery of event data. This method returns to the caller before delivery of the event is completed. Events are delivered in the order that they are received by this method.

NullPointerException– if the event map is null

IllegalArgumentException– if the topic name is not valid

157.9.4 public final class TypedEventConstants

Defines standard names for Typed Event properties.

Consumers of this API must not implement this type

157.9.4.1 public static final String TYPED_EVENT_FILTER = "event.filter"

The name of the service property used to indicate a filter that should be applied to events from the TYPED_EVENT_TOPICS. Only events which match the filter will be delivered to the Event Handler service.

If this service property is not present then all events from the topic(s) will be delivered to the Event Handler service.

157.9.4.2 public static final String TYPED_EVENT_IMPLEMENTATION = "osgi.typedevent"

The name of the implementation capability for the Typed Event specification

157.9.4.3 public static final String TYPED_EVENT_SPECIFICATION_VERSION = "1.0"

The version of the implementation capability for the Typed Event specification

157.9.4.4 public static final String TYPED_EVENT_TOPICS = "event.topics"

The name of the service property used to indicate the topic(s) to which an a TypedEventHandler or UntypedEventHandler service is listening.

If this service property is not present then the reified type parameter from the TypedEventHandler implementation class will be used to determine the topic.

157.9.4.5 public static final String TYPED_EVENT_TYPE = "event.type"

The name of the service property used to indicate the type of the event objects received by a TypedEventHandler service.

If this service property is not present then the reified type parameter from the TypedEventHandler implementation class will be used.

157.9.5 public interface TypedEventHandler<T>

The type of the event to be received

Listener for Typed Events.

TypedEventHandler objects are registered with the Framework service registry and are notified with an event object when an event is sent.

TypedEventHandler objects are expected to reify the type parameter T with the type of object they wish to receive when implementing this interface. This type can be overridden using the TypedEventConstants.TYPED_EVENT_TOPICS service property.

TypedEventHandler objects may be registered with a service property TypedEventConstants.TYPED_EVENT_TOPICS whose value is the list of topics in which the event handler is interested.

For example:

 String[] topics = new String[] {
 		"com/isv/*"
 };
 Hashtable ht = new Hashtable();
 ht.put(EventConstants.TYPE_SAFE_EVENT_TOPICS, topics);
 context.registerService(TypedEventHandler.class, this, ht);

Thread-safe

157.9.5.1 public void notify(String topic, T event)

The topic to which the event was sent

The event that occurred.

Called by the TypedEventBus service to notify the listener of an event.

157.9.6 public interface UnhandledEventHandler

Listener for Unhandled Events.

UnhandledEventHandler objects are registered with the Framework service registry and are notified with an event object when an event is sent, but no other handler is found to receive the event

Thread-safe

157.9.6.1 public void notifyUnhandled(String topic, Map<String, Object> event)

The topic to which the event was sent

The event that occurred.

Called by the TypedEventBus service to notify the listener of an unhandled event.

157.9.7 public interface UntypedEventHandler

Listener for Untyped Events.

UntypedEventHandler objects are registered with the Framework service registry and are notified with an event object when an event is sent.

UntypedEventHandler objects must be registered with a service property TypedEventConstants.TYPED_EVENT_TOPICS whose value is the list of topics in which the event handler is interested.

For example:

 String[] topics = new String[] {
 		"com/isv/*"
 };
 Hashtable ht = new Hashtable();
 ht.put(EventConstants.TYPE_SAFE_EVENT_TOPICS, topics);
 context.registerService(UntypedEventHandler.class, this, ht);

Thread-safe

157.9.7.1 public void notifyUntyped(String topic, Map<String, Object> event)

The topic to which the event was sent

The event that occurred.

Called by the TypedEventBus service to notify the listener of an event.

157.10 org.osgi.service.typedevent.annotations

Version 1.0

Typed Event Annotations Package Version 1.0.

This package contains annotations that can be used to require the Typed Event implementation.

Bundles should not normally need to import this package as the annotations are only used at build-time.

157.10.1 Summary

157.10.2 @RequireTypedEvent

This annotation can be used to require the Typed Event implementation. It can be used directly, or as a meta-annotation.

This annotation is applied to several of the Typed Event component property type annotations meaning that it does not normally need to be applied to Declarative Services components which use the Typed Event specification.

1.0

CLASS

TYPE, PACKAGE

157.11 org.osgi.service.typedevent.monitor

Version 1.0

Typed Event Monitoring Package Version 1.0.

Bundles wishing to use this package must list the package in the Import-Package header of the bundle's manifest. This package has two types of users: the consumers that use the API in this package and the providers that implement the API in this package.

Example import for consumers using the API in this package:

Import-Package: org.osgi.service.typedevent.monitor; version="[1.0,2.0)"

Example import for providers implementing the API in this package:

Import-Package: org.osgi.service.typedevent.monitor; version="[1.0,1.1)"

157.11.1 Summary

  • MonitorEvent - A monitoring event.

  • TypedEventMonitor - The EventMonitor service can be used to monitor the events that are sent using the EventBus, and that are received from remote EventBus instances

157.11.2 public class MonitorEvent

A monitoring event.

Consumers of this API must not implement this type

157.11.2.1 public Map<String, Object> eventData

The Data from the Event in Map form

157.11.2.2 public Instant publicationTime

The time at which the event was published

157.11.2.3 public String topic

The Event Topic

157.11.2.4 public MonitorEvent()

157.11.3 public interface TypedEventMonitor

The EventMonitor service can be used to monitor the events that are sent using the EventBus, and that are received from remote EventBus instances

Thread-safe

Consumers of this API must not implement this type

157.11.3.1 public PushStream<MonitorEvent> monitorEvents()

Get a stream of events, starting now.

A stream of event data

157.11.3.2 public PushStream<MonitorEvent> monitorEvents(int history)

The requested number of historical events, note that fewer than this number of events may be returned if history is unavailable, or if insufficient events have been sent.

Get a stream of events, including up to the requested number of historical data events.

A stream of event data

157.11.3.3 public PushStream<MonitorEvent> monitorEvents(Instant history)

The requested time after which historical events, should be included. Note that events may have been discarded, or history unavailable.

Get a stream of events, including historical data events prior to the supplied time

A stream of event data

157.12 org.osgi.service.typedevent.propertytypes

Version 1.0

Typed Event Component Property Types Package Version 1.0.

When used as annotations, component property types are processed by tools to generate Component Descriptions which are used at runtime.

Bundles wishing to use this package at runtime must list the package in the Import-Package header of the bundle's manifest.

Example import for consumers using the API in this package:

Import-Package: org.osgi.service.typedevent.propertytypes; version="[1.0,2.0)"

157.12.1 Summary

157.12.2 @EventFilter

Component Property Type for the TypedEventConstants.TYPED_EVENT_FILTER service property of an Event Handler service.

This annotation can be used on an TypedEventHandler or UntypedEventHandler component to declare the value of the TypedEventConstants.TYPED_EVENT_FILTER service property.

Component Property Types

CLASS

TYPE

157.12.2.1 String value

Service property specifying the event filter for a TypedEventHandler or UntypedEventHandler service.

The event filter.

TypedEventConstants.TYPED_EVENT_FILTER

157.12.3 @EventTopics

Component Property Type for the TypedEventConstants.TYPED_EVENT_TOPICS service property of a TypedEventHandler or UntypedEventHandler service.

This annotation can be used on a component to declare the values of the TypedEventConstants.TYPED_EVENT_TOPICS service property.

Component Property Types

CLASS

TYPE

157.12.3.1 String[] value

Service property specifying the Event topics of interest to an TypedEventHandler or UntypedEventHandler service.

The event topics.

TypedEventConstants.TYPED_EVENT_TOPICS

157.12.4 @EventType

Component Property Type for the TypedEventConstants.TYPED_EVENT_TYPE service property of an TypedEventHandler service.

This annotation can be used on an TypedEventHandler component to declare the value of the TypedEventConstants.TYPED_EVENT_TYPE service property.

Component Property Types

CLASS

TYPE

157.12.4.1 Class<?> value

Service property specifying the EventType for a TypedEventHandler service.

The event filter.

TypedEventConstants.TYPED_EVENT_TYPE