55 Service Hook Service Specification

55.1 Introduction

The OSGi framework has built-in support for the normal service primitives: publish, find, and bind. Despite their simplicity, these primitives are surprisingly powerful and have become quite popular. However, these primitives operate on information that is not completely visible to the bundles. For example, it is impossible to find out what services are being waited upon by other bundles. This information can be useful to provide a service just in time to that bundle. Additionally, it is also not possible to allow bundles functionality that interacts with the service engine. For example, a bundle could proxy another service but to do this transparently, it is required to hide the original service and offer the proxy only to a specific bundle. With the current primitives this is also not possible.

Therefore, this service hook specification provides a number of new mechanisms that closely interact with the service engine. These interactions are not intended for use by application bundles. The service primitives appear simple but require surprisingly complex code to make them appear simple to the bundle developer. Modifying the behavior of the service engine requires developers to closely follow the semantics of the OSGi service model and this is often hard, requiring a significant amount of code.

However, the service hooks provide a more symmetric model for service based programming that can act as a multiplier for the framework. The basic framework provides a powerful service engine and this specification allows a bundle to interact with this service engine

55.1.1 Essentials

  • Robust - The service primitives are very simple and work reliably in many scenarios. The specified hooks interact with this robust service engine. This interaction must not cause disruption of the normal operations.

  • Find listeners - Provide information about the services specific bundles are interested in.

  • Control visibility - Provide a mechanism to hide the visibility of a service to one or more bundles.

  • Intercept finds - Provide a mechanism to detect the searches of a bundle in the service registry and restrict the set of found service references.

  • Whiteboard based - Use the [1] Whiteboard Pattern to simplify the writing of the interceptors.

55.1.2 Entities

  • Client - The bundle that finds services, gets services, and/or receives events about services.

  • Handler - The bundle that registers a hook service and uses this to view or modify the state.

  • Target - A client bundle being targeted by a Handler.

  • Publisher - A client bundle that publishes services.

  • Consumer - A client bundle that consumes services.

  • Service Engine - The internal framework machinery that makes the service registry work.

  • Event Listener Hook - An Event Listener Hook intercepts service events before they are delivered to the client. The hook can select to remove events for specific bundles, which effective allows the hook to hide service events from a bundle.

  • Find Hook - A find hook intercepts the getServiceReference(s) call just before it is returns the result to the client. The result can be influenced by removing service entries. The find hook can be used to hide specific services for specific bundles.

  • Listener Hook - The listener hook provides insight into what services are being waited for in the system. It gets updated as service listeners are added and removed from the service registry.

Figure 55.1 Service Hooks, org.osgi.framework.hooks.service package

Service Hooks, org.osgi.framework.hooks.service package

55.1.3 Synopsis

A bundle that needs to hide service references from other bundles, or wants to be informed about the service events another bundle sees, can register a Find and Event Listener hook by registering a Find Hook service and an Event Listener Hook service with the framework. If a service event is generated, it will pass this event to the hook. The Event Listener Hook method can then inspect the arguments and optionally remove bundles from the event delivery list.

When a bundle uses the Bundle Context getServiceReference or getServiceReferences method, the Find Hook is notified with the list of discovered services. The hook can then remove any service references it wants to hide for the target bundle.

A bundle that wants to be aware of the services bundles are waiting for to be registered can register a Listener Hook. The framework will notify such hooks of all existing listeners as well as any changes in this list. The interceptor can use the filter information registered with the listener to detect the services that are being listened for.

55.2 Service Hooks

Service hooks provide an interaction with the service engine. This service engine provides the following primitives to the bundle:

  • Register a service under an interface/class name with a set of properties

  • Modify the set of properties of a service

  • Unregister a service

  • Find services based on their interface class name and/or property values

  • Listen for the life cycle events of a service

Figure 55.2 Service Primitives

Service Primitives

These primitives provide the cornerstone for service oriented programming. Service oriented programming consists of a code base that is de-coupled from the outside world through services. It can provide services to other bundles and it can consume services from other bundles. In the OSGi variation of service oriented programming, a service is a plain Java object that can be registered and unregistered at runtime.

