org.daisy.common.spi.ServiceLoader Maven / Gradle / Ivy
package org.daisy.common.spi;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.NoSuchElementException;
import com.google.common.collect.AbstractIterator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ServiceLoader implements Iterable {
private static final Logger logger = LoggerFactory.getLogger(ServiceLoader.class);
private static final Map,ServiceLoader>> cache = new HashMap,ServiceLoader>>();
private static ClassLoader lastContextClassLoader = null;
public static ServiceLoader load(Class serviceType) {
ClassLoader ccl = Thread.currentThread().getContextClassLoader();
if (ccl != lastContextClassLoader) {
cache.clear();
Memoize.singletons.clear();
}
lastContextClassLoader = ccl;
ServiceLoader loader;
if (cache.containsKey(serviceType)) {
loader = (ServiceLoader)cache.get(serviceType);
} else {
loader = new ServiceLoader(serviceType);
cache.put(serviceType, loader);
}
return loader;
}
private Class serviceType;
private Iterable serviceLoader;
private ServiceLoader(Class serviceType) {
this.serviceType = serviceType;
}
public Iterator iterator() {
return new AbstractIterator() {
Iterator serviceIterator;
public S computeNext() {
if (serviceIterator == null) {
try {
if (serviceLoader == null) {
serviceLoader = memoize(java.util.ServiceLoader.load(serviceType));
}
serviceIterator = serviceLoader.iterator();
} catch (Throwable e) {
logger.error("Failed to instantiate services", e);
return endOfData();
}
}
while (serviceIterator.hasNext()) {
try {
return serviceIterator.next();
} catch (Throwable e) {
logger.error("Failed to instantiate service", e);
}
}
return endOfData();
}
};
}
/*
* No two Iterables returned by this function contain multiple instances of the same class
*/
private static Iterable memoize(final Iterable iterable) {
return new Memoize() {
protected Iterator _iterator() {
return iterable.iterator();
}
};
}
private static abstract class Memoize implements Iterable {
private static final Map,Object> singletons = new HashMap,Object>();
private final ArrayList list = new ArrayList();
protected abstract Iterator _iterator();
private Iterator _iterator;
public final Iterator iterator() {
return new Iterator() {
private int index = 0;
public boolean hasNext() {
synchronized(list) {
if (index < list.size())
return true;
if (_iterator == null)
_iterator = _iterator();
return _iterator.hasNext();
}
}
public S next() throws NoSuchElementException {
synchronized(list) {
if (index < list.size())
return list.get(index++);
if (_iterator == null)
_iterator = _iterator();
S next = _iterator.next();
synchronized(singletons) {
if (singletons.containsKey(next.getClass()))
next = (S)singletons.get(next.getClass());
else
singletons.put(next.getClass(), next);
}
list.add(next);
index++;
return next;
}
}
public void remove() {
throw new UnsupportedOperationException();
}
};
}
}
}