Class ServiceFactory


  • public class ServiceFactory
    extends Object
    Factory for services based on ServiceFinder.

    A replacement for ServiceLoader providing the following additional features:

    • Not limited to load classes. Can load any kind of configuration.
    • Supports different service types. Each type gets its own directory in META-INF.
    • Each service (type + name) may have its own classloader. Useful for OSGi.
    • Works for modular (jigsaw) and non-modular applications.
    • As opposed to ServiceLoader, ServiceFinders retain the module dependency order for service URLs. The first URL is guaranteed to belong to the topmost relevant module. Unnamed, i.e. classpath comes last.
    Application modules must include an implementation of ModuleHook and a provides-clause in module-info. Example:
      provides org.tentackle.common.ModuleHook with com.myapp.somepackage.Hook;
     

    The factory itself is loaded via the standard JDK ServiceLoader and can be replaced via META-INF/services. If no such configuration is found, an instance of ServiceFactory is used, i.e. the fallback and default implementation is ServiceFactory itself. However, applications can replace it, if necessary.

    Author:
    harald
    • Field Detail

      • INSTANCE

        public static final ServiceFactory INSTANCE
        the singleton instance.
    • Constructor Detail

      • ServiceFactory

        public ServiceFactory()
        Creates the factory.
    • Method Detail

      • setFactoryClassname

        public static void setFactoryClassname​(String factoryClassname)
        Sets the classname of the service factory.

        If this value is null, the ServiceFactory is loaded via the ServiceLoader. However, if for whatever reason, the loader doesn't find the service configuration or cannot be used, the class defined by factoryClassname can be instantiated. Applications must change this at a very early stage of startup, for example in the main-method.

        Parameters:
        factoryClassname - the classname
      • getFactoryClassname

        public static String getFactoryClassname()
        Gets the classname of the service factory.
        Returns:
        the classname, default is null
      • setFactoryClassloader

        public static void setFactoryClassloader​(ClassLoader factoryClassloader)
        Sets the classloader to load the service factorty.

        If this value is null, the the ServiceFactory is loaded via a default classloader.

        Parameters:
        factoryClassloader - the classloader
      • getFactoryClassloader

        public static ClassLoader getFactoryClassloader()
        Gets the classloader to load the service factorty.
        Returns:
        the classloader, default is null
      • getServiceFinder

        public static ServiceFinder getServiceFinder​(ClassLoader loader,
                                                     String servicePath)
        Gets a service finder for a given classloader and service path.
        If the finder does not exist yet, it will be created.
        Parameters:
        loader - the classloader
        servicePath - the service path prefix
        Returns:
        the finder
      • getServiceFinder

        public static ServiceFinder getServiceFinder​(String servicePath)
        Gets a service finder for a given service path.
        If the finder does not exist yet, it will be created. The classloader used is Thread.currentThread().getContextClassLoader().
        Parameters:
        servicePath - the service path prefix
        Returns:
        the finder, never null
      • getServiceFinder

        public static ServiceFinder getServiceFinder()
        Gets a service finder.
        If the finder does not exist yet, it will be created. The classloader used is Thread.currentThread().getContextClassLoader() and the service path is "META_INF/services/".
        Returns:
        the finder
      • createServiceClass

        public static <T> Class<T> createServiceClass​(Class<T> serviceClass)
        Utility method to create a service instance.
        This is the standard way to instantiate singletons. Finds the first service implementation along the classpath.
        Type Parameters:
        T - the service type
        Parameters:
        serviceClass - the service class
        Returns:
        an instance of the service
      • createService

        public static <T> T createService​(Class<T> serviceClass)
        Utility method to create a service instance.
        This is the standard way to instantiate singletons. Finds the first service implementation along the classpath.
        Type Parameters:
        T - the service type
        Parameters:
        serviceClass - the service class
        Returns:
        an instance of the service
      • createService

        public static <T> T createService​(Class<T> serviceClass,
                                          Class<? extends T> defaultClass,
                                          boolean logDefault)
        Utility method to create a service instance with a default if not found.
        Type Parameters:
        T - the service type
        Parameters:
        serviceClass - the service class
        defaultClass - the default class if no service found
        logDefault - true if log warning with stacktrace if default implementation is used
        Returns:
        an instance of the service
      • createService

        public static <T> T createService​(Class<T> serviceClass,
                                          Class<? extends T> defaultClass)
        Utility method to create a service instance with a default if not found.
        Type Parameters:
        T - the service type
        Parameters:
        serviceClass - the service class
        defaultClass - the default class if no service found
        Returns:
        an instance of the service
      • getClassLoader

        public static ClassLoader getClassLoader​(String servicePath,
                                                 String serviceName)
        Gets the classloader for a given service path and name.
        If an explicit classloader is set, the last defined classloader for the given path and name is returned. Otherwise the default classloader is returned.
        Parameters:
        servicePath - the service path
        serviceName - the service name
        Returns:
        the classloader, never null
      • getExplicitClassLoader

        public static ClassLoader getExplicitClassLoader​(String servicePath,
                                                         String serviceName)
        Gets the explicit classloader for a given service path and name.
        Parameters:
        servicePath - the service path
        serviceName - the service name
        Returns:
        the classloader, null if no explicit classloader set
      • addExplicitClassLoader

        public static void addExplicitClassLoader​(String servicePath,
                                                  String serviceName,
                                                  ClassLoader classLoader)
        Adds an explict classloader for a given service path and name.
        Loaders are kept in a linked list for each path and name combination. Setting a classloader performs a push, clearing a pop. Thus, removing a loader activates the previously set loader, if any. This allows activation and deactivation as it used in OSGi, for example.
        Parameters:
        servicePath - the service path
        serviceName - the service name
        classLoader - the classloader, null if remove
      • removeExplicitClassLoader

        public static void removeExplicitClassLoader​(String servicePath,
                                                     String serviceName,
                                                     ClassLoader classLoader)
        Remove]s an explict classloader for a given service path and name.
        Loaders are kept in a linked list for each path and name combination. Setting a classloader performs a push, clearing a pop. Thus, removing a loader activates the previously set loader, if any. This allows activation and deactivation as it used in OSGi, for example.
        Parameters:
        servicePath - the service path
        serviceName - the service name
        classLoader - the classloader, null if remove
      • applyResourceIndex

        public static void applyResourceIndex​(ClassLoader classLoader,
                                              String indexName,
                                              boolean set)
        Apply a given resource index.
        The index is usually created via the tentackle-maven-plugin's analyze goal with the index option set to something like "META-INF/RESOURCES-INDEX.LIST".

        This is a utility method, that can be used during the activation within an OSGI-bundle, for example.

        Parameters:
        classLoader - the classloader to load the index resource
        indexName - the name of the index resource
        set - true if set loaders, else remove loaders from the services index
      • getFixedClassLoader

        public ClassLoader getFixedClassLoader()
        Gets the fixed classloader.
        Returns:
        the classloader, null if default
      • setFixedClassLoader

        public void setFixedClassLoader​(ClassLoader classLoader)
        Sets the fixed classloader.
        Default is Thread.currentThread().getContextClassLoader().
        Parameters:
        classLoader - the classloader, null if default
      • getClassLoader

        protected ClassLoader getClassLoader()
        Gets the default classloader.
        The classloader to use is determined as follows:
        1. use the fixed classloader set by setFixedClassLoader(java.lang.ClassLoader), if not null
        2. else try Thread.currentThread().getContextClassLoader()
        3. if the context classloader is null, use the classloader that loaded the service factory
        Returns:
        the loader, never null
      • getClassLoaderImpl

        protected ClassLoader getClassLoaderImpl​(String servicePath,
                                                 String serviceName)
        Gets the classloader for a given service path and name.
        If an explicit classloader is set, the last defined classloader for the given path and name is returned. Otherwise the default classloader is returned.
        Parameters:
        servicePath - the service path
        serviceName - the service name
        Returns:
        the classloader, never null
      • getExplicitClassLoaderImpl

        protected ClassLoader getExplicitClassLoaderImpl​(String servicePath,
                                                         String serviceName)
        Gets the explicit classloader for a given service path and name.
        Parameters:
        servicePath - the service path
        serviceName - the service name
        Returns:
        the classloader, null if no explicit classloader set
      • addExplicitClassLoaderImpl

        protected void addExplicitClassLoaderImpl​(String servicePath,
                                                  String serviceName,
                                                  ClassLoader classLoader)
        Adds an explict classloader for a given service path and name.
        Loaders are kept in a linked list for each path and name combination. Setting a classloader performs a push, clearing a pop. Thus, removing a loader activates the previously set loader, if any. This allows activation and deactivation as it used in OSGi, for example.
        Parameters:
        servicePath - the service path
        serviceName - the service name
        classLoader - the classloader, null if remove
      • removeExplicitClassLoaderImpl

        protected void removeExplicitClassLoaderImpl​(String servicePath,
                                                     String serviceName,
                                                     ClassLoader classLoader)
        Remove]s an explict classloader for a given service path and name.
        Loaders are kept in a linked list for each path and name combination. Setting a classloader performs a push, clearing a pop. Thus, removing a loader activates the previously set loader, if any. This allows activation and deactivation as it used in OSGi, for example.
        Parameters:
        servicePath - the service path
        serviceName - the service name
        classLoader - the classloader, null if remove
      • applyResourceIndexImpl

        protected void applyResourceIndexImpl​(ClassLoader classLoader,
                                              String indexName,
                                              boolean set)
        Apply a given resource index.
        The index is usually created via the tentackle-maven-plugin's analyze goal with the index option set to something like "META-INF/RESOURCES-INDEX.LIST".

        This is a utility method, that can be used during the activation within an OSGI-bundle, for example.

        Parameters:
        classLoader - the classloader to load the index resource
        indexName - the name of the index resource
        set - true if set loaders, else remove loaders from the services index
      • getFinderMap

        public Map<ServiceFinderKey,​ServiceFinder> getFinderMap()
        Gets the finder map.
        Allows applications to modify or add finders programmatically.
        The map is threadsafe.
        Returns:
        the finder map
      • getServiceFinderClass

        protected Class<? extends ServiceFinder> getServiceFinderClass()
        Gets the class of the service finder.
        Returns:
        the class of the service finder, never null
      • getServiceFinderImpl

        protected ServiceFinder getServiceFinderImpl​(ClassLoader loader,
                                                     String servicePath)
        Gets a service finder for a given classloader and service path.
        If the finder does not exist yet, it will be created.
        Parameters:
        loader - the classloader
        servicePath - the service path prefix
        Returns:
        the finder, never null
      • getServiceFinderImpl

        protected ServiceFinder getServiceFinderImpl​(String servicePath)
        Gets a service finder for a given service path.
        If the finder does not exist yet, it will be created. The classloader to use is determined as follows:
        1. use the fixed classloader set by setFixedClassLoader(java.lang.ClassLoader), if not null
        2. else try Thread.currentThread().getContextClassLoader()
        3. if the context classloader is null, use the classloader that loaded the service factory
        Parameters:
        servicePath - the service path prefix
        Returns:
        the finder, never null
      • getServiceFinderImpl

        protected ServiceFinder getServiceFinderImpl()
        Gets a service finder.
        If the finder does not exist yet, it will be created. The classloader used is Thread.currentThread().getContextClassLoader() and the service path is "META_INF/services/".
        Returns:
        the finder