The dynamics of OSGi services forces bundles to consider the absence, presence, and arrival of services. The cause of these dynamics can be external events, the result of an update, a bundle that is stopped, or the disappearance of a dependent service. A number of support libraries have been developed to minimize the amount of work for the developer that these dynamics can bring. The dynamic nature of services have made them an excellent tool to handle a wide array of dependency scenarios. Services can easily model a real world concept that a bundle depends upon. The features of the service model combined with support libraries like iPOJO, Declarative Services, Spring DM, and others have made the OSGi service model easy to use and very powerful.

A key aspect of the service model is the centrality of the OSGi framework. The service model acts as a guard between bundles. All service primitives pass through the framework and bundles can not intercept the result of other bundles interacting with the service registry. This design was intentional because it creates a boundary between bundles that increases robustness and security. However, the success of the service model also means that it becomes very attractive to interact with the service engine because all inter-bundle communication runs through this engine.

For complexity reasons, this specification does not introduce any ordering dependencies between the handlers and the client bundles.

All Service Hooks must be called in a privileged block, see Privileged Callbacks.

55.3 Usage Scenarios

The service hooks are general mechanisms but they were designed for some specific use cases. The following sections detail some of those use cases.

55.3.1 Proxying

In an OSGi system, all communication is normally tunneled through services. This makes it a very interesting place for a handler to intercept the service communications. These handlers can provide facilities like proxying, extra security, authentication, and other functions completely transparent to the parties that interact through services.

Proxying an existing service for a specific bundle requires the following steps:

  • Hide the existing service X

  • Register a proxy X' with the same properties as X

Registering a proxy service X' is trivial with the OSGi API, there are no special requirements on the service. As long as it implements the listed interfaces and provides the same attributes then it can pose as service X.

Hiding service X can be implemented with a combination of the Event Listener Hook and the Find Hook. The Event Listener Hook can be used to hide any service events from the target bundle and the Find Hook can be used to remove X from the delivered results of the getServiceReference(s) methods.

In the following figure the difference between a normal service interaction and a proxied interaction is depicted. In the normal case, Bundle A directly uses Service X, in the proxying case, the Proxy Bundle hides the original and provides an alternative.

Figure 55.3 Normal and proxied service interaction

Normal and proxied service interaction

However, there is one complication with the service hiding: what is the observing state of the target bundle when proxying begins? The Event Listener Hook must be registered to act as a filter on the service events. Just after this registration it can not determine what events have been seen by the target bundle. If it has already checked out X, the hook has no possibility to make the target bundle unget the service. A solution is to transiently stop the target bundle before the hook is registered and then transiently started it again, if the bundle is active. It is usually not advised to start/stop other bundles but this seems to be the only reliable solution. The problem can be alleviated when the start level is used to start the proxying handler bundle before the target bundles, in that case the target bundle is not started when the proxy is created. Though this optimizes the normal case, stopping the target bundle remains necessary because any of the bundles can be updated or stopped at any moment in time.

The following example shows how to hide a specific Service Reference from a specific bundle.

public class Hide implementsEventListenerHook, FindHook {
    final Bundle           bundle;
    final ServiceReference reference;
    final BundleContext    context;
    ServiceRegistration    reg;

    Hide(BundleContext context, 
        ServiceReference reference, 
        Bundle bundle) {
        this.context = context;
        this.bundle = bundle;
        this.reference = reference;
    }

    void open() {
        boolean active = 
            bundle.getBundleState() == Bundle.ACTIVE;
        if ( active )
            bundle.stop(Bundle.STOP_TRANSIENTLY);
        reg = context.registerService(
            new String[] {
                FindHook.class.getName(),
                EventListenerHook.class.getName() }, this, null);
        if ( active )
            bundle.start(Bundle.START_TRANSIENTLY);
    }

    public void close() { reg.unregister();}

The Hide class registers a Event Listener Hook and Find Hook service in the open method. Once registered, these services will receive their event callbacks. In the find hook, the target Service Reference is removed from the results if the bundle that called the getServiceReference(s) method is the target bundle.

    public void find(BundleContext ctx, 
        String name, String filter,
        boolean allServices, Collection refs) {
        if (ctx.getBundle() == bundle) {
            refs.remove(reference);
        }
    }

The event method is the opposite of the find method. In this method, the target bundle is removed from the event destinations if the related Service Reference is the target Service Reference.

