5 Service Layer

5.1 Introduction

The OSGi Service Layer defines a dynamic collaborative model that is highly integrated with the Life Cycle Layer. The service model is a publish, find and bind model. A service is a normal Java object that is registered under one or more Java interfaces with the service registry. Bundles can register services, search for them, or receive notifications when their registration state changes.

5.1.1 Essentials

  • Collaborative - The service layer must provide a mechanism for bundles to publish, find, and bind to each other's services without having a priori knowledge of those bundles.

  • Dynamic - The service mechanism must be able to handle changes in the outside world and underlying structures directly.

  • Secure - It must be possible to restrict access to services.

  • Reflective - Provide full access to the Service Layer's internal state.

  • Versioning - Provide mechanisms that make it possible to handle the fact that bundles and their services evolve over time.

  • Persistent Identifier - Provide a means for bundles to track services across Framework restarts.

5.1.2 Entities

  • Service - An object registered with the service registry under one or more interfaces together with properties. The service can be discovered and used by bundles.

  • Service Registry - Holds the service registrations.

  • Service Reference - A reference to a service. Provides access to the service's properties but not the actual service object. The service object must be acquired through a bundle's Bundle Context.

  • Service Registration - The receipt provided when a service is registered. The service registration allows the update of the service properties and the unregistration of the service.

  • Service Permission - The permission to use an interface name when registering or using a service.

  • Service Scope - Indicates how service objects are obtained when requesting a service object. The following service scopes are defined: singleton, bundle, and prototype. The default service scope is singleton.

  • Service Factory - A facility to let the registering bundle customize the service object for each using bundle. When using a Service Factory, the service scope of the service is bundle.

  • Prototype Service Factory - A facility to let the registering bundle customize the service object for each caller. When using a Prototype Service Factory, the service scope of the service is prototype.

  • Service Objects - A facility to let the using bundle obtain multiple service objects for a service with prototype service scope.

  • Service Listener - A listener to Service Events.

  • Service Event - An event holding information about the registration, modification, or unregistration of a service object.

  • Filter - An object that implements a simple but powerful filter language. It can select on properties.

  • Invalid Syntax Exception - The exception thrown when a filter expression contains an error.

Figure 5.1 Class Diagram org.osgi.framework Service Layer

Class Diagram org.osgi.framework Service Layer

5.2 Services

In the OSGi framework, bundles are built around a set of cooperating services available from a shared service registry. Such an OSGi service is defined semantically by its service interface and implemented as a service object.

The service interface should be specified with as few implementation details as possible. OSGi has specified many service interfaces for common needs and will specify more in the future.

The service object is owned by, and runs within, a bundle. This bundle must register the service object with the Framework service registry so that the service's functionality is available to other bundles under control of the Framework.

Dependencies between the bundle owning the service and the bundles using it are managed by the Framework. For example, when a bundle is stopped, all the services registered with the Framework by that bundle must be automatically unregistered.

The Framework maps services to their underlying service objects, and provides a simple but powerful query mechanism that enables a bundle to request the services it needs. The Framework also provides an event mechanism so that bundles can receive events of services that are registered, modified, or unregistered.

5.2.1 Service References

In general, registered service objects are referenced through ServiceReference objects. This avoids creating unnecessary dynamic service dependencies between bundles when a bundle needs to know about a service but does not require the service object itself.

A ServiceReference object can be stored and passed on to other bundles without the implications of dependencies. A ServiceReference object encapsulates the properties and other meta-information about the service object it represents. This meta-information can be queried by a bundle to assist in the selection of a service that best suits its needs.

When a bundle queries the Framework service registry for services, the Framework must provide the requesting bundle with the ServiceReference objects of the requested services, rather than with the services themselves. See Locating Services.

A ServiceReference object may also be obtained from a ServiceRegistration object.

A ServiceReference object is valid only as long as the service is registered. However, its properties must remain available as long as the ServiceReference object exists.

When a bundle wishes to use the service object, it can be obtained by using the ServiceReference. See Getting Service Objects.

5.2.2 Service Interfaces

A service interface is the specification of the service's public methods.

In practice, a bundle developer creates a service object by implementing its service interface and registers the service object with the Framework service registry. Once a bundle has registered a service object under an interface name, the associated service can be acquired by bundles under that interface name, and its methods can be accessed by way of its service interface. The Framework also supports registering service objects under a class name, so references to service interface in this specification can be interpreted to be an interface or class.

