Services¶
A service is an object that is registered to the service registry of the framework, associated to a set of specifications it implements and to properties.
The bundle that registers the service must keep track of the
ServiceRegistration
object returned by the framework.
It allows to update the service properties and to unregister the service.
This object shall not be accessible by other bundles/services, as it gives
access and control over the life cycle of the service it represents.
Finally, all services must be unregistered when their bundle is stopped.
A consumer can look for a service that matches a specification and a set of
properties, using its BundleContext
.
The framework will return a ServiceReference
object, which provides a
read-only access to the description of its associated service:
properties, registering bundle, bundles using it, etc..
Properties¶
When registered and while it is available, the properties of a service can be set and updated by its provider.
Although, some properties are reserved for the framework; each service has at least the following properties:
Name | Type | Description |
---|---|---|
objectClass | list of str | List of the specifications implemented by this service |
service.id | int | Identifier of the service. Unique in a framework instance |
The framework also uses the following property to sort the result of a service look up:
Name | Type | Description |
---|---|---|
service.ranking | int | The rank/priority of the service. The lower the rank, the more priority |
Service Factory¶
Warning
Service factories are a very recent feature of iPOPO and might be prone to bugs: please report any bug encounter on the project GitHub.
A service factory is a pseudo-service with a specific flag, which can create individual instances of service objects for different bundles. Sometimes a service needs to be differently configured depending on which bundle uses the service. For example, the log service needs to be able to print the logging bundle’s id, otherwise the log would be hard to read.
A service factory is registered in exactly the same way as a normal service,
using register_service()
, with the
factory
argument set to True
.
The only difference is an indirection step before the actual service object is
handed out.
The client using the service need not, and should not, care if a service is generated by a factory or by a plain object.
A simple service factory example
class ServiceInstance:
def __init__(self, value):
self.__value = value
def cleanup(self):
self.__value = None
def get_value(self):
return self.__value
class ServiceFactory:
def __init__(self):
# Bundle -> Instance
self._instances = {}
def get_service(self, bundle, registration):
"""
Called each time a new bundle requires the service
"""
instance = ServiceInstance(bundle.get_bundle_id())
self._instances[bundle] = instance
return instance
def unget_service(self, bundle, registration):
"""
Called when a bundle has released all its references
to the service
"""
# Release connections, ...
self._instances.pop(bundle).cleanup()
bundle_context.register_service(
"sample.factory", ServiceFactory(), {}, factory=True)
Note
The framework will cache generated service objects. Thus, at most one service can be generated per client bundle.
Prototype Service Factory¶
Warning
Prototype Service factories are a very recent feature of iPOPO and might be prone to bugs: please report any bug encounter on the project GitHub.
A prototype service factory is a pseudo-service with a specific flag, which can create multiple instances of service objects for different bundles.
Each time a bundle requires the service, the prototype service factory is
called and can return a different instance.
When called, the framework gives the factory the Bundle
object
requesting the service and the ServiceRegistration
of the requested
service.
This allows a single factory to be registered for multiple services.
Note that there is no Prototype Service Factory implemented in the core Pelix/iPOPO Framework (unlike the Log Service simple service factory).
A Prototype Service Factory is registered in exactly the same way as a normal
service, using register_service()
,
with the prototype
argument set to True
.
A simple prototype service factory example:
class ServiceInstance:
def __init__(self, value):
self.__value = value
def cleanup(self):
self.__value = None
def get_value(self):
return self.__value
class PrototypeServiceFactory:
def __init__(self):
# Bundle -> [instances]
self._instances = {}
def get_service(self, bundle, registration):
"""
Called each time ``get_service()`` is called
"""
bnd_instances = self._instances.setdefault(bundle, [])
instance = ServiceInstance(
[bundle.get_bundle_id(), len(bnd_instances)])
bnd_instances.append(instance)
return instance
def unget_service_instance(self, bundle, registration, service):
"""
Called when a bundle releases an instance of the service
"""
bnd_instances[bundle].remove(service)
service.cleanup()
def unget_service(self, bundle, registration):
"""
Called when a bundle has released all its references
to the service
"""
# Release global resources...
# When this method is called, all instances will have been cleaned
# up individually in ``unget_service_instance``
if len(self._instances.pop(bundle)) != 0:
raise ValueError("Should never happen")
bundle_context.register_service(
"sample.proto", PrototypeServiceFactory(), {}, factory=True)
Note
A Prototype Service Factory is considered as a Service Factory, hence
both is_factory()
and
is_prototype()
will return True
for this kind
of service
API¶
The service provider has access to the ServiceRegistration
object
created by the framework when register_service()
is called.
-
class
pelix.framework.
ServiceRegistration
(framework, reference, properties, update_callback)¶ Represents a service registration object
Parameters: - framework – The host framework
- reference – A service reference
- properties – A reference to the ServiceReference properties dictionary object
- update_callback – Method to call when the sort key is modified
-
get_reference
()¶ Returns the reference associated to this registration
Returns: A ServiceReference object
-
set_properties
(properties)¶ Updates the service properties
Parameters: properties – The new properties Raises: TypeError – The argument is not a dictionary
-
unregister
()¶ Unregisters the service
Consumers can access the service using its ServiceReference
object,
unique and constant for each service.
This object can be retrieved using the BundleContext
and its
get_service_reference*
methods.
A consumer can check the properties of a service through this object, before
consuming it.
-
class
pelix.framework.
ServiceReference
(bundle, properties)¶ Represents a reference to a service
Parameters: - bundle – The bundle registering the service
- properties – The service properties
Raises: BundleException – The properties doesn’t contain mandatory entries
-
get_bundle
()¶ Returns the bundle that registered this service
Returns: the bundle that registered this service
-
get_properties
()¶ Returns a copy of the service properties
Returns: A copy of the service properties
-
get_property
(name)¶ Retrieves the property value for the given name
Returns: The property value, None if not found
-
get_property_keys
()¶ Returns an array of the keys in the properties of the service
Returns: An array of property keys.
-
get_using_bundles
()¶ Returns the list of bundles that use this service
Returns: A list of Bundle objects
-
is_factory
()¶ Returns True if this reference points to a service factory
Returns: True if the service provides from a factory
-
is_prototype
()¶ Returns True if this reference points to a prototype service factory
Returns: True if the service provides from a prototype factory
Finally, here are the methods of the BundleContext class that can be used to handle services:
-
class
pelix.framework.
BundleContext
(framework, bundle) The bundle context is the link between a bundle and the framework. It is unique for a bundle and is created by the framework once the bundle is installed.
Parameters: - framework – Hosting framework
- bundle – The associated bundle
-
add_service_listener
(listener, ldap_filter=None, specification=None) Registers a service listener
The service listener must have a method with the following prototype:
def service_changed(self, event): ''' Called by Pelix when some service properties changes event: A ServiceEvent object ''' # ...
Parameters: - bundle_context – This bundle context
- listener – The listener to register
- ldap_filter – Filter that must match the service properties (optional, None to accept all services)
- specification – The specification that must provide the service (optional, None to accept all services)
Returns: True if the listener has been successfully registered
-
get_all_service_references
(clazz, ldap_filter=None) Returns an array of ServiceReference objects. The returned array of ServiceReference objects contains services that were registered under the specified class and match the specified filter expression.
Parameters: - clazz – Class implemented by the service
- ldap_filter – Service filter
Returns: The sorted list of all matching service references, or None
-
get_service
(reference) Returns the service described with the given reference
Parameters: reference – A ServiceReference object Returns: The service object itself
-
get_service_reference
(clazz, ldap_filter=None) Returns a ServiceReference object for a service that implements and was registered under the specified class
Parameters: - clazz – The class name with which the service was registered.
- ldap_filter – A filter on service properties
Returns: A service reference, None if not found
-
get_service_references
(clazz, ldap_filter=None) Returns the service references for services that were registered under the specified class by this bundle and matching the given filter
Parameters: - clazz – The class name with which the service was registered.
- ldap_filter – A filter on service properties
Returns: The list of references to the services registered by the calling bundle and matching the filters.
-
register_service
(clazz, service, properties, send_event=True, factory=False, prototype=False) Registers a service
Parameters: - clazz – Class or Classes (list) implemented by this service
- service – The service instance
- properties – The services properties (dictionary)
- send_event – If not, doesn’t trigger a service registered event
- factory – If True, the given service is a service factory
- prototype – If True, the given service is a prototype service factory (the factory argument is considered True)
Returns: A ServiceRegistration object
Raises: BundleException – An error occurred while registering the service
-
remove_service_listener
(listener) Unregisters a service listener
Parameters: listener – The service listener Returns: True if the listener has been unregistered
-
unget_service
(reference) Disables a reference to the service
Returns: True if the bundle was using this reference, else False