Class ServiceFactory
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 and automatic modules, come last (unless the service is annotated withClasspathFirst, seeModuleSorter).
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/org.tentackle.common.ServiceFactory on the classpath or, in modular mode,
via a provides org.tentackle.common.ServiceFactory with ... clause in module-info
(ServiceLoader ignores META-INF/services within named modules).
Alternatively, see setFactoryClassname(String).
If no such configuration is found, an instance of ServiceFactory is used,
i.e., the fallback and default implementation is ServiceFactory itself.
- Author:
- harald
-
Constructor Summary
Constructors -
Method Summary
Modifier and TypeMethodDescriptionstatic voidaddExplicitClassLoader(String servicePath, String serviceName, ClassLoader classLoader) Adds an explicit classloader for a given service path and name.
Loaders are kept in a list for each path and name combination, the most recently added first.protected voidaddExplicitClassLoaderImpl(String servicePath, String serviceName, ClassLoader classLoader) Adds an explicit classloader for a given service path and name.
Loaders are kept in a list for each path and name combination, the most recently added first.static voidapplyResourceIndex(ClassLoader classLoader, String indexName, boolean set) Applies 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/RESOURCE-INDEX.LIST".protected voidapplyResourceIndexImpl(ClassLoader classLoader, String indexName, boolean set) Applies 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/RESOURCE-INDEX.LIST".static <T> TcreateService(Class<T> serviceClass) Utility method to create a service instance.
This is the standard way to instantiate singletons.static <T> TcreateService(Class<T> serviceClass, Class<? extends T> defaultClass) Utility method to create a service instance with a default if not found.
Same ascreateService(Class, Class, boolean)with a warning logged if the default class is used.static <T> TcreateService(Class<T> serviceClass, Class<? extends T> defaultClass, boolean logDefault) Utility method to create a service instance with a default if not found.static <T> Class<T> createServiceClass(Class<T> serviceClass) Utility method to determine the provider class of a service.
Finds the first service implementation in module/classpath order (seeModuleSorter).protected ClassLoaderGets the default classloader.
The classloader to use is determined as follows: use the fixed classloader set bysetFixedClassLoader(java.lang.ClassLoader), if not null else tryThread.currentThread().getContextClassLoader()if the context classloader is null, use the classloader that loaded the service factorystatic ClassLoadergetClassLoader(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.protected ClassLoadergetClassLoaderImpl(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.static ClassLoadergetExplicitClassLoader(String servicePath, String serviceName) Gets the explicit classloader for a given service path and name.protected ClassLoadergetExplicitClassLoaderImpl(String servicePath, String serviceName) Gets the explicit classloader for a given service path and name.static ClassLoaderGets the classloader to load the service factory.static StringGets the classname of the service factory.Gets the finder map.
Allows applications to modify or add finders programmatically.
The map is thread-safe.Gets the fixed classloader.static ServiceFactoryGets the singleton.static ServiceFinderGets a service finder for the service path"META-INF/services/".
If the finder does not exist yet, it will be created.static ServiceFindergetServiceFinder(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.static ServiceFindergetServiceFinder(ModuleLayer layer, String servicePath) Gets a service finder looking up services within a module layer.
If the finder does not exist yet, it will be created.static ServiceFindergetServiceFinder(String servicePath) Gets a service finder for a given service path.
If the finder does not exist yet, it will be created.protected Class<? extends ServiceFinder> Gets the class of the service finder.protected ServiceFinderGets a service finder for the service path"META-INF/services/".
If the finder does not exist yet, it will be created.protected ServiceFindergetServiceFinderImpl(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.protected ServiceFindergetServiceFinderImpl(ModuleLayer layer, String servicePath) Gets a service finder looking up services within a module layer.
If the finder does not exist yet, it will be created.protected ServiceFindergetServiceFinderImpl(String servicePath) Gets a service finder for a given service path.
If the finder does not exist yet, it will be created.static voidremoveExplicitClassLoader(String servicePath, String serviceName, ClassLoader classLoader) Removes an explicit classloader for a given service path and name.
Loaders are kept in a list for each path and name combination, the most recently added first.protected voidremoveExplicitClassLoaderImpl(String servicePath, String serviceName, ClassLoader classLoader) Removes an explicit classloader for a given service path and name.
Loaders are kept in a list for each path and name combination, the most recently added first.static voidsetFactoryClassloader(ClassLoader factoryClassloader) Sets the classloader to load the service factory.static voidsetFactoryClassname(String factoryClassname) Sets the classname of the service factory.voidsetFixedClassLoader(ClassLoader classLoader) Sets the fixed classloader.
If set, it is used instead of the context classloader for all finders that are not created for an explicit classloader or module layer.
-
Constructor Details
-
ServiceFactory
public ServiceFactory()Creates the factory.
-
-
Method Details
-
setFactoryClassname
Sets the classname of the service factory.If this value is null, the
ServiceFactoryis loaded via theServiceLoader. However, if for whatever reason, the loader doesn't find the service configuration or cannot be used, the class defined byfactoryClassnamecan be instantiated. Applications must change this at a very early stage of startup, for example in the main-method.Notice that the singleton is created lazily on its first use. Setting the classname afterwards has no effect and is logged as a warning.
- Parameters:
factoryClassname- the classname
-
getFactoryClassname
Gets the classname of the service factory.- Returns:
- the classname, default is null
-
setFactoryClassloader
Sets the classloader to load the service factory.If this value is null, the
ServiceFactoryis loaded via a default classloader.Notice that the singleton is created lazily on its first use. Setting the classloader afterwards has no effect and is logged as a warning.
- Parameters:
factoryClassloader- the classloader
-
getFactoryClassloader
Gets the classloader to load the service factory.- Returns:
- the classloader, default is null
-
getInstance
Gets the singleton.The instance is created lazily on the first invocation, so that
setFactoryClassname(String)andsetFactoryClassloader(ClassLoader)are effective if applied before.- Returns:
- the singleton, never null
-
getServiceFinder
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, never nullservicePath- the service path prefix- Returns:
- the finder, never null
- Throws:
NullPointerException- if loader or servicePath is null
-
getServiceFinder
Gets a service finder looking up services within a module layer.
If the finder does not exist yet, it will be created.Unlike
getServiceFinder(ClassLoader, String), this always creates aDefaultServiceFinder, bypassing the pluggableService-replaced finder class. A replacedServiceFinderimplementation is never used for module layers.Layer-bound finders are cached separately from the classloader-based finders, even if the layer's classloader is the same (see
ServiceFinderKey).- Parameters:
layer- the module layerservicePath- the service path prefix- Returns:
- the finder, never null
-
getServiceFinder
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:- 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
- Parameters:
servicePath- the service path prefix- Returns:
- the finder, never null
- use the fixed classloader set by
-
getServiceFinder
Gets a service finder for the service path"META-INF/services/".
If the finder does not exist yet, it will be created. 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
- Returns:
- the finder, never null
- use the fixed classloader set by
-
createServiceClass
Utility method to determine the provider class of a service.
Finds the first service implementation in module/classpath order (seeModuleSorter).- Type Parameters:
T- the service type- Parameters:
serviceClass- the service class- Returns:
- the provider class of the service
- Throws:
TentackleRuntimeException- if no provider found or the provider does not implement the service
-
createService
Utility method to create a service instance.
This is the standard way to instantiate singletons. Finds the first service implementation in module/classpath order (seeModuleSorter) and invokes its no-arg constructor.- Type Parameters:
T- the service type- Parameters:
serviceClass- the service class- Returns:
- an instance of the service
- Throws:
TentackleRuntimeException- if no provider found or it could not be instantiated
-
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 classdefaultClass- the fallback class if no service found or could not be instantiated, null to rethrow the exceptionlogDefault- true if log warning with stacktrace if default implementation is used- Returns:
- an instance of the service
- Throws:
TentackleRuntimeException- if the service could not be created and the default class is null or could not be instantiated either
-
createService
Utility method to create a service instance with a default if not found.
Same ascreateService(Class, Class, boolean)with a warning logged if the default class is used.- Type Parameters:
T- the service type- Parameters:
serviceClass- the service classdefaultClass- the default class if no service found- Returns:
- an instance of the service
- Throws:
TentackleRuntimeException- if neither the service nor the default could be created
-
getClassLoader
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 pathserviceName- the service name- Returns:
- the classloader, never null
-
getExplicitClassLoader
Gets the explicit classloader for a given service path and name.- Parameters:
servicePath- the service pathserviceName- 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 list for each path and name combination, the most recently added first. Adding a classloader pushes it onto the list (moving it to the front, if already contained), removing it deletes it from the list, wherever it is located. Thus, removing the most recently added loader activates the previously added one, if any. This allows activation and deactivation as is used in OSGi, for example.- Parameters:
servicePath- the service pathserviceName- the service nameclassLoader- the classloader to add
-
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 list for each path and name combination, the most recently added first. Adding a classloader pushes it onto the list (moving it to the front, if already contained), removing it deletes it from the list, wherever it is located. Thus, removing the most recently added loader activates the previously added one, if any. This allows activation and deactivation as is used in OSGi, for example.- Parameters:
servicePath- the service pathserviceName- the service nameclassLoader- the classloader to remove
-
applyResourceIndex
Applies 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/RESOURCE-INDEX.LIST". It is a plain list of resource paths, one per line, such asMETA-INF/services/org.tentackle.common.ServiceFactory. Lines starting with#are ignored. For each entry, the given classloader is added as (or removed from) the explicit classloader for the service path and name (seeaddExplicitClassLoader(String, String, ClassLoader)). If the classloader finds more than one index resource, only the first is used.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 resourceindexName- the name of the index resourceset- true if set loaders, else remove loaders from the services index- Throws:
TentackleRuntimeException- if reading the index failed
-
getFixedClassLoader
Gets the fixed classloader.- Returns:
- the classloader, null if default
-
setFixedClassLoader
Sets the fixed classloader.
If set, it is used instead of the context classloader for all finders that are not created for an explicit classloader or module layer. Finders already created are not affected.- Parameters:
classLoader- the classloader, null if default
-
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
- Returns:
- the loader, never null
- use the fixed classloader set by
-
getClassLoaderImpl
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 pathserviceName- the service name- Returns:
- the classloader, never null
-
getExplicitClassLoaderImpl
Gets the explicit classloader for a given service path and name.- Parameters:
servicePath- the service pathserviceName- 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 list for each path and name combination, the most recently added first. Adding a classloader pushes it onto the list (moving it to the front, if already contained), removing it deletes it from the list, wherever it is located. Thus, removing the most recently added loader activates the previously added one, if any. This allows activation and deactivation as is used in OSGi, for example.- Parameters:
servicePath- the service pathserviceName- the service nameclassLoader- the classloader to add
-
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 list for each path and name combination, the most recently added first. Adding a classloader pushes it onto the list (moving it to the front, if already contained), removing it deletes it from the list, wherever it is located. Thus, removing the most recently added loader activates the previously added one, if any. This allows activation and deactivation as is used in OSGi, for example.- Parameters:
servicePath- the service pathserviceName- the service nameclassLoader- the classloader to remove
-
applyResourceIndexImpl
Applies 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/RESOURCE-INDEX.LIST". It is a plain list of resource paths, one per line, such asMETA-INF/services/org.tentackle.common.ServiceFactory. Lines starting with#are ignored. For each entry, the given classloader is added as (or removed from) the explicit classloader for the service path and name (seeaddExplicitClassLoader(String, String, ClassLoader)). If the classloader finds more than one index resource, only the first is used.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 resourceindexName- the name of the index resourceset- true if set loaders, else remove loaders from the services index- Throws:
TentackleRuntimeException- if reading the index failed
-
getFinderMap
Gets the finder map.
Allows applications to modify or add finders programmatically.
The map is thread-safe.- Returns:
- the finder map
-
getServiceFinderClass
Gets the class of the service finder.- Returns:
- the class of the service finder, never null
-
getServiceFinderImpl
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 classloaderservicePath- the service path prefix- Returns:
- the finder, never null
-
getServiceFinderImpl
Gets a service finder looking up services within a module layer.
If the finder does not exist yet, it will be created.- Parameters:
layer- the module layerservicePath- the service path prefix- Returns:
- the finder, never null
-
getServiceFinderImpl
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:- 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
- Parameters:
servicePath- the service path prefix- Returns:
- the finder, never null
- use the fixed classloader set by
-
getServiceFinderImpl
Gets a service finder for the service path"META-INF/services/".
If the finder does not exist yet, it will be created. The classloader is determined bygetClassLoader().- Returns:
- the finder, never null
-