When requesting a service object from the Framework, a bundle can specify the name of the service interface that the requested service object must implement. In the request, the bundle may also specify a filter string to narrow the search.

Many service interfaces are defined and specified by organizations such as the OSGi Alliance. A service interface that has been accepted as a standard can be implemented and used by any number of bundle developers.

5.2.3 Registering Services

A bundle publishes a service by registering a service object with the Framework service registry. A service object registered with the Framework is exposed to other bundles installed in the OSGi environment.

Every registered service object has a unique ServiceRegistration object, and has one or more ServiceReference objects that refer to it. These ServiceReference objects expose the registration properties of the service, including the set of service interfaces they implement. The ServiceReference object can then be used to acquire a service object that implements the desired service interface.

The Framework permits bundles to register and unregister service objects dynamically. Therefore, a bundle is permitted to register service objects at any time during the STARTING, ACTIVE or STOPPING states.

A bundle registers a service object with the Framework by calling one of the BundleContext.registerService methods on its BundleContext object:

The names of the service interfaces under which a bundle wants to register its service are provided as arguments to the registerService methods. The Framework must ensure that the service object actually is an instance of each specified service interfaces, unless the object is a Service Factory. See Service Factory and Prototype Service Factory.

To perform this check, the Framework must load the Class object for each specified service interface from either the bundle or a shared package. For each Class object, Class.isInstance must be called and return true on the Class object with the service object as the argument.

The service object being registered may be further described by a Dictionary object, which contains the properties of the service as a collection of key/value pairs.

The service interface names under which a service object has been successfully registered are automatically added to the service's properties under the key objectClass. This value must be set automatically by the Framework and any value provided by the bundle must be overridden.

If the service object is successfully registered, the Framework must return a ServiceRegistration object to the caller. A service object can be unregistered only by the holder of its ServiceRegistration object (see the unregister() method). Every successful service object registration must yield a unique ServiceRegistration object even if the same service object is registered multiple times.

Using the ServiceRegistration object is the only way to reliably change the service's properties after it has been registered (see the setProperties(Dictionary) method). Modifying a service's Dictionary object after the service object is registered may not have any effect on the service's properties.

The process of registering a service object is subject to a permission check. The registering bundle must have ServicePermission[<name>,REGISTER] to register the service object under all the service interfaces specified. Otherwise, the service object must not be registered, and a SecurityException must be thrown.

5.2.4 Early Need for ServiceRegistration Object

The registration of a service object will cause all registered ServiceListener objects to be notified. This is a synchronous notification. This means that such a listener can get access to the service and call its methods before the registerService method has returned the ServiceRegistration object. In certain cases, access to the ServiceRegistration object is necessary in such a callback. However, the registering bundle has not yet received the ServiceRegistration object. Figure 5.2 on page shows such a sequence.

Figure 5.2 Service Registration and registration

Service Registration and registration

In a case as described previously, access to the registration object can be obtained via a ServiceFactory object or PrototypeServiceFactory object. If a ServiceFactory object or PrototypeServiceFactory object is registered, the Framework must call-back the registering bundle with the ServiceFactory method getService(Bundle,ServiceRegistration) or the PrototypeServiceFactory method getService(Bundle,ServiceRegistration). The required ServiceRegistration object is passed as a parameter to these methods.

5.2.5 Service Properties

Properties hold information as key/value pairs. The key must be a String object and the value should be a type recognized by Filter objects (see Filters for a list). Multiple values for the same key are supported with arrays ([]) and Collection objects.

The values of properties should be limited to primitive or standard Java types to prevent unwanted inter bundle dependencies. The Framework cannot detect dependencies that are created by the exchange of objects between bundles via the service properties.

The key of a property is not case sensitive. ObjectClass, OBJECTCLASS and objectclass all are the same property key. A Framework must return the key in ServiceReference.getPropertyKeys in exactly the same case as it was last set. When a Dictionary object that contains keys that only differ in case is passed, the Framework must raise an exception.

The service properties are intended to provide information about the service. The properties should not be used to participate in the actual function of the service. Modifying the properties for the service registration is a potentially expensive operation. For example, a Framework may pre-process the properties into an index during registration to speed up later look-ups.

The Filter interface supports complex filtering; it can be used to find matching services. Therefore, all properties share a single namespace in the Framework service registry. As a result, it is important to use descriptive names or formal definitions of shorter names to prevent conflicts. Several OSGi specifications reserve parts of this namespace. All properties starting with the prefix service. and the property objectClass are reserved for use by OSGi specifications.

