Ejemplo n.º 1
0
    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
Ejemplo n.º 2
0
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
Ejemplo n.º 3
0
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
Ejemplo n.º 4
0
    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()
Ejemplo n.º 5
0
    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
Ejemplo n.º 6
0
    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)
Ejemplo n.º 7
0
    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))
Ejemplo n.º 8
0
    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
Ejemplo n.º 9
0
    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))
Ejemplo n.º 10
0
    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))
Ejemplo n.º 11
0
    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
Ejemplo n.º 12
0
    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
Ejemplo n.º 13
0
    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
Ejemplo n.º 14
0
    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