    public void event(ServiceEvent event, 
        Collection bundles) {
        if (event.getServiceReference().equals(
            reference)) 
            bundles.remove(bundle);
    }
}

Once the Hide class is working, a proxy can be registered. For example:

void startProxy(ServiceReference ref,Bundlefor,
        Object proxy ) {
    Hide hide = new Hide(ctx, ref, for);
    hide.open();
    ServiceRegistration reg = ctx.registerService(
        (String[]) ref.getProperty("objectClass"),
        proxy,
        makeProperties(ref)  // copy the properties
    );
}
...

55.3.2 Providing a Service on Demand

The Listener Hook provides information about services that bundles are listening for. This makes it possible to look outside the OSGi framework to see if a listened for service could be provided in another way. For example, this service could come from Jini, SLP, or through some other means.

A Listener Hook receives events every time a bundle adds or removes a Service Listener. The Listener Hook is called with an added and removed method that take a collection of ListenerInfo objects. These objects provide the identity of the bundle that added a Service Listener and the optional filter string. The Listener Hook can use this filter string to look for specific properties, for example the objectClass property to determine the type that is being sought. Extracting the property from this filter string is non-trivial though regular expressions can in general be used to extract the needed information.

The following class uses an unexplained Track object to do the low level details. The example only shows how the Listener Hook can interact with these track objects.

public class OnDemand implements ListenerHook{
    final BundleContext context;
    final Map           tracked = HashMap();
    ServiceRegistration reg;

The constructor saves the Bundle Context. The registration is done in an open method.

    public OnDemand(BundleContext context) {
        this.context = context; }
    public void open() {
        reg = context.registerService(
            ListenerHook.class.getName(), this, null); }

The Listener Hook has added and removed methods that take collections. It is easier to handle the concurrency per object.

    public void added(Collection listeners) {
        for (Iterator i=listeners.iterator(); i.hasNext();) {
            add((ListenerHook.ListenerInfo) i.next());
    } }
    public void removed(Collection listeners) {
        for (Iterator i=listeners.iterator(); i.hasNext();) {
            remove((ListenerHook.ListenerInfo) i.next());
    } }

In the add hook, a ListenerInfo object provides the information about the Service Listener. In this example, a Track object is created for each active listener and associated with the given info object. This requires proper synchronization and should handle the rare case that the events are delivered out of order. The ListenerInfo object contains an isRemoved method that provides this information. If it is true, the corresponding removed event has already been called or will be called very soon. In that case, it is safe to discard the added event. For proper cleanup, the reg field is tested to see if it is set, if not, this call is during closing and should be ignored.

    synchronized void add(ListenerHook.ListenerInfoinfo) {
        if ( reg == null || info.isRemoved() )
            return;

        Track t = new Track(info);
        tracked.put(info, t);
        t.open();
    }

To remove a Track object it is necessary to consult the tracked map. If the track object is in the map, it must be closed. If not, there is an out of order delivery and this event can be ignored, the add method will ignore the corresponding ListenerInfo object because the isRemoved flag will be set. For proper closing, the reg field is tested for null.

    synchronized void remove(ListenerHook.ListenerInfoinfo){
        if ( reg == null )
            return;
        Track t = tracked.remove(info);
        if ( t != null ) 
            t.close();
    }

The close method is straightforward. The hook services are unregistered and all the remaining Track objects are closed. The reg field is used to make sure the event methods are ignoring any outstanding calls by setting it to null. After the synchronized block, any incoming event is ignored.

    public void close() {
        reg.unregister();
        synchronized(this) { reg = null; }
        for ( Track t : tracked.values() ) { t.close(); }
        tracked.clear();    }  }

55.4 Event Listener Hook

To intercept events being delivered to bundles, a handler must register an EventListenerHook object as a service with the framework. The framework must then send a service events to all the registered hooks. The calling order of the hooks is defined by the reversed compareTo ordering of their Service Reference objects. That is, the service with the highest ranking number is called first. Event Listener Hooks are called after the event is generated but before they are filtered by the optional filter expressions of the service listeners. Before the return, the handler can remove bundles from the given list. This allows an Event Listener Hook to hide service events for specific bundles.

The model is depicted in the Figure 55.4. A target bundle listens for service events but these events can be filtered by the handler because it has registered an Event Listener Hook service that is accepted by the Framework.