Table 5.1 contains a list of pre-defined properties.

Table 5.1 Standard Service Properties (+ indicates scalar, array of, or collection of)

Property Key Type Constants Property Description
objectClass String[]

OBJECTCLASS

The objectClass property contains the set of interface names under which a service object is registered with the Framework. The Framework must set this property automatically. The Framework must guarantee that when a service object is retrieved with getService(ServiceReference), it can be cast to any of the interface names.

service.bundleid Long

SERVICE_BUNDLEID

The service.bundleid property identifies the bundle registering the service. The Framework must set this property automatically with the value of the bundle id of the registering bundle.

service.description String

SERVICE_DESCRIPTION

The service.description property is intended to be used as documentation and is optional. Frameworks and bundles can use this property to provide a short description of a registered service object. The purpose is mainly for debugging because there is no support for localization.

service.id Long

SERVICE_ID

Every registered service object is assigned a unique, non-negative service.id by the Framework. This number is added to the service's properties. The Framework assigns a unique, non-negative value to every registered service object that is larger than values provided to all previously registered service objects.

service.pid String+

SERVICE_PID

The service.pid property optionally identifies a persistent, unique identifier for the service object. See Persistent Identifier (PID).

service.scope String

SERVICE_SCOPE

The service.scope property identifies the service's scope. The Framework must set this property automatically. If the registered service object implements PrototypeServiceFactory, then the value will be prototype. Otherwise, if the registered service object implements ServiceFactory, then the value will be bundle. Otherwise, the value will be singleton. See Service Scope.

service.ranking Integer

SERVICE_RANKING

See Service Ranking Order.

service.vendor String

SERVICE_VENDOR

This optional property can be used by the bundle registering the service object to indicate the vendor.


The values for these service properties must be set by the Framework. Any values specified for these service properties during service registration or service properties update must be ignored.

5.2.6 Service Ranking Order

When registering a service object, a bundle may optionally specify a SERVICE_RANKING service property of type Integer. This number specifies a ranking order between services. The highest number has the highest ranking and the lowest number (including negative numbers) has the lowest ranking. If no service.ranking service property is specified or its type is not Integer then a ranking of 0 must be used.

The ranking order is defined as follows:

  • Sorted on descending ranking number (highest first)

  • If the ranking numbers are equal, sorted on ascending service.id property (oldest first).

This ordering is complete because service ids are never reused and handed out in order of their registration time. That is, a service that is registered later will have a higher service id. Therefore, the ranking order is in descending service.ranking numeric order where ties give a preference to the earlier registrant.

The ranking order is the reverse of the natural ordering of a ServiceReference object.

The purpose of the ranking order is to allow:

  • Selection - When a single service must be chosen but multiple services qualify then the service with the highest ranking must be selected.

  • Ordering - When multiple services must be used in a specified order.

5.2.7 Persistent Identifier (PID)

The purpose of a Persistent Identifier (PID) is to identify a service across Framework restarts. Services that can reference the same underlying entity every time they are registered should therefore use a service property that contains a PID. The name of the service property for PID is defined as service.pid. The PID is a unique identifier for a service that persists over multiple invocations of the Framework. For a given service, the same PID should always be used. If the bundle is stopped and later started, the same PID must always be used.

The format of the PID should be:

    pid ::= symbolic-name                   // See 1.3.2

5.2.8 Locating Services

In order to use a service object and call its methods, a bundle must first obtain a ServiceReference object. The BundleContext interface defines a number of methods a bundle can call to obtain ServiceReference objects from the Framework:

  • getServiceReference(String), getServiceReference(Class) - These methods returns a ServiceReference object to a service object that implements, and was registered under, the name of the specified service interface. If multiple such service objects exist, a ServiceReference object to the service object with the highest SERVICE_RANKING is returned. If there is a tie in ranking, a ServiceReference object to the service object with the lowest SERVICE_ID (the service object that was registered first) is returned. If no matching service objects are registered then null must be returned.

  • getServiceReferences(String,String), getServiceReferences(Class,String) - These methods returns an array or collection, respectively, of ServiceReference objects for service objects that:

    • Implement and were registered under the specified service interface.

    • Satisfy the search filter specified. The filter syntax is further explained in Filters.

    If no matching service objects are registered then null must be returned by the getServiceReferences(String,String) method and an empty collection must be returned by the getServiceReferences(Class,String) method.

