package mil.nga.giat.geowave.core.store.spi; import java.util.Arrays; import java.util.Collections; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Set; import javax.imageio.spi.ServiceRegistry; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Compensate for VFSClassloader's failure to discovery SPI registered classes * (used by JBOSS and Accumulo). * * To Use: * * (1) Register class loaders: * * * (2) Look up SPI providers: * * final Iterator<FieldSerializationProviderSpi> serializationProviders = new * SPIServiceRegistry(FieldSerializationProviderSpi.class).load( * FieldSerializationProviderSpi.class); * * * */ public class SPIServiceRegistry extends ServiceRegistry { private static final Logger LOGGER = LoggerFactory.getLogger(SPIServiceRegistry.class); @SuppressWarnings("unchecked") public SPIServiceRegistry( Class<?> category ) { super( (Iterator) Arrays.asList( category).iterator()); } public SPIServiceRegistry( Iterator<Class<?>> categories ) { super( categories); } private static final Set<ClassLoader> ClassLoaders = Collections.synchronizedSet(new HashSet<ClassLoader>()); private final Set<ClassLoader> localClassLoaders = Collections.synchronizedSet(new HashSet<ClassLoader>()); public static void registerClassLoader( ClassLoader loader ) { ClassLoaders.add(loader); } public void registerLocalClassLoader( ClassLoader loader ) { localClassLoaders.add(loader); } public <T> Iterator<T> load( final Class<T> service ) { final Set<ClassLoader> checkset = new HashSet<ClassLoader>(); final Set<ClassLoader> clSet = getClassLoaders(); final Iterator<ClassLoader> loaderIt = clSet.iterator(); return new Iterator<T>() { Iterator<T> spiIT = null; @Override public boolean hasNext() { while ((spiIT == null || !spiIT.hasNext()) && (loaderIt.hasNext())) { final ClassLoader l = loaderIt.next(); if (checkset.contains(l)) continue; checkset.add(l); spiIT = (Iterator<T>) ServiceRegistry.lookupProviders( service, l); } return spiIT != null && spiIT.hasNext(); } @Override public T next() { return (T) spiIT.next(); } @Override public void remove() {} }; } /** * Returns all class loaders to be used for scanning plugins. The following * class loaders are always included in the search: * <p> * <ul> * <li>{@linkplain Class#getClassLoader This object class loader}</li> * <li>{@linkplain Thread#getContextClassLoader The thread context class * loader}</li> * <li>{@linkplain ClassLoader#getSystemClassLoader The system class loader} * </li> * </ul> * * Both locally registered (this instance) and globally registered * classloaders are included it the search. * * Redundancies and parent classloaders are removed where possible. Possible * error conditions include security exceptions. Security exceptions are not * logger UNLESS the set of searchable classloaders is empty. * * @return Classloaders to be used for scanning plugins. */ public final Set<ClassLoader> getClassLoaders() { final List<String> exceptions = new LinkedList<String>(); final Set<ClassLoader> loaders = new HashSet<ClassLoader>(); try { loaders.add(SPIServiceRegistry.class.getClassLoader()); } catch (SecurityException ex) { LOGGER.warn( "Unable to get the class loader", ex); exceptions.add("SPIServiceRegistry's class loader : " + ex.getLocalizedMessage()); } try { loaders.add(ClassLoader.getSystemClassLoader()); } catch (SecurityException ex) { LOGGER.warn( "Unable to get the system class loader", ex); exceptions.add("System class loader : " + ex.getLocalizedMessage()); } try { loaders.add(Thread.currentThread().getContextClassLoader()); } catch (SecurityException ex) { LOGGER.warn( "Unable to get the context class loader", ex); exceptions.add("Thread's class loader : " + ex.getLocalizedMessage()); } loaders.addAll(ClassLoaders); loaders.addAll(localClassLoaders); /** * Remove those loaders that are parents to other loaders. */ final ClassLoader[] loaderSet = loaders.toArray(new ClassLoader[loaders.size()]); for (int i = 0; i < loaderSet.length; i++) { ClassLoader parent = loaderSet[i].getParent(); try { while (parent != null) { loaders.remove(parent); parent = parent.getParent(); } } catch (SecurityException ex) { LOGGER.warn( "Unable to get the class loader", ex); exceptions.add(loaderSet[i].toString() + "'s parent class loader : " + ex.getLocalizedMessage()); } } if (loaders.isEmpty()) { LOGGER.warn("No class loaders available. Check security exceptions (logged next)."); for (String exString : exceptions) { LOGGER.warn(exString); } } return loaders; } }