Class ServiceFactory


  • public class ServiceFactory
    extends java.lang.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 Summary

      Fields 
      Modifier and Type Field Description
      static ServiceFactory INSTANCE
      the singleton instance.
    • Constructor Summary

      Constructors 
      Constructor Description
      ServiceFactory()
      Creates the factory.
    • Method Summary

      All Methods Static Methods Instance Methods Concrete Methods 
      Modifier and Type Method Description
      static void addExplicitClassLoader​(java.lang.String servicePath, java.lang.String serviceName, java.lang.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.
      protected void addExplicitClassLoaderImpl​(java.lang.String servicePath, java.lang.String serviceName, java.lang.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.
      static void applyResourceIndex​(java.lang.ClassLoader classLoader, java.lang.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".
      protected void applyResourceIndexImpl​(java.lang.ClassLoader classLoader, java.lang.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".
      static <T> T createService​(java.lang.Class<T> serviceClass)
      Utility method to create a service instance.
      This is the standard way to instantiate singletons.
      static <T> T createService​(java.lang.Class<T> serviceClass, java.lang.Class<? extends T> defaultClass)
      Utility method to create a service instance with a default if not found.
      static <T> T createService​(java.lang.Class<T> serviceClass, java.lang.Class<? extends T> defaultClass, boolean logDefault)
      Utility method to create a service instance with a default if not found.
      static <T> java.lang.Class<T> createServiceClass​(java.lang.Class<T> serviceClass)
      Utility method to create a service instance.
      This is the standard way to instantiate singletons.
      protected java.lang.ClassLoader getClassLoader()
      Gets the default classloader.
      The classloader to use is determined as follows: use the fixed classloader set by setFixedClassLoader(java.lang.ClassLoader), if not null else try Thread.currentThread().getContextClassLoader() if the context classloader is null, use the classloader that loaded the service factory
      static java.lang.ClassLoader getClassLoader​(java.lang.String servicePath, java.lang.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.
      protected java.lang.ClassLoader getClassLoaderImpl​(java.lang.String servicePath, java.lang.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.
      static java.lang.ClassLoader getExplicitClassLoader​(java.lang.String servicePath, java.lang.String serviceName)
      Gets the explicit classloader for a given service path and name.
      protected java.lang.ClassLoader getExplicitClassLoaderImpl​(java.lang.String servicePath, java.lang.String serviceName)
      Gets the explicit classloader for a given service path and name.
      static java.lang.ClassLoader getFactoryClassloader()
      Gets the classloader to load the service factorty.
      static java.lang.String getFactoryClassname()
      Gets the classname of the service factory.
      java.util.Map<ServiceFinderKey,​ServiceFinder> getFinderMap()
      Gets the finder map.
      Allows applications to modify or add finders programmatically.
      The map is threadsafe.
      java.lang.ClassLoader getFixedClassLoader()
      Gets the fixed classloader.
      static ServiceFinder getServiceFinder()
      Gets a service finder.
      If the finder does not exist yet, it will be created.
      static ServiceFinder getServiceFinder​(java.lang.ClassLoader loader, java.lang.String servicePath)
      Gets a service finder for a given classloader and service path.
      If the finder does not exist yet, it will be created.
      static ServiceFinder getServiceFinder​(java.lang.String servicePath)
      Gets a service finder for a given service path.
      If the finder does not exist yet, it will be created.
      protected java.lang.Class<? extends ServiceFinder> getServiceFinderClass()
      Gets the class of the service finder.
      protected ServiceFinder getServiceFinderImpl()
      Gets a service finder.
      If the finder does not exist yet, it will be created.
      protected ServiceFinder getServiceFinderImpl​(java.lang.ClassLoader loader, java.lang.String servicePath)
      Gets a service finder for a given classloader and service path.
      If the finder does not exist yet, it will be created.
      protected ServiceFinder getServiceFinderImpl​(java.lang.String servicePath)
      Gets a service finder for a given service path.
      If the finder does not exist yet, it will be created.
      static void removeExplicitClassLoader​(java.lang.String servicePath, java.lang.String serviceName, java.lang.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.
      protected void removeExplicitClassLoaderImpl​(java.lang.String servicePath, java.lang.String serviceName, java.lang.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.
      static void setFactoryClassloader​(java.lang.ClassLoader factoryClassloader)
      Sets the classloader to load the service factorty.
      static void setFactoryClassname​(java.lang.String factoryClassname)
      Sets the classname of the service factory.
      void setFixedClassLoader​(java.lang.ClassLoader classLoader)
      Sets the fixed classloader.
      Default is Thread.currentThread().getContextClassLoader().
      • Methods inherited from class java.lang.Object

        clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
    • 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​(java.lang.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 java.lang.String getFactoryClassname()
        Gets the classname of the service factory.
        Returns:
        the classname, default is null
      • setFactoryClassloader

        public static void setFactoryClassloader​(java.lang.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 java.lang.ClassLoader getFactoryClassloader()
        Gets the classloader to load the service factorty.
        Returns:
        the classloader, default is null
      • getServiceFinder

        public static ServiceFinder getServiceFinder​(java.lang.ClassLoader loader,
                                                     java.lang.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​(java.lang.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> java.lang.Class<T> createServiceClass​(java.lang.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​(java.lang.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​(java.lang.Class<T> serviceClass,
                                          java.lang.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​(java.lang.Class<T> serviceClass,
                                          java.lang.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 java.lang.ClassLoader getClassLoader​(java.lang.String servicePath,
                                                           java.lang.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 java.lang.ClassLoader getExplicitClassLoader​(java.lang.String servicePath,
                                                                   java.lang.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​(java.lang.String servicePath,
                                                  java.lang.String serviceName,
                                                  java.lang.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​(java.lang.String servicePath,
                                                     java.lang.String serviceName,
                                                     java.lang.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​(java.lang.ClassLoader classLoader,
                                              java.lang.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 java.lang.ClassLoader getFixedClassLoader()
        Gets the fixed classloader.
        Returns:
        the classloader, null if default
      • setFixedClassLoader

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

        protected java.lang.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 java.lang.ClassLoader getClassLoaderImpl​(java.lang.String servicePath,
                                                           java.lang.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 java.lang.ClassLoader getExplicitClassLoaderImpl​(java.lang.String servicePath,
                                                                   java.lang.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​(java.lang.String servicePath,
                                                  java.lang.String serviceName,
                                                  java.lang.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​(java.lang.String servicePath,
                                                     java.lang.String serviceName,
                                                     java.lang.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​(java.lang.ClassLoader classLoader,
                                              java.lang.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 java.util.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 java.lang.Class<? extends ServiceFinder> getServiceFinderClass()
        Gets the class of the service finder.
        Returns:
        the class of the service finder, never null
      • getServiceFinderImpl

        protected ServiceFinder getServiceFinderImpl​(java.lang.ClassLoader loader,
                                                     java.lang.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​(java.lang.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