import java.util.HashMap;
import java.util.Map;

import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Inject;
import com.google.inject.Injector;
import com.google.inject.Module;


public class ModularityTest {
	
	public static void main (String... args) {
		PluginManager plugins = Guice.createInjector(new MainModule()).getInstance(PluginManager.class);
		plugins.install(new Extension1Module(), null);
		plugins.install(new Extension2Module(), "ext1");
	}
	
	public static class MainModule extends AbstractModule {
		@Override protected void configure() {
		    bind(PluginManager.class);
		}
	}
	
	public static class PluginManager {
		@Inject private Injector mainInjector;
		private Map<String, Injector> injectors = new HashMap<String, Injector>(); 
		public void install(Module module, String req) {
			Injector parentInjector = (req == null ? mainInjector : injectors.get(req));
			Injector childInjector = parentInjector.createChildInjector(module);
			Plugin plugin = childInjector.getInstance(Plugin.class);
			String name = plugin.getName();
			injectors.put(name, childInjector);
		}
	}
	
	public static interface Plugin {
		public String getName ();
	}
	
	public static class Extension1Module extends AbstractModule {
		@Override protected void configure() {
		    bind(Plugin.class).to(Extension1Plugin.class);
		}
	}
	
	public static class Extension1Plugin implements Plugin {
		@Override public String getName() {
		    return "ext1";
		}
	}
	
	public static class Extension2Module extends AbstractModule {
		@Override protected void configure() {
		    bind(Plugin.class).to(Extension2Plugin.class);
		}
	}
	
	public static class Extension2Plugin implements Plugin {
		@Override public String getName() {
		    return "ext2";
		}
	}
}