Figure 55.4 Event Listener Hook Interaction

Event Listener Hook Interaction

An Event Listener Hook receives all events, REGISTERED, MODIFIED, UNREGISTERING, and MODIFIED_ENDMATCH, that are to be delivered to all Service Listener objects registered with the framework, regardless of the presence of a service listener filter.

The EventListenerHook class has a single method:

  • event(ServiceEvent,Map) - A service event has been generated. The implementer of this method can optionally shrink the given map of target bundles to service listeners.

One of the parameters of the event method is a map of target bundles to a collection of ListenerInfo objects. The handler can shrink this map by removing bundles as well as specific service listeners from the collection of ListenerHook.ListenerInfo objects. Both the map and the collection must therefore implement the appropriate remove methods.

Removing a bundle from the list of target bundles will effectively hide the service event from the target bundle. The target bundle can still get the service, though the Find Hook can be used to block this access to the service.

Implementers of the Event Listener Hook must ensure that target bundles continue to see a consistent set of service events. Service events are normally used in a state machine. Such state machines can get confused if some events are missed. For example, if a Service Tracker sees a REGISTERED event but is hidden from the corresponding UNREGISTERING event then the service will never be released. A simple solution is to stop the target bundle when the filter is put in place. However, when the bundle that implements the Event Listener Hook is stopped, it will of course no longer be able to filter events and the target bundle might see an service events for services it was not aware of.

55.4.1 System Service Listeners

Service Listeners may be registered with the system bundle's BundleContext. If at least one Service Listener is registered with the system bundle's BundleContext then the system bundle's BundleContext must be contained in the keys of the shrinkable map passed to the event(ServiceEvent,Map) method. Just like other BundleContext keys contained in the shrinkable map, the system bundle's BundleContext may be removed. If the system bundle's BundleContext is removed by a service Event Listener Hook then the BundleContext will not be contained in the map for the remaining service Event Listener Hooks called. Unlike other BundleContext objects, if the system bundle's BundleContext is removed from the shrinkable map then the service event is still delivered to the Service Listeners added to the system bundle's BundleContext.

55.5 Find Hook

The Find Hook is called when a target bundle searches the service registry with the getServiceReference or getServiceReferences methods. A registered Find Hook service gets a chance to inspect the returned set of service references and can optionally shrink the set of returned services. The order in which the find hooks are called is the reverse compareTo ordering of their Service References. That is, the service with the highest ranking number must be called first.

  • find(BundleContext,String,String,boolean,Collection) - The callback when a bundle calls the getServiceReference, getServiceReferences, or getAllServiceReferences method. As parameters, it gets the bundle context of the calling bundle, the service name, the filter name, the flag that indicates that all services are considered or only the ones that are class compatible with the target bundle. The last parameter is the set of service references that will be returned. This list can be shortened by removing service references form the given list.

The purpose of the Find Hook is to limit the visibility of services to selected target bundles. For this reason, the hook implementation can remove selected service references from the result collection.

55.5.1 System Bundle Context

When one of the getServiceReference or getServiceReferences methods is called using the system bundle's BundleContext then the service Find Hooks are called in the same way the hooks are called when a normal BundleContext is used. The system bundle's BundleContext along with the shrinkable candidate service references collection is passed to the find(BundleContext,String,String,boolean,Collection) method. Service Find Hooks may remove service references from the shrinkable collection. If a service reference is removed by a service Find Hook then the service reference will not be contained in the collection for the remaining service find hooks called. Unlike other BundleContext objects, if the system bundle's BundleContext is used to find services then the Framework ignores the service reference removals performed by the service Find Hooks and allows the service references removed to remain visible in the find results.

55.6 Listener Hook

The Framework API provides extensive insight in the registration, modification, and unregistration of services. However, it does not provide the information about what services bundles are waiting for. It is a common pattern that a bundle waits for a service to arrive before it is able to perform its function, having the knowledge what bundles are waiting for, allows a number of interesting scenarios.

The Listener Hook is a [1] Whiteboard Pattern service that is informed about the coming and going of all service listeners. When a Listener Hook service is registered with the Framework, the Framework will inform this service of all existing listeners and keep it updated of all removed and newly registered service listeners. The events are dispatched in order of the Listener Hook service registration.