The caller receives zero or more ServiceReference objects. These objects can be used to retrieve properties of the underlying service, or they can be used to obtain the actual service object. See Getting Service Objects.

The above methods require that the caller has the necessary ServicePermission[ServiceReference, GET] to get the service object for the returned Service Reference. If the caller lacks the required permission, these methods must not include that Service Reference in the result.

5.2.9 Getting Service Properties

To allow for interrogation of service properties, the ServiceReference interface defines these two methods:

Both of these methods must continue to provide information about the referenced service object, even after it has been unregistered from the Framework. This requirement can be useful when a ServiceReference object is stored with the Log Service.

5.2.10 Information About Services

The Bundle interface defines these two methods for returning information pertaining to service usage of the bundles:

  • getRegisteredServices() - Returns the ServiceReference objects for the service objects that the bundle has registered with the Framework.

  • getServicesInUse() - Returns the ServiceReference objects for the service objects that the bundle is currently using.

5.2.11 Service Exceptions

The Service Exception is a Run Time exception that can be used by the Framework to report errors or by user code that needs to signal a problem with a service. An exception type available from this exception provides the detailed information about the problem that caused the exception to be thrown.

Implementations of the framework or user code are allowed to throw sub classes of the ServiceException class. If a sub class is thrown for a reason other than one of the specified types, then the type should be set to SUBCLASSED. Sub classes that provide additional information for a specified type should use the specified type.

5.2.12 Services and Concurrency

Services published on one thread and obtained on another thread must be safe to use. That is, the Framework must guarantee that there is a happens-before relationship between the time a service is registered and the time a service object or Service Reference is obtained. That is both the registering and obtaining threads must be properly synchronized with each other.

5.3 Service Scope

The SERVICE_SCOPE service property identifies the scope of the registered service object. The following service scopes are supported by the Framework:

  • SCOPE_SINGLETON - Identifies the registered service object as a single service object which will be used by all bundles requesting the service object.

  • SCOPE_BUNDLE - Identifies the registered service object as a Service Factory. A Service Factory allows the registering bundle to customize the service object for each bundle requesting the service object. See Service Factory

  • SCOPE_PROTOTYPE - Identifies the registered service object as a Prototype Service Factory. A Prototype Service Factory allows the registering bundle to customize the service object for each request for the service object. See Prototype Service Factory.

The Framework must set the SERVICE_SCOPE service property automatically depending on the type of registered service object. If the registered service object implements PrototypeServiceFactory, then the value must be SCOPE_PROTOTYPE. Otherwise, if the registered service object implements ServiceFactory, then the value must be SCOPE_BUNDLE. Otherwise, the value must be SCOPE_SINGLETON. The SERVICE_SCOPE service property allows bundles to determine whether multiple service objects can be obtained for the service. Component models like Declarative Services and Blueprint need to know if they can properly obtain multiple service objects for referenced services.

5.4 Getting Service Objects

There are two methods available to get service objects from the service registry:

These methods are used to obtain an actual service object so that the Framework can manage dependencies. If a bundle retrieves a service object, that bundle becomes dependent upon the life cycle of the registered service object. This dependency is tracked by the BundleContext object used to obtain the service object, directly or indirectly by a ServiceObjects object, and is one reason that it is important to be careful when sharing BundleContext and ServiceObjects objects with other bundles.

5.4.1 Getting a Single Service Object

The BundleContext is used when a bundle only needs a single service object. The BundleContext.getService(ServiceReference) method returns an object that implements the interfaces as defined by the objectClass property. A bundle making multiple calls to this method, without releasing the service object, will receive the same service object.

This method has the following characteristics:

  • Returns null if the underlying service object has been unregistered.

  • Determines if the caller has ServicePermission[ServiceReference,GET], to get a service object associated with the specified Service Reference. This permission check is necessary so that ServiceReference objects can be passed around freely without compromising security.

  • Increments the usage count of the service by one for this BundleContext object.

  • If the service has SCOPE_SINGLETON scope then the registered service object is returned. Otherwise, if the bundle context's usage count of the service is one, the registered service object is cast to a ServiceFactory object and the getService(Bundle,ServiceRegistration) method is called to create a customized service object for the calling bundle which is then cached and returned. Otherwise, a cached copy of this customized service object is returned. See Service Factory for more information about ServiceFactory objects.

