Home | History | Annotate | Download | only in internal
      1 /**
      2  * Copyright (C) 2006 Google Inc.
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  * http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.google.inject.internal;
     18 
     19 import com.google.common.collect.ImmutableList;
     20 import com.google.common.collect.Iterables;
     21 import com.google.inject.Binding;
     22 import com.google.inject.Injector;
     23 import com.google.inject.Key;
     24 import com.google.inject.MembersInjector;
     25 import com.google.inject.Module;
     26 import com.google.inject.Provider;
     27 import com.google.inject.Scope;
     28 import com.google.inject.Stage;
     29 import com.google.inject.TypeLiteral;
     30 import com.google.inject.internal.util.Stopwatch;
     31 import com.google.inject.spi.Dependency;
     32 import com.google.inject.spi.TypeConverterBinding;
     33 
     34 import java.lang.annotation.Annotation;
     35 import java.util.Collection;
     36 import java.util.List;
     37 import java.util.Map;
     38 import java.util.Set;
     39 
     40 /**
     41  * Builds a tree of injectors. This is a primary injector, plus child injectors needed for each
     42  * {@code Binder.newPrivateBinder() private environment}. The primary injector is not necessarily a
     43  * top-level injector.
     44  *
     45  * <p>Injector construction happens in two phases.
     46  * <ol>
     47  *   <li>Static building. In this phase, we interpret commands, create bindings, and inspect
     48  *     dependencies. During this phase, we hold a lock to ensure consistency with parent injectors.
     49  *     No user code is executed in this phase.</li>
     50  *   <li>Dynamic injection. In this phase, we call user code. We inject members that requested
     51  *     injection. This may require user's objects be created and their providers be called. And we
     52  *     create eager singletons. In this phase, user code may have started other threads. This phase
     53  *     is not executed for injectors created using {@link Stage#TOOL the tool stage}</li>
     54  * </ol>
     55  *
     56  * @author crazybob (at) google.com (Bob Lee)
     57  * @author jessewilson (at) google.com (Jesse Wilson)
     58  */
     59 public final class InternalInjectorCreator {
     60 
     61   private final Stopwatch stopwatch = new Stopwatch();
     62   private final Errors errors = new Errors();
     63 
     64   private final Initializer initializer = new Initializer();
     65   private final ProcessedBindingData bindingData;
     66   private final InjectionRequestProcessor injectionRequestProcessor;
     67 
     68   private final InjectorShell.Builder shellBuilder = new InjectorShell.Builder();
     69   private List<InjectorShell> shells;
     70 
     71   public InternalInjectorCreator() {
     72     injectionRequestProcessor = new InjectionRequestProcessor(errors, initializer);
     73     bindingData = new ProcessedBindingData();
     74   }
     75 
     76   public InternalInjectorCreator stage(Stage stage) {
     77     shellBuilder.stage(stage);
     78     return this;
     79   }
     80 
     81   /**
     82    * Sets the parent of the injector to-be-constructed. As a side effect, this sets this injector's
     83    * stage to the stage of {@code parent} and sets {@link #requireExplicitBindings()} if the parent
     84    * injector also required them.
     85    */
     86   public InternalInjectorCreator parentInjector(InjectorImpl parent) {
     87     shellBuilder.parent(parent);
     88     return this;
     89   }
     90 
     91   public InternalInjectorCreator addModules(Iterable<? extends Module> modules) {
     92     shellBuilder.addModules(modules);
     93     return this;
     94   }
     95 
     96   public Injector build() {
     97     if (shellBuilder == null) {
     98       throw new AssertionError("Already built, builders are not reusable.");
     99     }
    100 
    101     // Synchronize while we're building up the bindings and other injector state. This ensures that
    102     // the JIT bindings in the parent injector don't change while we're being built
    103     synchronized (shellBuilder.lock()) {
    104       shells = shellBuilder.build(initializer, bindingData, stopwatch, errors);
    105       stopwatch.resetAndLog("Injector construction");
    106 
    107       initializeStatically();
    108     }
    109 
    110     injectDynamically();
    111 
    112     if (shellBuilder.getStage() == Stage.TOOL) {
    113       // wrap the primaryInjector in a ToolStageInjector
    114       // to prevent non-tool-friendy methods from being called.
    115       return new ToolStageInjector(primaryInjector());
    116     } else {
    117       return primaryInjector();
    118     }
    119   }
    120 
    121   /** Initialize and validate everything. */
    122   private void initializeStatically() {
    123     bindingData.initializeBindings();
    124     stopwatch.resetAndLog("Binding initialization");
    125 
    126     for (InjectorShell shell : shells) {
    127       shell.getInjector().index();
    128     }
    129     stopwatch.resetAndLog("Binding indexing");
    130 
    131     injectionRequestProcessor.process(shells);
    132     stopwatch.resetAndLog("Collecting injection requests");
    133 
    134     bindingData.runCreationListeners(errors);
    135     stopwatch.resetAndLog("Binding validation");
    136 
    137     injectionRequestProcessor.validate();
    138     stopwatch.resetAndLog("Static validation");
    139 
    140     initializer.validateOustandingInjections(errors);
    141     stopwatch.resetAndLog("Instance member validation");
    142 
    143     new LookupProcessor(errors).process(shells);
    144     for (InjectorShell shell : shells) {
    145       ((DeferredLookups) shell.getInjector().lookups).initialize(errors);
    146     }
    147     stopwatch.resetAndLog("Provider verification");
    148 
    149     for (InjectorShell shell : shells) {
    150       if (!shell.getElements().isEmpty()) {
    151         throw new AssertionError("Failed to execute " + shell.getElements());
    152       }
    153     }
    154 
    155     errors.throwCreationExceptionIfErrorsExist();
    156   }
    157 
    158   /**
    159    * Returns the injector being constructed. This is not necessarily the root injector.
    160    */
    161   private Injector primaryInjector() {
    162     return shells.get(0).getInjector();
    163   }
    164 
    165   /**
    166    * Inject everything that can be injected. This method is intentionally not synchronized. If we
    167    * locked while injecting members (ie. running user code), things would deadlock should the user
    168    * code build a just-in-time binding from another thread.
    169    */
    170   private void injectDynamically() {
    171     injectionRequestProcessor.injectMembers();
    172     stopwatch.resetAndLog("Static member injection");
    173 
    174     initializer.injectAll(errors);
    175     stopwatch.resetAndLog("Instance injection");
    176     errors.throwCreationExceptionIfErrorsExist();
    177 
    178     if(shellBuilder.getStage() != Stage.TOOL) {
    179       for (InjectorShell shell : shells) {
    180         loadEagerSingletons(shell.getInjector(), shellBuilder.getStage(), errors);
    181       }
    182       stopwatch.resetAndLog("Preloading singletons");
    183     }
    184     errors.throwCreationExceptionIfErrorsExist();
    185   }
    186 
    187   /**
    188    * Loads eager singletons, or all singletons if we're in Stage.PRODUCTION. Bindings discovered
    189    * while we're binding these singletons are not be eager.
    190    */
    191   void loadEagerSingletons(InjectorImpl injector, Stage stage, final Errors errors) {
    192     @SuppressWarnings("unchecked") // casting Collection<Binding> to Collection<BindingImpl> is safe
    193     Iterable<BindingImpl<?>> candidateBindings = ImmutableList.copyOf(Iterables.concat(
    194         (Collection) injector.state.getExplicitBindingsThisLevel().values(),
    195         injector.jitBindings.values()));
    196     for (final BindingImpl<?> binding : candidateBindings) {
    197       if (isEagerSingleton(injector, binding, stage)) {
    198         try {
    199           injector.callInContext(new ContextualCallable<Void>() {
    200             Dependency<?> dependency = Dependency.get(binding.getKey());
    201             public Void call(InternalContext context) {
    202               Dependency previous = context.pushDependency(dependency, binding.getSource());
    203               Errors errorsForBinding = errors.withSource(dependency);
    204               try {
    205                 binding.getInternalFactory().get(errorsForBinding, context, dependency, false);
    206               } catch (ErrorsException e) {
    207                 errorsForBinding.merge(e.getErrors());
    208               } finally {
    209                 context.popStateAndSetDependency(previous);
    210               }
    211 
    212               return null;
    213             }
    214           });
    215         } catch (ErrorsException e) {
    216           throw new AssertionError();
    217         }
    218       }
    219     }
    220   }
    221 
    222   private boolean isEagerSingleton(InjectorImpl injector, BindingImpl<?> binding, Stage stage) {
    223     if (binding.getScoping().isEagerSingleton(stage)) {
    224       return true;
    225     }
    226 
    227     // handle a corner case where a child injector links to a binding in a parent injector, and
    228     // that binding is singleton. We won't catch this otherwise because we only iterate the child's
    229     // bindings.
    230     if (binding instanceof LinkedBindingImpl) {
    231       Key<?> linkedBinding = ((LinkedBindingImpl<?>) binding).getLinkedKey();
    232       return isEagerSingleton(injector, injector.getBinding(linkedBinding), stage);
    233     }
    234 
    235     return false;
    236   }
    237 
    238   /** {@link Injector} exposed to users in {@link Stage#TOOL}. */
    239   static class ToolStageInjector implements Injector {
    240     private final Injector delegateInjector;
    241 
    242     ToolStageInjector(Injector delegateInjector) {
    243       this.delegateInjector = delegateInjector;
    244     }
    245     public void injectMembers(Object o) {
    246       throw new UnsupportedOperationException(
    247         "Injector.injectMembers(Object) is not supported in Stage.TOOL");
    248     }
    249     public Map<Key<?>, Binding<?>> getBindings() {
    250       return this.delegateInjector.getBindings();
    251     }
    252     public Map<Key<?>, Binding<?>> getAllBindings() {
    253       return this.delegateInjector.getAllBindings();
    254     }
    255     public <T> Binding<T> getBinding(Key<T> key) {
    256       return this.delegateInjector.getBinding(key);
    257     }
    258     public <T> Binding<T> getBinding(Class<T> type) {
    259       return this.delegateInjector.getBinding(type);
    260     }
    261     public <T> Binding<T> getExistingBinding(Key<T> key) {
    262       return this.delegateInjector.getExistingBinding(key);
    263     }
    264     public <T> List<Binding<T>> findBindingsByType(TypeLiteral<T> type) {
    265       return this.delegateInjector.findBindingsByType(type);
    266     }
    267     public Injector getParent() {
    268       return delegateInjector.getParent();
    269     }
    270     public Injector createChildInjector(Iterable<? extends Module> modules) {
    271       return delegateInjector.createChildInjector(modules);
    272     }
    273     public Injector createChildInjector(Module... modules) {
    274       return delegateInjector.createChildInjector(modules);
    275     }
    276     public Map<Class<? extends Annotation>, Scope> getScopeBindings() {
    277       return delegateInjector.getScopeBindings();
    278     }
    279     public Set<TypeConverterBinding> getTypeConverterBindings() {
    280       return delegateInjector.getTypeConverterBindings();
    281     }
    282     public <T> Provider<T> getProvider(Key<T> key) {
    283       throw new UnsupportedOperationException(
    284         "Injector.getProvider(Key<T>) is not supported in Stage.TOOL");
    285     }
    286     public <T> Provider<T> getProvider(Class<T> type) {
    287       throw new UnsupportedOperationException(
    288         "Injector.getProvider(Class<T>) is not supported in Stage.TOOL");
    289     }
    290     public <T> MembersInjector<T> getMembersInjector(TypeLiteral<T> typeLiteral) {
    291       throw new UnsupportedOperationException(
    292         "Injector.getMembersInjector(TypeLiteral<T>) is not supported in Stage.TOOL");
    293     }
    294     public <T> MembersInjector<T> getMembersInjector(Class<T> type) {
    295       throw new UnsupportedOperationException(
    296         "Injector.getMembersInjector(Class<T>) is not supported in Stage.TOOL");
    297     }
    298     public <T> T getInstance(Key<T> key) {
    299       throw new UnsupportedOperationException(
    300         "Injector.getInstance(Key<T>) is not supported in Stage.TOOL");
    301     }
    302     public <T> T getInstance(Class<T> type) {
    303       throw new UnsupportedOperationException(
    304         "Injector.getInstance(Class<T>) is not supported in Stage.TOOL");
    305     }
    306   }
    307 }
    308