def add_service_listener(self, listener, specification=None, ldap_filter=None): """ Registers a service listener :param listener: The service listener :param specification: The specification that must provide the service (optional, None to accept all services) :param ldap_filter: Filter that must match the service properties (optional, None to accept all services) :return: True if the listener has been registered, False if it was already known :raise BundleException: An invalid listener has been given """ if listener is None or not hasattr(listener, 'service_changed'): raise BundleException("Invalid service listener given") with self.__svc_lock: if listener in self.__listeners_data: self._logger.warning("Already known service listener '%s'", listener) return False try: ldap_filter = ldapfilter.get_ldap_filter(ldap_filter) except ValueError as ex: raise BundleException("Invalid service filter: {0}".format(ex)) stored = _Listener(listener, specification, ldap_filter) self.__listeners_data[listener] = stored self.__svc_listeners.setdefault(specification, []).append(stored) return True
def use_waiting_list(bundle_context): """ Utility context to use the iPOPO waiting list safely in a "with" block. It looks after the the iPOPO waiting list service and releases its reference when exiting the context. :param bundle_context: The calling bundle context :return: The iPOPO waiting list service :raise BundleException: Service not found """ # Get the service and its reference ref = bundle_context.get_service_reference(SERVICE_IPOPO_WAITING_LIST) if ref is None: raise BundleException("No iPOPO waiting list service available") try: # Give the service yield bundle_context.get_service(ref) finally: try: # Release it bundle_context.unget_service(ref) except BundleException: # Service might have already been unregistered pass
def use_ipopo(bundle_context): """ Utility context to use the iPOPO service safely in a "with" block. It looks after the the iPOPO service and releases its reference when exiting the context. :param bundle_context: The calling bundle context :return: The iPOPO service :raise BundleException: Service not found """ # Get the service and its reference ref_svc = get_ipopo_svc_ref(bundle_context) if ref_svc is None: raise BundleException("No iPOPO service available") try: # Give the service yield ref_svc[1] finally: try: # Release it bundle_context.unget_service(ref_svc[0]) except BundleException: # Service might have already been unregistered pass
def __init__(self, bundle, properties): """ Sets up the service reference :param bundle: The bundle registering the service :param properties: The service properties :raise BundleException: The properties doesn't contain mandatory entries """ # Check properties for mandatory in (SERVICE_ID, OBJECTCLASS): if mandatory not in properties: raise BundleException( "A Service must at least have a '{0}' entry".format( mandatory)) # Properties lock (used by ServiceRegistration too) self._props_lock = threading.RLock() # Usage lock self.__usage_lock = threading.Lock() # Service details self.__bundle = bundle self.__properties = properties self.__service_id = properties[SERVICE_ID] # Bundle object -> Usage Counter object self.__using_bundles = {} # Compute the sort key self.__sort_key = None self.update_sort_key()
def find_service_references(self, clazz=None, ldap_filter=None, only_one=False): """ Finds all services references matching the given filter. :param clazz: Class implemented by the service :param ldap_filter: Service filter :param only_one: Return the first matching service reference only :return: A list of found references, or None :raise BundleException: An error occurred looking for service references """ with self.__svc_lock: if clazz is None and ldap_filter is None: # Return a sorted copy of the keys list # Do not return None, as the whole content was required return sorted(self.__svc_registry.keys()) if hasattr(clazz, '__name__'): # Escape the type name clazz = ldapfilter.escape_LDAP(clazz.__name__) elif is_string(clazz): # Escape the class name clazz = ldapfilter.escape_LDAP(clazz) if clazz is None: # Directly use the given filter refs_set = sorted(self.__svc_registry.keys()) else: try: # Only for references with the given specification refs_set = iter(self.__svc_specs[clazz]) except KeyError: # No matching specification return None # Parse the filter try: new_filter = ldapfilter.get_ldap_filter(ldap_filter) except ValueError as ex: raise BundleException(ex) if new_filter is not None: # Prepare a generator, as we might not need a complete # walk-through refs_set = (ref for ref in refs_set if new_filter.matches(ref.get_properties())) if only_one: # Return the first element in the list/generator try: return next(refs_set) except StopIteration: # No match return None # Get all the matching references return list(refs_set) or None
def __sort_registry(self, svc_ref): """ Sorts the registry, after the update of the sort key of given service reference :param svc_ref: A service reference with a modified sort key """ with self.__svc_lock: if svc_ref not in self.__svc_registry: raise BundleException("Unknown service: {0}".format(svc_ref)) # Remove current references for spec in svc_ref.get_property(OBJECTCLASS): # Use bisect to remove the reference (faster) spec_refs = self.__svc_specs[spec] idx = bisect.bisect_left(spec_refs, svc_ref) del spec_refs[idx] # ... use the new sort key svc_ref.update_sort_key() for spec in svc_ref.get_property(OBJECTCLASS): # ... and insert it again spec_refs = self.__svc_specs[spec] bisect.insort_left(spec_refs, svc_ref)
def get_service(self, bundle, reference): """ Retrieves the service corresponding to the given reference :param bundle: The bundle requiring the service :param reference: A service reference :return: The requested service :raise BundleException: The service could not be found """ with self.__svc_lock: # Be sure to have the instance try: service = self.__svc_registry[reference] # Indicate the dependency imports = self.__bundle_imports.setdefault(bundle, []) bisect.insort(imports, reference) reference.used_by(bundle) return service except KeyError: # Not found raise BundleException( "Service not found (reference: {0})".format(reference))
def unregister(self, svc_ref): """ Unregisters a service :param svc_ref: A service reference :return: The unregistered service instance :raise BundleException: Unknown service reference """ with self.__svc_lock: if svc_ref not in self.__svc_registry: raise BundleException("Unknown service: {0}".format(svc_ref)) # Get the owner bundle = self.__svc_bundle.pop(svc_ref) # Get the service instance service = self.__svc_registry.pop(svc_ref) for spec in svc_ref.get_property(OBJECTCLASS): spec_services = self.__svc_specs[spec] # Use bisect to remove the reference (faster) idx = bisect.bisect_left(spec_services, svc_ref) del spec_services[idx] if len(spec_services) == 0: del self.__svc_specs[spec] # Delete bundle association bundle_services = self.__bundle_svc[bundle] idx = bisect.bisect_left(bundle_services, svc_ref) del bundle_services[idx] if len(bundle_services) == 0: # Don't keep empty lists del self.__bundle_svc[bundle] return service
def __get_service_from_factory(self, bundle, reference): # type: (Any, ServiceReference) -> Any """ Returns a service instance from a service factory or a prototype service factory :param bundle: The bundle requiring the service :param reference: A reference pointing to a factory :return: The requested service :raise BundleException: The service could not be found """ try: factory, svc_reg = self.__svc_factories[reference] # Indicate the dependency imports = self.__bundle_imports.setdefault(bundle, {}) if reference not in imports: # New reference usage: store a single usage # The Factory counter will handle the rest usage_counter = _UsageCounter() usage_counter.inc() imports[reference] = usage_counter reference.used_by(bundle) # Check the per-bundle usage counter factory_counter = self.__factory_usage.setdefault( bundle, _FactoryCounter(bundle)) return factory_counter.get_service(factory, svc_reg) except KeyError: # Not found raise BundleException( "Service not found (reference: {0})".format(reference))
def get_service(self, bundle, reference): # type: (Any, ServiceReference) -> Any """ Retrieves the service corresponding to the given reference :param bundle: The bundle requiring the service :param reference: A service reference :return: The requested service :raise BundleException: The service could not be found """ with self.__svc_lock: if reference.is_factory(): return self.__get_service_from_factory(bundle, reference) # Be sure to have the instance try: service = self.__svc_registry[reference] # Indicate the dependency imports = self.__bundle_imports.setdefault(bundle, {}) imports.setdefault(reference, _UsageCounter()).inc() reference.used_by(bundle) return service except KeyError: # Not found raise BundleException( "Service not found (reference: {0})".format(reference))
def unregister(self, svc_ref): # type: (ServiceReference) -> Any """ Unregisters a service :param svc_ref: A service reference :return: The unregistered service instance :raise BundleException: Unknown service reference """ with self.__svc_lock: try: # Try in pending services return self.__pending_services.pop(svc_ref) except KeyError: # Not pending: continue pass if svc_ref not in self.__svc_registry: raise BundleException("Unknown service: {0}".format(svc_ref)) # Get the owner bundle = svc_ref.get_bundle() # Get the service instance service = self.__svc_registry.pop(svc_ref) for spec in svc_ref.get_property(OBJECTCLASS): spec_services = self.__svc_specs[spec] # Use bisect to remove the reference (faster) idx = bisect.bisect_left(spec_services, svc_ref) del spec_services[idx] if not spec_services: del self.__svc_specs[spec] # Remove the service factory if svc_ref.is_factory(): # Call unget_service for all client bundle factory, svc_reg = self.__svc_factories.pop(svc_ref) for counter in self.__factory_usage.values(): counter.cleanup_service(factory, svc_reg) else: # Delete bundle association bundle_services = self.__bundle_svc[bundle] bundle_services.remove(svc_ref) if not bundle_services: # Don't keep empty lists del self.__bundle_svc[bundle] return service
def add_bundle_listener(self, listener): """ Adds a bundle listener :param listener: The bundle listener to register :return: True if the listener has been registered, False if it was already known :raise BundleException: An invalid listener has been given """ if listener is None or not hasattr(listener, 'bundle_changed'): raise BundleException("Invalid bundle listener given") with self.__bnd_lock: if listener in self.__bnd_listeners: self._logger.warning("Already known bundle listener '%s'", listener) return False self.__bnd_listeners.append(listener) return True
def unregister(self, svc_ref): """ Unregisters a service :param svc_ref: A service reference :return: The unregistered service instance :raise BundleException: Unknown service reference """ with self.__svc_lock: try: # Try in pending services return self.__pending_services.pop(svc_ref) except KeyError: # Not pending: continue pass if svc_ref not in self.__svc_registry: raise BundleException("Unknown service: {0}".format(svc_ref)) # Get the owner bundle = svc_ref.get_bundle() # Get the service instance service = self.__svc_registry.pop(svc_ref) for spec in svc_ref.get_property(OBJECTCLASS): spec_services = self.__svc_specs[spec] # Use bisect to remove the reference (faster) idx = bisect.bisect_left(spec_services, svc_ref) del spec_services[idx] if not spec_services: del self.__svc_specs[spec] # Delete bundle association bundle_services = self.__bundle_svc[bundle] bundle_services.remove(svc_ref) if not bundle_services: # Don't keep empty lists del self.__bundle_svc[bundle] return service
def add_framework_listener(self, listener): """ Registers a listener that will be called back right before the framework stops. :param listener: The framework stop listener :return: True if the listener has been registered, False if it was already known :raise BundleException: An invalid listener has been given """ if listener is None or not hasattr(listener, 'framework_stopping'): raise BundleException("Invalid framework listener given") with self.__fw_lock: if listener in self.__fw_listeners: self._logger.warning("Already known framework listener '%s'", listener) return False self.__fw_listeners.append(listener) return True