The BundleContext.getService(ServiceReference) method will only return a single service object for the bundle even if the service has SCOPE_PROTOTYPE scope. See Getting Multiple Service Objects for information on how to obtain multiple service objects for a service with SCOPE_PROTOTYPE scope.

5.4.2 Getting Multiple Service Objects

A ServiceObjects object is used when the service has SCOPE_PROTOTYPE scope and a bundle needs multiple service objects. A ServiceObjects object is associated with a single service and is obtained by calling the BundleContext.getServiceObjects(ServiceReference) method. The caller must have ServicePermission[ServiceReference,GET], to get a ServiceObjects object for a service.

The ServiceObjects.getService() method can be used to obtain multiple service objects for the associated service.

This method has the following characteristics for a service with SCOPE_PROTOTYPE scope:

  • Returns null if the underlying service object has been unregistered.

  • The registered service object is cast to a PrototypeServiceFactory object and the getService(Bundle,ServiceRegistration) method is called to create a customized service object. See Prototype Service Factory for more information about PrototypeServiceFactory objects.

  • The usage count for the customized service object is incremented.

  • The customized service object is returned.

The ServiceObjects.getService() method will only return a single service object for the bundle if the service has SCOPE_SINGLETON or SCOPE_BUNDLE scope. That is, the method behaves the same as the BundleContext.getService(ServiceReference) method and only a single service object is available. See Getting a Single Service Object.

5.5 Releasing Service Objects

A bundle must release a service object to remove the dynamic dependency on the bundle that registered the service object. Depending on how a service object was obtained, one of the following methods is used to release a service object:

5.5.1 Releasing a Single Service Object

The BundleContext interface defines a method to release a single service object: ungetService(ServiceReference)

This method has the following characteristics:

  • If the usage count of the service for this BundleContext object is zero or the service has been unregistered, false is returned.

  • The usage count of the service for this BundleContext object is decremented by one.

  • If the usage count of the service for this BundleContext object is now zero and the service has SCOPE_BUNDLE or SCOPE_PROTOTYPE scope, the registered service object is cast to a ServiceFactory object and the ungetService(Bundle,ServiceRegistration,S) method is called to release the previously cached customized service object for the calling bundle. The cached customized service object must be unreferenced by the Framework so it may be garbage collected. See Service Factory for more information about ServiceFactory objects.

  • true is returned.

5.5.2 Releasing Multiple Service Objects

A ServiceObjects object can be used to obtain multiple service objects for the associated service if the service has SCOPE_PROTOTYPE scope. The ServiceObjects interface defines a method to release one of the service objects obtained by a bundle: ungetService(S). If the associated service has SCOPE_SINGLETON or SCOPE_BUNDLE scope, this method behaves the same as calling the BundleContext.ungetService(ServiceReference) method.

For a service with SCOPE_PROTOTYPE scope, the following steps are required to release the specified service object:

  • If the associated service has been unregistered, this method returns without doing anything.

  • If the specified service object is null or was not provided by a ServiceObjects for the associated service, then an IllegalArgumentException is thrown.

  • The usage count for the specified service object is decremented.

  • If the usage count for the specified service object is now zero, the registered service object is cast to a PrototypeServiceFactory object and the ungetService(Bundle,ServiceRegistration,S) method is called to release the specified service object . The specified service object must be unreferenced by the Framework so it may be garbage collected. See Prototype Service Factory for more information about PrototypeServiceFactory objects.

5.6 Service Events

  • ServiceEvent - Reports registration, unregistration, and property changes for service objects. All events of this kind must be delivered synchronously. The type of the event is given by the getType() method, which returns an int. Event types can be extended in the future; unknown event types should be ignored.

  • ServiceListener - Called with a ServiceEvent when a service object has been registered or modified, or is in the process of unregistering. A security check must be performed for each registered listener when a ServiceEvent occurs. The listener must not be called unless the bundle which registered the listener has the required ServicePermission[ServiceReference,GET] for the corresponding Service Reference.

  • AllServiceListener - Services can only be seen when the service interface/class is not incompatible with the getter. The AllServiceListener is a marker interface that indicates that the getter wants to receive events for all services even if they are incompatible. See Multiple Version Export Considerations.

  • UnfilteredServiceListener - Extenders (bundles that can act on behalf of other bundles) frequently require unfiltered access to the service events for efficiency reasons. However, when they register without a filter then the Service Hooks, see Service Hook Service Specification, cannot provide the filter expression to the hooks. This filter information is sometimes necessary to detect when certain services are needed. Therefore, the UnfilteredServiceListener interface is a marker interface that instructs the framework to never filter service events but still pass the filter to the Service Hooks. Extenders should use a single UnfilteredServiceListener object with a compound filter.