In the following figure, it is depicted how the interceptor can find out about target bundles listening for services. It listens to registration and unregistration of Service Listeners.

Figure 55.5 Listener Hook Interaction

Listener Hook Interaction

The ListenerHook interface is composed of the following methods:

  • added(Collection) - Inform the hook of the registered listeners. The collection is immutable and contains ListenerInfo objects. These objects identify a unique ServiceListener object registration with the framework. They provide the registering bundle as well as the optional filter. The ListenerInfo class is nested class of the ListenerHook class.

  • removed(Collection) -Inform the hook of listeners that have been removed because the bundle is stopped or the bundle implementation has unregistered a listener. The ListenerInfo objects are equal to their corresponding Info Listener object during the addition.

The ListenerHook.ListenerInfo class provides the following methods:

  • getBundleContext() - The Bundle Context of the bundle that registered the service listener.

  • getFilter() - The filter used in the registration.

  • isRemoved() - Provides information if this Listener Info is still valid.

A ListenerInfo object is related to the registration of a ServiceListener with the Framework. The Framework maintains only one registration for a specific, identity based, Service Listener object. That is, registering the same object again, even with a different filter, will automatically unregister the previous registration. This will be visible as a removed - added pair of calls.

The equality and hashCode method of a ListenerInfo object must guarantee that the hook can place the Listener Info objects in hashed collections, such that an ListenerInfo object received in the added method's collection parameter matches its corresponding ListenerInfo object in the removed method's collection parameter. This is trivially met by the identity equals and hashCode methods if the same objects are used in both methods.

The reason the Listener Hook provides methods that take collection instead of a single ListenerInfo object is because of performance optimization. When a Listener Hook service gets registered, there can already be a large number of Service Listeners available. Similarly, when a bundle gets stopped, it could have registered a number of service listeners that then need to be unregistered. Being able to provide all changes in a batch improves performance.

The framework must report each registration of a Service Listener with the Bundle Context with a new ListenerInfo object that is unequal to any other ListenerInfo object. If the same Service Listener object is registered multiple times, each previous registration must be removed before the listener is added again.

The event method in a Listener Hook is called synchronously with the registration of the Service Listener to minimize the overhead for the framework. However, this does not imply that delivery is always ordered. There are rare cases where a removal is reported before the corresponding addition. Handling this case is simplified by the isRemoved method. If the removed and added methods are synchronized, then the isRemoved method can be used in the added method to detect the out of order delivery. A simple strategy is to ignore removed events without corresponding added events and ignore added events where the ListenerInfo object is already removed.

The following code shows a skeleton of how the Listener Hook methods can be implemented.

final HashMap tracked = new HashMap();

public void added( Collection lis ) {
    for ( Iterator li = lis.iterator(); li.hasNext(); ) {   
        ListenerHook.ListenerInfo li =
            (ListenerHook.ListenerInfo) li.next();
        synchronized(tracked) {
            if ( li.isRemoved() )
                return;
            ... create some object t
            tracked.put( li, t );
        }
  }
}
public void removed( Collection lis ) {
    for ( Iterator li = lis.iterator(); li.hasNext(); ) {   
        ListenerHook.ListenerInfo li =
            (ListenerHook.ListenerInfo) li.next();
        synchronized(tracked) {
            Object t =  tracked.remove( li );
            if ( t != null )
                ... dispose object t
        }
  }
}

55.6.1 Filter

A key concept in the Listener Hook is the filter. When a bundle is interested in a specific set of services, it registers a service listener with a filter. This filter is an indication of what services are interesting to the target bundle. The objectclass property holds the names of the interfaces and classes. However, just searching for this property with a regular expression is not guaranteed to return a usable value. The form of the sub-expressions can make the property part of an and or even negate. For example, looking for the objectclass in the following expression gives a result that is the opposite of what is searched.

(!(objectclass=org.osgi.service.cm.ConfigurationAdmin))

However, understanding a full filter expression is quite difficult. An acceptable strategy is to look for the object classes in the filter string with a regular expression but evaluate the filter against any conclusions that are being drawn. That is, testing a Configuration Admin service against the filter in the previous example will not match.

Realistically, many scenarios that are enabled by the Listener Hook will require the filters to have a simple structure.

55.7 Architectural Notes

