package net.frontlinesms.resources;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import org.apache.log4j.Logger;
import net.frontlinesms.FrontlineUtils;
/**
* Identifies concrete implementations of an interface or abstract class, and loads them.
* @author Alex
*
* @param <E>
*/
public abstract class ImplementationLoader<E> {
private Logger log = FrontlineUtils.getLogger(getClass());
protected abstract Class<E> getEntityClass();
protected abstract Comparator<? super Class<? extends E>> getSorter();
public List<Class<? extends E>> getAll() {
ArrayList<Class<? extends E>> entityClasses = new ArrayList<Class<? extends E>>(loadClasses());
Collections.sort(entityClasses, getSorter());
return entityClasses;
}
@SuppressWarnings("unchecked")
protected Set<Class<? extends E>> loadClasses() {
Set<Class<? extends E>> providers = new HashSet<Class<? extends E>>();
for(String name : getNames()) {
try {
providers.add((Class<? extends E>) Class.forName(name));
} catch(Exception ex) {
log.warn("Could not load " + name + " for " + getEntityClass().getName(), ex);
}
}
return providers;
}
private Set<String> getNames() {
Enumeration<URL> resources;
String resourceLocation = "META-INF/frontlinesms/" + getEntityClass().getSimpleName() + "s";
try {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
resources = classLoader.getResources(resourceLocation);
} catch (IOException e) {
log.warn("Resource(s) not found at " + resourceLocation, e);
return Collections.emptySet();
}
HashSet<String> names = new HashSet<String>();
for(URL resourceUrl : new IterableEnumeration<URL>(resources)) {
names.addAll(ResourceUtils.getUsefulLines(resourceUrl));
}
return names;
}
}
class IterableEnumeration<E> implements Iterable<E> {
private final Enumeration<E> e;
public IterableEnumeration(Enumeration<E> e) {
this.e = e;
}
public Iterator<E> iterator() {
return new Iterator<E>() {
public boolean hasNext() {
return e.hasMoreElements();
}
public E next() {
return e.nextElement();
}
public void remove() {
throw new IllegalStateException();
}
};
}
}