package net.sf.openrocket.plugin;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.google.inject.AbstractModule;
import com.google.inject.multibindings.Multibinder;
/**
* Guice module definition that searches for plugins in a list of provided
* JAR files and registers each found plugin to the corresponding plugin interface.
*
* @author Sampo Niskanen <sampo.niskanen@iki.fi>
*/
public class PluginModule extends AbstractModule {
private Map<Class<?>, Multibinder<?>> binders = new HashMap<Class<?>, Multibinder<?>>();
private AnnotationFinder finder = new AnnotationFinderImpl();
@SuppressWarnings("unchecked")
@Override
protected void configure() {
List<Class<?>> classes = finder.findAnnotatedTypes(Plugin.class);
List<Class<?>> interfaces = new ArrayList<Class<?>>();
List<Class<?>> unusedInterfaces;
// Find plugin interfaces
for (Class<?> c : classes) {
if (c.isInterface()) {
interfaces.add(c);
}
}
unusedInterfaces = new ArrayList<Class<?>>(interfaces);
// Find plugin implementations
for (Class<?> c : classes) {
if (c.isInterface())
continue;
for (Class<?> intf : interfaces) {
if (intf.isAssignableFrom(c)) {
// Ugly hack to enable dynamic binding... Can this be done type-safely?
Multibinder<Object> binder = (Multibinder<Object>) findBinder(intf);
binder.addBinding().to(c);
unusedInterfaces.remove(intf);
}
}
}
// TODO: Unused plugin interfaces should be bound to an empty set - how?
}
private Multibinder<?> findBinder(Class<?> intf) {
Multibinder<?> binder = binders.get(intf);
if (binder == null) {
binder = Multibinder.newSetBinder(binder(), intf);
binders.put(intf, binder);
}
return binder;
}
}