Home | History | Annotate | Download | only in internal
      1 /**
      2  * Copyright (C) 2008 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 static com.google.common.base.Preconditions.checkState;
     20 import static com.google.inject.Scopes.SINGLETON;
     21 
     22 import com.google.common.collect.ImmutableSet;
     23 import com.google.common.collect.Lists;
     24 import com.google.inject.Binder;
     25 import com.google.inject.Injector;
     26 import com.google.inject.Key;
     27 import com.google.inject.Module;
     28 import com.google.inject.Provider;
     29 import com.google.inject.Singleton;
     30 import com.google.inject.Stage;
     31 import com.google.inject.internal.InjectorImpl.InjectorOptions;
     32 import com.google.inject.internal.util.SourceProvider;
     33 import com.google.inject.internal.util.Stopwatch;
     34 import com.google.inject.spi.Dependency;
     35 import com.google.inject.spi.Element;
     36 import com.google.inject.spi.Elements;
     37 import com.google.inject.spi.InjectionPoint;
     38 import com.google.inject.spi.ModuleAnnotatedMethodScannerBinding;
     39 import com.google.inject.spi.PrivateElements;
     40 import com.google.inject.spi.ProvisionListenerBinding;
     41 import com.google.inject.spi.TypeListenerBinding;
     42 
     43 import java.util.List;
     44 import java.util.logging.Logger;
     45 
     46 /**
     47  * A partially-initialized injector. See {@link InternalInjectorCreator}, which
     48  * uses this to build a tree of injectors in batch.
     49  *
     50  * @author jessewilson (at) google.com (Jesse Wilson)
     51  */
     52 final class InjectorShell {
     53 
     54   private final List<Element> elements;
     55   private final InjectorImpl injector;
     56 
     57   private InjectorShell(Builder builder, List<Element> elements, InjectorImpl injector) {
     58     this.elements = elements;
     59     this.injector = injector;
     60   }
     61 
     62   InjectorImpl getInjector() {
     63     return injector;
     64   }
     65 
     66   List<Element> getElements() {
     67     return elements;
     68   }
     69 
     70   static class Builder {
     71     private final List<Element> elements = Lists.newArrayList();
     72     private final List<Module> modules = Lists.newArrayList();
     73 
     74     /** lazily constructed */
     75     private State state;
     76 
     77     private InjectorImpl parent;
     78     private InjectorOptions options;
     79     private Stage stage;
     80 
     81     /** null unless this exists in a {@link Binder#newPrivateBinder private environment} */
     82     private PrivateElementsImpl privateElements;
     83 
     84     Builder stage(Stage stage) {
     85       this.stage = stage;
     86       return this;
     87     }
     88 
     89     Builder parent(InjectorImpl parent) {
     90       this.parent = parent;
     91       this.state = new InheritingState(parent.state);
     92       this.options = parent.options;
     93       this.stage = options.stage;
     94       return this;
     95     }
     96 
     97     Builder privateElements(PrivateElements privateElements) {
     98       this.privateElements = (PrivateElementsImpl) privateElements;
     99       this.elements.addAll(privateElements.getElements());
    100       return this;
    101     }
    102 
    103     void addModules(Iterable<? extends Module> modules) {
    104       for (Module module : modules) {
    105         this.modules.add(module);
    106       }
    107     }
    108 
    109     Stage getStage() {
    110       return options.stage;
    111     }
    112 
    113     /** Synchronize on this before calling {@link #build}. */
    114     Object lock() {
    115       return getState().lock();
    116     }
    117 
    118     /**
    119      * Creates and returns the injector shells for the current modules. Multiple shells will be
    120      * returned if any modules contain {@link Binder#newPrivateBinder private environments}. The
    121      * primary injector will be first in the returned list.
    122      */
    123     List<InjectorShell> build(
    124         Initializer initializer,
    125         ProcessedBindingData bindingData,
    126         Stopwatch stopwatch,
    127         Errors errors) {
    128       checkState(stage != null, "Stage not initialized");
    129       checkState(privateElements == null || parent != null, "PrivateElements with no parent");
    130       checkState(state != null, "no state. Did you remember to lock() ?");
    131 
    132       // bind Singleton if this is a top-level injector
    133       if (parent == null) {
    134         modules.add(0, new RootModule());
    135       } else {
    136         modules.add(0, new InheritedScannersModule(parent.state));
    137       }
    138       elements.addAll(Elements.getElements(stage, modules));
    139 
    140       // Look for injector-changing options
    141       InjectorOptionsProcessor optionsProcessor = new InjectorOptionsProcessor(errors);
    142       optionsProcessor.process(null, elements);
    143       options = optionsProcessor.getOptions(stage, options);
    144 
    145       InjectorImpl injector = new InjectorImpl(parent, state, options);
    146       if (privateElements != null) {
    147         privateElements.initInjector(injector);
    148       }
    149 
    150       // add default type converters if this is a top-level injector
    151       if (parent == null) {
    152         TypeConverterBindingProcessor.prepareBuiltInConverters(injector);
    153       }
    154 
    155       stopwatch.resetAndLog("Module execution");
    156 
    157       new MessageProcessor(errors).process(injector, elements);
    158 
    159       /*if[AOP]*/
    160       new InterceptorBindingProcessor(errors).process(injector, elements);
    161       stopwatch.resetAndLog("Interceptors creation");
    162       /*end[AOP]*/
    163 
    164       new ListenerBindingProcessor(errors).process(injector, elements);
    165       List<TypeListenerBinding> typeListenerBindings = injector.state.getTypeListenerBindings();
    166       injector.membersInjectorStore = new MembersInjectorStore(injector, typeListenerBindings);
    167       List<ProvisionListenerBinding> provisionListenerBindings =
    168           injector.state.getProvisionListenerBindings();
    169       injector.provisionListenerStore =
    170           new ProvisionListenerCallbackStore(provisionListenerBindings);
    171       stopwatch.resetAndLog("TypeListeners & ProvisionListener creation");
    172 
    173       new ScopeBindingProcessor(errors).process(injector, elements);
    174       stopwatch.resetAndLog("Scopes creation");
    175 
    176       new TypeConverterBindingProcessor(errors).process(injector, elements);
    177       stopwatch.resetAndLog("Converters creation");
    178 
    179       bindStage(injector, stage);
    180       bindInjector(injector);
    181       bindLogger(injector);
    182 
    183       // Process all normal bindings, then UntargettedBindings.
    184       // This is necessary because UntargettedBindings can create JIT bindings
    185       // and need all their other dependencies set up ahead of time.
    186       new BindingProcessor(errors, initializer, bindingData).process(injector, elements);
    187       new UntargettedBindingProcessor(errors, bindingData).process(injector, elements);
    188       stopwatch.resetAndLog("Binding creation");
    189 
    190       new ModuleAnnotatedMethodScannerProcessor(errors).process(injector, elements);
    191       stopwatch.resetAndLog("Module annotated method scanners creation");
    192 
    193       List<InjectorShell> injectorShells = Lists.newArrayList();
    194       injectorShells.add(new InjectorShell(this, elements, injector));
    195 
    196       // recursively build child shells
    197       PrivateElementProcessor processor = new PrivateElementProcessor(errors);
    198       processor.process(injector, elements);
    199       for (Builder builder : processor.getInjectorShellBuilders()) {
    200         injectorShells.addAll(builder.build(initializer, bindingData, stopwatch, errors));
    201       }
    202       stopwatch.resetAndLog("Private environment creation");
    203 
    204       return injectorShells;
    205     }
    206 
    207     private State getState() {
    208       if (state == null) {
    209         state = new InheritingState(State.NONE);
    210       }
    211       return state;
    212     }
    213   }
    214 
    215   /**
    216    * The Injector is a special case because we allow both parent and child injectors to both have
    217    * a binding for that key.
    218    */
    219   private static void bindInjector(InjectorImpl injector) {
    220     Key<Injector> key = Key.get(Injector.class);
    221     InjectorFactory injectorFactory = new InjectorFactory(injector);
    222     injector.state.putBinding(key,
    223         new ProviderInstanceBindingImpl<Injector>(injector, key, SourceProvider.UNKNOWN_SOURCE,
    224             injectorFactory, Scoping.UNSCOPED, injectorFactory,
    225             ImmutableSet.<InjectionPoint>of()));
    226   }
    227 
    228   private static class InjectorFactory implements InternalFactory<Injector>, Provider<Injector> {
    229     private final Injector injector;
    230 
    231     private InjectorFactory(Injector injector) {
    232       this.injector = injector;
    233     }
    234 
    235     public Injector get(Errors errors, InternalContext context, Dependency<?> dependency, boolean linked)
    236         throws ErrorsException {
    237       return injector;
    238     }
    239 
    240     public Injector get() {
    241       return injector;
    242     }
    243 
    244     public String toString() {
    245       return "Provider<Injector>";
    246     }
    247   }
    248 
    249   /**
    250    * The Logger is a special case because it knows the injection point of the injected member. It's
    251    * the only binding that does this.
    252    */
    253   private static void bindLogger(InjectorImpl injector) {
    254     Key<Logger> key = Key.get(Logger.class);
    255     LoggerFactory loggerFactory = new LoggerFactory();
    256     injector.state.putBinding(key,
    257         new ProviderInstanceBindingImpl<Logger>(injector, key,
    258             SourceProvider.UNKNOWN_SOURCE, loggerFactory, Scoping.UNSCOPED,
    259             loggerFactory, ImmutableSet.<InjectionPoint>of()));
    260   }
    261 
    262   private static class LoggerFactory implements InternalFactory<Logger>, Provider<Logger> {
    263     public Logger get(Errors errors, InternalContext context, Dependency<?> dependency, boolean linked) {
    264       InjectionPoint injectionPoint = dependency.getInjectionPoint();
    265       return injectionPoint == null
    266           ? Logger.getAnonymousLogger()
    267           : Logger.getLogger(injectionPoint.getMember().getDeclaringClass().getName());
    268     }
    269 
    270     public Logger get() {
    271       return Logger.getAnonymousLogger();
    272     }
    273 
    274     public String toString() {
    275       return "Provider<Logger>";
    276     }
    277   }
    278 
    279   private static void bindStage(InjectorImpl injector, Stage stage) {
    280     Key<Stage> key = Key.get(Stage.class);
    281     InstanceBindingImpl<Stage> stageBinding = new InstanceBindingImpl<Stage>(
    282         injector,
    283         key,
    284         SourceProvider.UNKNOWN_SOURCE,
    285         new ConstantFactory<Stage>(Initializables.of(stage)),
    286         ImmutableSet.<InjectionPoint>of(),
    287         stage);
    288     injector.state.putBinding(key, stageBinding);
    289   }
    290 
    291   private static class RootModule implements Module {
    292     public void configure(Binder binder) {
    293       binder = binder.withSource(SourceProvider.UNKNOWN_SOURCE);
    294       binder.bindScope(Singleton.class, SINGLETON);
    295       binder.bindScope(javax.inject.Singleton.class, SINGLETON);
    296     }
    297   }
    298 
    299   private static class InheritedScannersModule implements Module {
    300     private final State state;
    301 
    302     InheritedScannersModule(State state) {
    303       this.state = state;
    304     }
    305 
    306     public void configure(Binder binder) {
    307       for (ModuleAnnotatedMethodScannerBinding binding : state.getScannerBindings()) {
    308         binding.applyTo(binder);
    309       }
    310     }
    311   }
    312 }
    313