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
17package com.google.inject.internal;
18
19import static com.google.common.base.Preconditions.checkState;
20import static com.google.inject.Scopes.SINGLETON;
21
22import com.google.common.collect.ImmutableSet;
23import com.google.common.collect.Lists;
24import com.google.inject.Binder;
25import com.google.inject.Injector;
26import com.google.inject.Key;
27import com.google.inject.Module;
28import com.google.inject.Provider;
29import com.google.inject.Singleton;
30import com.google.inject.Stage;
31import com.google.inject.internal.InjectorImpl.InjectorOptions;
32import com.google.inject.internal.util.SourceProvider;
33import com.google.inject.internal.util.Stopwatch;
34import com.google.inject.spi.Dependency;
35import com.google.inject.spi.Element;
36import com.google.inject.spi.Elements;
37import com.google.inject.spi.InjectionPoint;
38import com.google.inject.spi.ModuleAnnotatedMethodScannerBinding;
39import com.google.inject.spi.PrivateElements;
40import com.google.inject.spi.ProvisionListenerBinding;
41import com.google.inject.spi.TypeListenerBinding;
42
43import java.util.List;
44import 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@google.com (Jesse Wilson)
51 */
52final 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