A bundle that uses a service object should register a ServiceListener object to track the availability of the service object, and take appropriate action when the service object is unregistering.

5.6.1 Service Event Types

The following service events are defined:

  • REGISTERED - A service object has been registered. This event is synchronously delivered after the service object has been registered with the Framework.

  • MODIFIED - The properties of a service have been modified. This event is synchronously delivered after the service properties have been modified.

  • MODIFIED_ENDMATCH - Listeners registered with a filter can not see the MODIFIED event when a modification makes the filter no longer match. The lack of this notification complicates tracking a service with a filter. The MODIFIED_ENDMATCH event is therefore delivered if the old service properties matched the given filter but the modified properties do not. This event is synchronously delivered after the service properties have been modified.

  • UNREGISTERING - A service object is in the process of being unregistered. This event is synchronously delivered before the service object has completed unregistering. That is, during the delivery of this event, the service object is still valid. The bundle receiving this event must release all references to this service before this method returns.

New service event types can be added in future specifications

5.7 Stale References

The Framework must manage the dependencies between bundles. This management is, however, restricted to Framework structures. Bundles must listen to events generated by the Framework to clean up and remove stale references.

A stale reference is a reference to a Java object that belongs to the class loader of a bundle that is stopped or is associated with a service object that is unregistered. Standard Java does not provide any generic means to clean up stale references, and bundle developers must analyze their code carefully to ensure that stale references are deleted.

Stale references are potentially harmful because they hinder the Java garbage collector from harvesting the classes, and possibly the instances, of stopped bundles. This may result in significantly increased memory usage and can cause updating native code libraries to fail. Bundles using services are strongly recommended to use either the Service Tracker or Declarative Services.

Service developers can minimize the consequences of (but not completely prevent) stale references by using the following mechanisms:

  • Implement service objects using the ServiceFactory or PrototypeServiceFactory interface. The methods in the ServiceFactory and PrototypeServiceFactory interface simplify tracking bundles that use their service objects. See Service Factory and Prototype Service Factory.

  • Use indirection in the service object implementations. Service objects handed out to other bundles should use a pointer to the actual service implementation. When the service object becomes invalid, the pointer is set to null, effectively removing the reference to the actual service implementation.

The behavior of a service object that becomes unregistered is undefined. Such service objects may continue to work properly or throw an exception at their discretion. This type of error should be logged.

5.8 Filters

The Framework provides a Filter interface, and uses a filter syntax in the getServiceReferences methods that is defined in Filter Syntax. Filter objects can be created by calling BundleContext.createFilter(String) or FrameworkUtil.createFilter(String) with the chosen filter string. The filter supports the following match methods:

  • match(ServiceReference) - Match the properties of the Service Reference performing key lookup in a case insensitive way.

  • match(Dictionary) - Match the entries in the given Dictionary object performing key lookup in a case insensitive way.

  • matchCase(Dictionary) - Match the entries in the given Dictionary object performing key lookup in a case sensitive way.

  • matches(Map) - Match the entries in the given Map object. The map defines the case sensitivity of the match, standard maps are case sensitive but for example a TreeMap(String.CASE_INSENSITIVE_ORDER) provides a case insensitive map.

A Filter object can be used numerous times to determine if the match argument, a ServiceReference object, a Map object, or a Dictionary object, matches the filter string that was used to create the Filter object.

This matching requires comparing the value string in the filter to a target object from the service properties or dictionary. This comparison can be executed with the Comparable interface if the target object's class implements the Comparable interface. If the target object's class does not implement Comparable, the =, ~=, <= >= operators must return only true when the objects are equal (using the equals(Object) method).

The value string in the filter can be converted into an object suitable for comparison with the target object if the target object's class implements either a static valueOf method taking a single String object or a constructor taking a single String object. That is, if the target object is of class Target, the class Target must implement one of the following methods:

  • A static valueOf(String) method whose return type is assignable to Target

  • A Target(String) constructor

The Target class does not need to be a public class.

If during the evaluation of the filter a target object throws an exception, then this exception must not be re-thrown but caught. The result of the evaluation must then be interpreted as false.

