// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.jdisc.application; import com.google.common.collect.ImmutableSet; import com.google.inject.Binding; import com.google.inject.Guice; import com.google.inject.Injector; import com.google.inject.Key; import com.google.inject.Module; import com.google.inject.spi.DefaultElementVisitor; import com.google.inject.spi.Element; import com.google.inject.spi.Elements; import com.yahoo.jdisc.Container; import org.osgi.framework.Bundle; import java.util.Arrays; import java.util.Collection; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.List; import java.util.ListIterator; import java.util.Map; import java.util.Set; import java.util.logging.Logger; /** * This is a repository of {@link Module}s. An instance of this class is owned by the {@link ContainerBuilder}, and is * used to configure the set of Modules that eventually form the {@link Injector} of the active {@link Container}. * * @author Simon Thoresen Hult */ public class GuiceRepository implements Iterable { private static final Logger log = Logger.getLogger(GuiceRepository.class.getName()); private final Map> modules = new LinkedHashMap<>(); private Injector injector; public GuiceRepository(Module... modules) { installAll(Arrays.asList(modules)); } public Injector activate() { return getInjector(); } public List installAll(Bundle bundle, Iterable moduleNames) throws ClassNotFoundException { List lst = new LinkedList<>(); for (String moduleName : moduleNames) { lst.add(install(bundle, moduleName)); } return lst; } public Module install(Bundle bundle, String moduleName) throws ClassNotFoundException { log.finer("Installing Guice module '" + moduleName + "'."); Class namedClass = bundle.loadClass(moduleName); Class moduleClass = ContainerBuilder.safeClassCast(Module.class, namedClass); Module module = getInstance(moduleClass); install(module); return module; } public final void installAll(Iterable modules) { for (Module module : modules) { install(module); } } public final void install(Module module) { modules.put(module, Elements.getElements(module)); injector = null; } public void uninstallAll(Iterable modules) { for (Module module : modules) { uninstall(module); } } public void uninstall(Module module) { modules.remove(module); injector = null; } public Injector getInjector() { if (injector == null) { injector = Guice.createInjector(createModule()); } return injector; } public T getInstance(Key key) { return getInjector().getInstance(key); } public T getInstance(Class type) { return getInjector().getInstance(type); } public Collection collection() { return ImmutableSet.copyOf(modules.keySet()); } @Override public Iterator iterator() { return collection().iterator(); } private Module createModule() { List allElements = new LinkedList<>(); for (List moduleElements : modules.values()) { allElements.addAll(moduleElements); } ElementCollector collector = new ElementCollector(); for (ListIterator it = allElements.listIterator(allElements.size()); it.hasPrevious(); ) { it.previous().acceptVisitor(collector); } return Elements.getModule(collector.elements); } private static class ElementCollector extends DefaultElementVisitor { final Set> seenKeys = new HashSet<>(); final List elements = new LinkedList<>(); @Override public Boolean visit(Binding binding) { if (seenKeys.add(binding.getKey())) { elements.add(binding); } return Boolean.TRUE; } @Override public Boolean visitOther(Element element) { elements.add(element); return Boolean.TRUE; } } }