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.
-
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.
-
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.
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.
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.
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.
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:
-
registerService(String,Object,Dictionary) - For a service object registered under a single service interface.
-
registerService(String[],Object,Dictionary) - For a service object registered under multiple service interfaces.
-
registerService(Class,S,Dictionary) - For a service object registered under a single service interface using the class object for the interface name.
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 methods asMap(Dictionary) and asDictionary(Map) can be helpful when working with service
properties to provide Map views over Dictionaries and Dictionary views
over Maps.
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.
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.
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.
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[] |
The |
|
service.bundleid † |
Long |
The |
|
service.description |
String |
The
|
|
service.id † |
Long |
Every registered service object is assigned a
unique, non-negative |
|
service.pid |
String+ |
The |
|
service.scope † |
String |
The |
|
service.ranking |
Integer |
||
service.vendor |
String |
This optional property can be used by the bundle registering the service object to indicate the vendor. |
|
service.changecount |
Long |
This optional property can be used by the bundle registering the service object to indicate there has been a change in some data provided by the service. |
† 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.
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.
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
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, aServiceReference
object to the service object with the highest SERVICE_RANKING is returned. If there is a tie in ranking, aServiceReference
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 thennull
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.
To allow for interrogation of service properties, the
ServiceReference
interface defines these two
methods:
-
getPropertyKeys() - Returns an array of the property keys that are available.
-
getProperty(String) - Returns the value of a property.
-
getProperties() - Returns a copy of the properties.
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.
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.
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.
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.
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.
There are two methods available to get service objects from the service registry:
-
BundleContext.getService(ServiceReference) - This method should be used if the using bundle only needs a single service object.
-
ServiceObjects.getService() - This method should be used if the service has SCOPE_PROTOTYPE scope and the using bundle needs multiple service objects.
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.
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 thatServiceReference
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.
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.
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:
-
BundleContext.ungetService(ServiceReference) - This method should be used if the bundle is using a single service object and needs to release the single service object. See Getting a Single Service Object.
-
ServiceObjects.ungetService(S) - This method should be used if the bundle is using multiple service objects and needs to release one of the service objects. See Getting Multiple Service Objects.
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 aboutServiceFactory
objects. -
true
is returned.
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 aServiceObjects
for the associated service, then anIllegalArgumentException
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.
-
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 aServiceEvent
occurs. The listener must not be called unless the bundle which registered the listener has the requiredServicePermission[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.
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. TheMODIFIED_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
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
orPrototypeServiceFactory
interface. The methods in theServiceFactory
andPrototypeServiceFactory
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.
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 performing key lookup in a case sensitive way.
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, dictionary, or map. 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 toTarget
-
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.
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.
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.
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 returnnull
. -
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.
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.
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.
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.
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. Seejava.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 theobjectClass
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.
-
Added methods asMap(Dictionary) and asDictionary(Map) to facilitate working with Dictionaries and services.
-
Updated ServiceReference.isAssignableTo(Bundle,String) to clarify the behavior when no package source can be found.