The following example shows how a class can verify the ordering of an enumeration with a filter.

public class B implements Comparable {
    String keys[] = {"bugs", "daffy", "elmer", "pepe"};
    int         index;
    
    public B(String s) {
        for ( index=0; index<keys.length; index++ ) 
            if ( keys[index].equals(s) )
                return;
    }
    
    public int compareTo( Object other ) {
        B vother = (B) other;
        return index - vother.index;
    }
 }

The class could be used with the following filter:

(!(enum>=elmer))   -> matches bugs and daffy

The Filter.toString method must always return the filter string with unnecessary white space removed.

5.9 Service Factory

A Service Factory allows customization of the service object that is returned to a calling bundle. See Getting a Single Service Object. See also Prototype Service Factory.

Often, the service object that is registered by a bundle is returned directly to all using bundles. Such a service has SCOPE_SINGLETON scope. If, however, the registered service object implements the ServiceFactory interface, the service has SCOPE_BUNDLE scope and the Framework must call methods on the registered object to obtain a customized service object for each distinct bundle that gets the service.

When the customized service object is no longer used by a bundle - for example, when that bundle is stopped - then the Framework must notify the ServiceFactory object to release the customized service object.

ServiceFactory objects help manage bundle dependencies that are not explicitly managed by the Framework. By binding a returned service object to the requesting bundle, the service can be notified when that bundle ceases to use the customized service object, such as when it is stopped, and release resources associated with providing the service to that bundle.

The ServiceFactory interface defines the following methods:

  • getService(Bundle,ServiceRegistration) - This method is called by the Framework when it needs to obtain a customized service object for a requesting bundle. See Getting Service Objects.

    The Framework must check the customized service object returned by this method. If it is not an instance of all the classes named when the Service Factory was registered, null is returned to the requesting bundle. This check must be done as specified in Registering Services.

    If this method is called recursively for the same bundle then it must return null to break the recursion.

  • ungetService(Bundle,ServiceRegistration,S) - This method is called by the Framework when it needs to release a customized service object for a requesting bundle. See Releasing Service Objects.

5.10 Prototype Service Factory

A Prototype Service Factory allows customization of service objects and allows multiple service objects to be used by a bundle. See Getting Multiple Service Objects. See also Service Factory.

Often, the service object that is registered by a bundle is returned directly to all using bundles. Such a service has SCOPE_SINGLETON scope. If, however, the registered service object implements the PrototypeServiceFactory interface, the service has SCOPE_PROTOTYPE scope and the Framework must call methods on the registered service object to create customized service object instances for each call to ServiceObjects.getService(). Services with SCOPE_PROTOTYPE are useful for service objects that maintain state for the duration of usage and the using bundles require multiple service objects at the same time.

When the customized service objects are no longer used by a bundle - for example, when that bundle is stopped - then the Framework must notify the PrototypeServiceFactory object to release all the customized service objects.

PrototypeServiceFactory objects help manage bundle dependencies that are not explicitly managed by the Framework. By binding a returned service object to the requesting bundle and optionally some other stateful information, the Prototype Service Factory can be notified when that bundle ceases to use a customized service object, such as when it is stopped, and release resources associated with providing a customized service object to that bundle.

The PrototypeServiceFactory interface defines the following methods:

  • getService(Bundle,ServiceRegistration) - This method is called by the Framework when it needs to obtain a customized service object for a requesting bundle. See Getting Service Objects.

    The Framework must check the customized service object returned by this method. If it is not an instance of all the classes named when the Service Factory was registered, null is returned to the requesting bundle. This check must be done as specified in Registering Services.

    For each customized services object returned by this method, the Framework must hold a reference to it until it is released. This is necessary so the Framework can release all unused and unreleased customized service objects - for example, when a requesting bundle is stopped or the service object is unregistered.

    Since this method can return the same service object repeatedly, the framework must maintain a usage count for each customized service object so that it is only released when its usage count returns to zero.

  • ungetService(Bundle,ServiceRegistration,S) - This method is called by the Framework when it needs to release a customized service object for a requesting bundle. See Releasing Service Objects.

5.11 Unregistering Services

The ServiceRegistration interface defines the unregister() method to unregister the service object. This must remove the service object from the Framework service registry. Any ServiceReference object for this ServiceRegistration object can no longer be used to access the service object.

