Class ServiceFactory

java.lang.Object
org.tentackle.common.ServiceFactory

@Service(ServiceFactory.class) 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 Details

    • INSTANCE

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

    • ServiceFactory

      public ServiceFactory()
      Creates the factory.
  • Method Details

    • 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 factory.

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

      Parameters:
      factoryClassloader - the classloader
    • getFactoryClassloader

      public static ClassLoader getFactoryClassloader()
      Gets the classloader to load the service factory.
      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 fallback class if no service found or could not be instantiated
      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 explicit 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)
      Removes an explicit 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 explicit 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)
      Removes an explicit 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