Source code for AutoArchive._infrastructure.service._service_accessor
# _service_accessor.py
#
# Project: AutoArchive
# License: GNU GPLv3
#
# Copyright (C) 2003 - 2014 Róbert Čerňanský
""":class:`ServiceAccessor`."""
# {{{ CLASSES
# SMELL: Application layer can register. Factor the registration out to a separate class?.
[docs]class ServiceAccessor:
"""Access to services.
A service can be made available by registering via this interface. Registered classes has to implement
:class:`.IService`."""
def __init__(self):
# key is :class:`IServiceIdentification`, value is list of tuples (service provider class,
# service provider identification)
self.__services = {}
# key is service provider class, value is its instance
self.__serviceInstances = {}
[docs] def getOrCreateService(self, serviceIdentification, providerIdentification, *args):
"""Provides access to registered services interfaces.
See also: :meth:`registerInterface`.
:param serviceIdentification: Identification of the service that shall be created.
:type serviceIdentification: :class:`.IServiceIdentification`
:param providerIdentification: Corresponding service provider identification object. It should be one of the
instances returned by :meth:`getProvidersIdentifications`. For services with a single provider
(implementation) it can be ``None``.
:type providerIdentification: ``serviceIdentification.providerIdentificationInterface``
:param args: Service specific arguments.
:return: Instance of a service provider of the particular service.
:rtype: ``serviceIdentification.interface``
:raise KeyError: If ``serviceIdentification`` is not registered."""
providers = self.__findProviders(serviceIdentification)
if len(self.__filterProvidersByIdentification(providers, providerIdentification)) == 0:
raise KeyError(
str.format("Service {} is not registered with service provider {}.", serviceIdentification,
providerIdentification))
providerClass = self.__findProviderClass(providers, providerIdentification)
if providerClass in self.__serviceInstances:
serviceInstance = self.__serviceInstances[providerClass]
else:
serviceInstance = providerClass(*args)
self.__serviceInstances[providerClass] = serviceInstance
return serviceInstance
[docs] def getProvidersIdentifications(self, serviceIdentification):
"""Returns providers identifications for the given service.
:param serviceIdentification: Identification of the service.
:type serviceIdentification: :class:`.IServiceIdentification`
:return: Service providers.
:rtype: ``iterable<serviceIdentification.providerIdentificationInterface>``
:raise KeyError: If ``serviceIdentification`` is not registered."""
return (p[1] for p in self.__findProviders(serviceIdentification))
[docs] def registerService(self, serviceIdentification, providerClass, providerIdentification = None):
"""Registers a service.
See also: :meth:`unregisterService`, :meth:`getOrCreateService`.
:param serviceIdentification: Identification of the service that shall be registered.
:type serviceIdentification: :class:`.IServiceIdentification`
:param providerClass: Provider of the service.
:type providerClass: ``type{`` ``serviceIdentification.interface``, :class:`IService`\ ``}``
:param providerIdentification: Corresponding service provider identification object.
:type providerIdentification: ``serviceIdentification.providerIdentificationInterface``
:raise TypeError: If ``providerClass`` does not implement ``serviceIdentification.interface``. If
``providerIdentification`` does not implement ``serviceIdentification.providerIdentificationInterface``.
:raise KeyError: If ``serviceIdentification`` is already registered with ``providerClass`` or
``providerIdentification``."""
if not issubclass(providerClass, serviceIdentification.interface):
raise TypeError("providerClass")
if providerIdentification is not None and not isinstance(
providerIdentification, serviceIdentification.providerIdentificationInterface):
raise TypeError("serviceProviderInfo")
providers = self.__tryFindProviders(serviceIdentification)
if providers is None:
providers = []
self.__services[serviceIdentification] = providers
if len(self.__filterProvidersByIdentification(providers, providerIdentification)) > 0:
raise KeyError(
str.format("Service {} is already registered with service provider info {}.", serviceIdentification,
providerIdentification))
if len(self.__filterProvidersByClass(providers, providerClass)) > 0:
raise KeyError(
str.format("Service {} is already registered with service provider class {}.", serviceIdentification,
providerClass))
self.__services[serviceIdentification].append((providerClass, providerIdentification))
[docs] def unregisterService(self, serviceIdentification):
"""Unregisters a service with all its providers.
All serviceType instances all destroyed first.
See also: :meth:`registerService`, :meth:`getOrCreateService`.
:param serviceIdentification: Identification of the service that shall be registered.
:type serviceIdentification: :class:`.IServiceIdentification`
:raise KeyError: If ``serviceIdentification`` is not registered."""
self.__destroyServiceInstances(serviceIdentification)
del self.__services[self.__findService(serviceIdentification)]
def __destroyServiceInstances(self, serviceIdentification):
"Destroys service instances if any."
providers = self.__findProviders(serviceIdentification)
for provider in providers:
if provider[0] in self.__serviceInstances:
del self.__serviceInstances[provider[0]]
def __findProviders(self, serviceIdentification):
return self.__services[self.__findService(serviceIdentification)]
def __tryFindProviders(self, serviceIdentification):
if serviceIdentification not in self.__services:
return None
return self.__services[serviceIdentification]
def __findService(self, serviceIdentification):
if serviceIdentification not in self.__services:
raise KeyError(str.format("Service {} is not registered", serviceIdentification))
return serviceIdentification
@classmethod
def __findProviderClass(cls, providers, providerIdentification):
provider = cls.__filterProvidersByIdentification(providers, providerIdentification)[0]
return provider[0]
@staticmethod
def __filterProvidersByIdentification(providers, providerIdentification):
return [p for p in providers if p[1] == providerIdentification]
@staticmethod
def __filterProvidersByClass(providers, providerClass):
return [p for p in providers if p[0] == providerClass]