The fact that this method is on the ServiceRegistration object ensures that only the bundle holding this object can unregister the associated service object. The bundle that unregisters a service object, however, might not be the same bundle that registered it. As an example, the registering bundle could have passed the ServiceRegistration object to another bundle, endowing that bundle with the responsibility of unregistering the service object. Passing ServiceRegistration objects should be done with caution.

After unregister() successfully completes, the service objects must be:

  • Completely removed from the Framework service registry. Therefore, ServiceReference objects obtained for that service object can no longer be used to access a service object. Attempts to get a service object must return null.

  • Unregistered, even if other bundles had dependencies upon it. Bundles must be notified of the unregistration through the publishing of a ServiceEvent of type UNREGISTERING. This event is sent synchronously in order to give bundles the opportunity to release service objects.

    After receiving an event of type UNREGISTERING, a bundle should release the service objects and release any references it has to the service objects, so that the service objects can be garbage collected by the Java VM.

  • Released by all using bundles. For each bundle with unreleased service objects after all invoked ServiceListener objects have returned, the Framework must release all the service objects.

5.12 Multiple Version Export Considerations

Allowing multiple bundles to export a package with a given name causes some complications for Framework implementers and bundle programmers: The class name no longer uniquely identifies the exported class. This affects the service registry and permission checking.

5.12.1 Service Registry

Bundles must not be exposed to service objects for which there are conflicting class loaders. A bundle that gets a service object should be able to expect that it can safely cast the service object to any of the associated interfaces or classes under which the service object was registered and that it can access. No ClassCastExceptions should occur because those interfaces do not come from the same class loader. The service registry must therefore ensure that bundles can only see service objects that are not incompatible with the bundle. A service object is not incompatible with the bundle getting the service object when that bundle is not wired to another source class loader for this interface package than the bundle registering the service object. That is, it is either wired to the same source class loader or it has no wire for that package at all.

It is paramount that bundles are not accidentally confronted with incompatible service objects. Therefore, the following methods need to filter ServiceReference objects depending on the incompatibility of the interfaces with the calling bundle and only return Service Reference objects for services object that are not incompatible with the calling bundle for the specified interface. The bundle is identified by the used Bundle Context:

The getAllServiceReferences(String,String) method provides access to the service registry without any compatibility restrictions. Service References acquired through this method can be used to obtain service objects which can cause a Class Cast Exception when casting to the specified class name.

The ServiceReference.isAssignableTo(Bundle,String) method is also available to test if the bundle that registered the service object referenced by this ServiceReference and the specified bundle are both wired to same source for the specified interface.

5.12.2 Service Events

Service events must only be delivered to event listeners registered by bundles that are not incompatible with the referenced service object.

Some bundles need to listen to all service events regardless of any compatibility issues. A special type of ServiceListener can therefore be used: AllServiceListener. This is a marker interface; it extends ServiceListener. Listeners that use this marker interface indicate to the Framework that the bundle registering the event listener wants to see events for all services, including for service objects that are incompatible with the bundle.

5.13 Security

5.13.1 Service Permission

A ServicePermission has the following parameters.

  • target - Either the interface name or a filter expression for the GET action. The interface name may end with a wildcard to match multiple interface names. See java.security.BasicPermission for a discussion of wildcards. Filters are explained in Filter Based Permissions. The filter expression can additionally test for the service interface name with the objectClass key. Additionally, a service permission can also test for service properties that are part of the service registration. In general, all the service properties are usable in the filter expression. However, when there is a name conflict with the bundle identification properties, then the key can be prefixed with the commercial at sign ('@' \u0040). For example, @id will refer to a service property with the name id.

  • action - Supported actions are:

    • REGISTER - Indicates that the permission holder may register the service object

    • GET - Indicates that the holder may get the service.

When an object is being registered as a service object using BundleContext.registerService, the registering bundle must have the ServicePermission to register all the named classes. See Registering Services.

When a ServiceReference object is obtained from the service registry, see Locating Services, the calling bundle must have the required ServicePermission[ServiceReference, GET] to get the service object for each returned Service Reference.

When a service object is obtained using a ServiceReference object, see Getting Service Objects, the calling code must have the required ServicePermission[ServiceReference, GET] to get the service object associated with the Service Reference.

ServicePermission must be used as a filter for the service events received by the Service Listener, as well as for the methods to enumerate services, including Bundle.getRegisteredServices and Bundle.getServicesInUse. The Framework must assure that a bundle must not be able to detect the presence of a service that it does not have permission to access.

5.14 Changes