package org.deephacks.confit.spi;
import com.google.common.collect.Lists;
import javax.enterprise.inject.CreationException;
import javax.enterprise.inject.spi.CDI;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.ServiceConfigurationError;
import java.util.concurrent.ConcurrentHashMap;
public abstract class LookupProvider {
protected final ConcurrentHashMap<Class<?>, Object> objectRegistry = new ConcurrentHashMap<>();
private static final ThreadLocal<String> RECURSION_SHORTCIRCUIT = new ThreadLocal<>();
/**
* Look up an object matching a given interface.
*
* @param clazz The type of the object we want to lookupPrefered.
* @return The object, if found, otherwise null.
*/
public abstract <T> T lookup(Class<T> clazz);
/**
* Look up a list of objects that match a given interface.
*
* @param clazz The type of the object we want to lookupPrefered.
* @return The object(s), if found, otherwise null.
*/
public abstract <T> Collection<T> lookupAll(Class<T> clazz);
/**
* ServiceLoaderLookup is responsible for handling standard java service loader lookup.
*/
static class ServiceLoaderLookup extends LookupProvider {
public ServiceLoaderLookup() {
}
public final <T> T lookup(Class<T> clazz) {
ClassLoader cl = Thread.currentThread().getContextClassLoader();
Iterator<T> iterator = java.util.ServiceLoader.load(clazz, cl).iterator();
while (iterator.hasNext()) {
try {
// return first provider found.
return iterator.next();
} catch (ServiceConfigurationError e) {
// treat lookup failures as if the implementation is unavailable
}
}
return null;
}
@Override
public <T> Collection<T> lookupAll(Class<T> clazz) {
ArrayList<T> found = new ArrayList<>();
ClassLoader cl = Thread.currentThread().getContextClassLoader();
Iterator<T> iterator = java.util.ServiceLoader.load(clazz, cl).iterator();
while (iterator.hasNext()) {
try {
found.add(iterator.next());
} catch (ServiceConfigurationError e) {
// treat lookup failures as if the implementation is unavailable
}
}
return found;
}
}
static class CdiLookup extends LookupProvider {
private final String CDI_CLASS = "javax.enterprise.inject.spi.CDI";
/** use CDI only if available on classpath */
private final boolean cdiEnabled;
public CdiLookup() {
Class<?> cls = null;
try {
ClassLoader cl = Thread.currentThread().getContextClassLoader();
cls = cl.loadClass(CDI_CLASS);
} catch (Exception e) {
// ignore
}
cdiEnabled = cls != null;
}
public final <T> T lookup(Class<T> clazz) {
if (!cdiEnabled) {
return null;
}
try {
// lookup first instance found
return CDI.current().select(clazz).get();
} catch (Exception e) {
if (e instanceof CreationException) {
throw e;
}
// may fail if CDI was not setup correctly
// which is acceptable so return nothing..
// fix: new Weld().initialize() at bootstrap
return null;
}
}
@Override
public <T> Collection<T> lookupAll(Class<T> clazz) {
if (!cdiEnabled) {
return Lists.newArrayList();
}
// return all instances found
try {
if (clazz.getName().equals(RECURSION_SHORTCIRCUIT.get())) {
return new ArrayList<>();
} else {
RECURSION_SHORTCIRCUIT.set(clazz.getName());
return Lists.newArrayList(CDI.current().select(clazz));
}
} catch (Exception e) {
if (e instanceof CreationException) {
throw e;
}
// may fail if CDI was not setup correctly
// which is acceptable so return nothing..
// fix: new Weld().initialize() at bootstrap
return new ArrayList<>();
} finally {
RECURSION_SHORTCIRCUIT.remove();
}
}
}
}