55.7.1 Remove Only

The Event Listener Hook and Find Hook both allow the interceptor to remove elements from a collection and not add elements. The reason is that adding almost inevitably violates framework invariants that can trip the receivers. These invariants are very important to keep the programming model for the bundle developers simple.

55.7.2 Ordinary Services

All service hooks are treated as ordinary services. If the framework uses them, their Service References will show that the system bundle is using them, and if a hook is a Service Factory, then the actual instance will be properly created.

The only special treatment of the service hooks is that the framework must not use them for the hooks themselves. That is, the Event and Find Hooks can not be used to hide the services from the framework.

55.7.3 Ordering

The hooks are very sensitive to ordering because they modify the basic behavior of the OSGi Framework. Before a hook is registered, a client bundle interacts with the framework directly. However, ordering in an OSGi Framework can never be relied upon from an programmer's perspective. It is bad practice to rely on start level ordering in a program because updates and other disturbances will inevitably break this ordering. Start level ordering is a tool for deployers to smoothen initialization problems, not to handle ordering dependencies.

Implementers of the hooks must therefore be intricately aware that they can be started before or after their target bundles are started.

55.7.4 Providing the Service Object

Many scenarios for the hooks specified here could be simplified by being able to intercept the getService call of the target bundle. This design was investigated and rejected because it created a dependency graph (registering bundle, proxying bundle, and target bundle) that could not be properly managed in a dynamic OSGi system. For example, if a proxying bundle provides an alternative implementation for a service, how does the receiving bundle know that it should stop using this service? It has no knowledge that the proxying bundle even exists. Instead of creating a much more complex service registry, it was decided to keep the model simple and reuse the existing primitives. This puts the complexity at implementing the hooks, but leaves the overall service model simple.

55.7.5 Multi Threading

All hooks in this specification must be thread safe because the hooks can be called any time. All hook methods must be re-entrant, the framework can enter them at any time, and in rare cases in the wrong order. Most methods will be called synchronously with framework activities. It is fully allowed to call the framework from any of the hook methods. However, even more than usual, it is highly recommended to not hold any locks while calling the framework.

55.8 Security

All hooks described in this specification are highly complex facilities that require great care in their implementation to maintain the Framework invariants concerning the service registry. It is therefore important that in a secure system the permission to register these hooks is only given to privileged bundles.

In this case, the user of the hook services is the framework. Therefore, there is never a need to provide:

  • ServicePermission[..EventListenerHook,GET],

  • ServicePermission[..FindHook,GET], or

  • ServicePermission[..ListenerHook,GET]

Implementers of these hooks must have:

  • ServicePermission[..EventListenerHook,REGISTER] for Event Listener Hook services.

  • ServicePermission[..FindHook,REGISTER] for Find Hook services

  • ServicePermission[..ListenerHook,REGISTER] for Listener Hook services

55.9 org.osgi.framework.hooks.service

Version 1.1

Framework Service Hooks Package Version 1.1.

Bundles wishing to use this package 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.framework.hooks.service; version="[1.1,2.0)"

55.9.1 Summary

55.9.2 public interface EventHook

OSGi Framework Service Event Hook Service.

Bundles registering this service will be called during framework service (register, modify, and unregister service) operations.

As of 1.1. Replaced by EventListenerHook.

Thread-safe

55.9.2.1 public void event(ServiceEvent event, Collection<BundleContext> contexts)

The service event to be delivered.

A collection of Bundle Contexts for bundles which have listeners to which the specified event will be delivered. The implementation of this method may remove bundle contexts from the collection to prevent the event from being delivered to the associated bundles. The collection supports all the optional Collection operations except add and addAll. Attempting to add to the collection will result in an UnsupportedOperationException. The collection is not synchronized.

Event hook method. This method is called prior to service event delivery when a publishing bundle registers, modifies or unregisters a service. This method can filter the bundles which receive the event.

55.9.3 public interface EventListenerHook

OSGi Framework Service Event Listener Hook Service.

Bundles registering this service will be called during framework service (register, modify, and unregister service) operations.

1.1

Thread-safe

55.9.3.1 public void event(ServiceEvent event, Map<BundleContext, Collection<ListenerHook.ListenerInfo>> listeners)

The service event to be delivered.

