xpertss.ds.utils.ServiceLoader Maven / Gradle / Ivy
package xpertss.ds.utils;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
public class ServiceLoader implements Iterable {
private static final String PREFIX = "META-INF/services/";
// The class or interface representing the service being loaded
private Class service;
// The class loader used to locate, load, and instantiate providers
private ClassLoader loader;
// Cached providers, in instantiation order
private Set providers;
private ServiceLoader(Class svc, ClassLoader cl)
{
service = svc;
loader = cl;
reload();
}
/**
* Clear this loader's provider cache so that all providers will be reloaded.
*
*
* After invoking this method, subsequent invocations of the {@link #iterator() iterator} method will lazily look up
* and instantiate providers from scratch, just as is done by a newly-created loader.
*
*
* This method is intended for use in situations in which new providers can be installed into a running Java virtual
* machine.
*/
public void reload()
{
Set list = new LinkedHashSet();
String fullName = PREFIX + service.getName();
try {
Enumeration configs = loader.getResources(fullName);
Set> classes = new HashSet>();
while(configs.hasMoreElements()) {
try {
InputStream in = configs.nextElement().openStream();
try {
for(String clsName : parse(in)) {
try {
Class> clazz = loader.loadClass(clsName);
if(!classes.contains(clazz) && service.isAssignableFrom(clazz)) {
list.add(service.cast(clazz.newInstance()));
classes.add(clazz);
}
} catch(Exception e) { }
}
} finally {
if(in != null) in.close();
}
} catch(Exception iex) { }
}
} catch(Exception ex) { }
providers = Collections.unmodifiableSet(list);
}
private List parse(InputStream in)
throws IOException
{
List classes = new ArrayList();
BufferedReader br = new BufferedReader(new InputStreamReader(in, "utf-8"));
String line;
while((line = br.readLine()) != null) {
if(line.contains("#")) {
line = line.substring(0, line.indexOf("#")).trim();
}
if(line.length() > 0) classes.add(line);
}
return classes;
}
/**
* Iterates the available providers of this loader's service.
*
* The iterator returned by this method first yields all of the elements of the provider cache, in instantiation
* order. It then lazily loads and instantiates any remaining providers, adding each one to the cache in turn.
*
*
* The iterator returned by this method does not support removal. Invoking its {@link java.util.Iterator#remove()
* remove} method will cause an {@link UnsupportedOperationException} to be thrown.
*
* @return An iterator that lazily loads providers for this loader's service
*/
public Iterator iterator()
{
return providers.iterator();
}
/**
* Returns a string describing this service.
*
* @return A descriptive string
*/
public String toString()
{
return "ServiceLoader[" + service.getName() + "]";
}
/**
* Creates a new service loader for the given service type and class loader.
*
* @param service
* The interface or abstract class representing the service
*
* @param loader
* The class loader to be used to load provider-configuration files and provider classes, or null
* if the system class loader (or, failing that, the bootstrap class loader) is to be used
*
* @return A new service loader
*/
public static ServiceLoader load(Class service, ClassLoader loader)
{
if(loader == null) loader = ClassLoader.getSystemClassLoader();
return new ServiceLoader(service, loader);
}
/**
* Creates a new service loader for the given service type, using the current thread's
* {@linkplain java.lang.Thread#getContextClassLoader context class loader}.
*
*
* An invocation of this convenience method of the form
*
*
*
*
* ServiceLoader.load(service)
*
*
*
*
* is equivalent to
*
*
*
*
* ServiceLoader.load(service,
* Thread.currentThread().getContextClassLoader())
*
*
*
*
* @param service
* The interface or abstract class representing the service
*
* @return A new service loader
*/
public static ServiceLoader load(Class service)
{
ClassLoader cl = Thread.currentThread().getContextClassLoader();
return ServiceLoader.load(service, cl);
}
}