/* * Copyright 2011 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package com.google.gwt.inject.rebind.resolution; import com.google.gwt.core.ext.TreeLogger; import com.google.gwt.inject.rebind.GinjectorBindings; import com.google.gwt.inject.rebind.binding.Binding; import com.google.gwt.inject.rebind.binding.BindingFactory; import com.google.gwt.inject.rebind.binding.Context; import com.google.gwt.inject.rebind.binding.Dependency; import com.google.gwt.inject.rebind.binding.ParentBinding; import com.google.gwt.inject.rebind.resolution.DependencyExplorer.DependencyExplorerOutput; import com.google.gwt.inject.rebind.util.PrettyPrinter; import com.google.inject.Inject; import com.google.inject.Key; import com.google.inject.assistedinject.Assisted; import java.util.Map; /** * Adds all of the positioned implicit bindings necessary to satisfy the unresolved bindings in the * origin injector to the {@link GinjectorBindings} where we've placed each key. It installs the * following bindings using {@link GinjectorBindings#addBinding(Key, Binding)}: * <ul> * <li>Each implicit binding created for a key is installed in the Ginjector that * {@link BindingPositioner} decided it should be placed in. * </li> * <li>For each implicit binding added to a Ginjector G, we add {@link ParentBinding}s to G * to make sure it can access any dependencies for the implicit binding. * </li> * <li>For all the dependencies in the origin, we add {@link ParentBinding}s for the targets that * are not available at the origin (eg, installed higher in the Ginjector hierarchy). * </li> * </ul> * * <p>See {@link BindingResolver} for how this fits into the overall algorithm for resolution. */ class BindingInstaller { private final BindingPositioner positions; private final BindingFactory bindingFactory; private final TreeLogger logger; @Inject public BindingInstaller( BindingPositioner.Factory positionsFactory, BindingFactory bindingFactory, @Assisted TreeLogger logger) { this.positions = positionsFactory.create(logger); this.bindingFactory = bindingFactory; this.logger = logger; } /** * Installs all of the implicit bindings as described {@link BindingInstaller above}. * * @param output {@link DependencyExplorerOutput} with information about the unresolved bindings * for the current ginjector. */ public void installBindings(DependencyExplorerOutput output) { positions.position(output); // Install each implicit binding in the correct position for (Map.Entry<Key<?>, Binding> entry : output.getImplicitBindings()) { installBinding(output.getGraph(), entry.getKey(), entry.getValue()); } // Make sure that each of the dependencies needed directly from the origin are available GinjectorBindings origin = output.getGraph().getOrigin(); inheritBindingsForDeps(origin, origin.getDependencies()); } /** * Adds the given implicit binding in the graph to the injector hierarchy in the position * specified by the {@link BindingPositioner}. Also ensures that the dependencies of the implicit * binding are available at the chosen position. */ private void installBinding(DependencyGraph graph, Key<?> key, Binding binding) { // Figure out where we're putting the implicit entry GinjectorBindings implicitEntryPosition = positions.getInstallPosition(key); // Ensure that the dependencies are available to the ginjector inheritBindingsForDeps(implicitEntryPosition, graph.getDependenciesOf(key)); // Now add the implicit binding to the ginjector implicitEntryPosition.addBinding(key, binding); } /** * @param ginjector Ginjector that needs the dependencies * @param deps dependencies that are needed */ private void inheritBindingsForDeps(GinjectorBindings ginjector, Iterable<Dependency> deps) { for (Dependency dep : deps) { ensureAccessible(dep.getTarget(), positions.getInstallPosition(dep.getTarget()), ginjector); } } /** * Ensure that the binding for key which exists in the parent Ginjector is also available to the * child Ginjector. */ private void ensureAccessible(Key<?> key, GinjectorBindings parent, GinjectorBindings child) { // Parent will be null if it is was an optional dependency and it couldn't be created. if (parent != null && !child.equals(parent) && !child.isBound(key)) { PrettyPrinter.log(logger, TreeLogger.DEBUG, "In %s: inheriting binding for %s from the parent %s", child, key, parent); Context context = Context.format("Inheriting %s from parent", key); // We don't strictly need all the extra checks in addBinding, but it can't hurt. We know, for // example, that there will not be any unresolved bindings for this key. child.addBinding(key, bindingFactory.getParentBinding(key, parent, context)); } } interface Factory { BindingInstaller create(TreeLogger logger); } }