A map of Bundle Contexts to a collection of Listener Infos for the bundle's listeners to which the specified event will be delivered. The implementation of this method may remove bundle contexts from the map and listener infos from the collection values to prevent the event from being delivered to the associated listeners. The map supports all the optional Map operations except put and putAll. Attempting to add to the map will result in an UnsupportedOperationException. The collection values in the map supports all the optional Collection operations except add and addAll. Attempting to add to a collection will result in an UnsupportedOperationException . The map and the collections are not synchronized.

Event listener hook method. This method is called prior to service event delivery when a publishing bundle registers, modifies or unregisters a service. This method can filter the listeners which receive the event.

55.9.4 public interface FindHook

OSGi Framework Service Find Hook Service.

Bundles registering this service will be called during framework service find (get service references) operations.

Thread-safe

55.9.4.1 public void find(BundleContext context, String name, String filter, boolean allServices, Collection<ServiceReference<?>> references)

The bundle context of the bundle performing the find operation.

The class name of the services to find or null to find all services.

The filter criteria of the services to find or null for no filter criteria.

true if the find operation is the result of a call to BundleContext.getAllServiceReferences(String, String)

A collection of Service References to be returned as a result of the find operation. The implementation of this method may remove service references from the collection to prevent the references from being returned to the bundle performing the find operation. The collection supports all the optional Collection operations except add and addAll. Attempting to add to the collection will result in an UnsupportedOperationException. The collection is not synchronized.

Find hook method. This method is called during the service find operation (for example, BundleContext.getServiceReferences(String, String) ). This method can filter the result of the find operation.

55.9.5 public interface ListenerHook

OSGi Framework Service Listener Hook Service.

Bundles registering this service will be called during service listener addition and removal.

Thread-safe

55.9.5.1 public void added(Collection<ListenerHook.ListenerInfo> listeners)

A collection of ListenerInfos for newly added service listeners which are now listening to service events. Attempting to add to or remove from the collection will result in an UnsupportedOperationException. The collection is not synchronized.

Added listeners hook method. This method is called to provide the hook implementation with information on newly added service listeners. This method will be called as service listeners are added while this hook is registered. Also, immediately after registration of this hook, this method will be called to provide the current collection of service listeners which had been added prior to the hook being registered.

55.9.5.2 public void removed(Collection<ListenerHook.ListenerInfo> listeners)

A collection of ListenerInfos for newly removed service listeners which are no longer listening to service events. Attempting to add to or remove from the collection will result in an UnsupportedOperationException. The collection is not synchronized.

Removed listeners hook method. This method is called to provide the hook implementation with information on newly removed service listeners. This method will be called as service listeners are removed while this hook is registered.

55.9.6 public static interface ListenerHook.ListenerInfo

Information about a Service Listener. This interface describes the bundle which added the Service Listener and the filter with which it was added.

Thread-safe

Consumers of this API must not implement this type

55.9.6.1 public boolean equals(Object obj)

The object to compare against this ListenerInfo.

Compares this ListenerInfo to another ListenerInfo. Two ListenerInfos are equals if they refer to the same listener for a given addition and removal life cycle. If the same listener is added again, it must have a different ListenerInfo which is not equal to this ListenerInfo.

true if the other object is a ListenerInfo object and both objects refer to the same listener for a given addition and removal life cycle.

55.9.6.2 public BundleContext getBundleContext()

Return the context of the bundle which added the listener.

The context of the bundle which added the listener.

55.9.6.3 public String getFilter()

Return the filter string with which the listener was added.

The filter string with which the listener was added. This may be null if the listener was added without a filter.

55.9.6.4 public int hashCode()

Returns the hash code for this ListenerInfo.

The hash code of this ListenerInfo.

55.9.6.5 public boolean isRemoved()

Return the state of the listener for this addition and removal life cycle. Initially this method will return false indicating the listener has been added but has not been removed. After the listener has been removed, this method must always return true.

There is an extremely rare case in which removed notification to ListenerHooks can be made before added notification if two threads are racing to add and remove the same service listener. Because ListenerHooks are called synchronously during service listener addition and removal, the Framework cannot guarantee in-order delivery of added and removed notification for a given service listener. This method can be used to detect this rare occurrence.

false if the listener has not been removed, true otherwise.

55.10 References