blob: ce9e5b9e295ea98c90aabee0ff1bfb175a81763b [file] [log] [blame]
limpbizkitfcbdf992008-11-26 02:37:35 +00001/**
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;
18
limpbizkitfcbdf992008-11-26 02:37:35 +000019import static com.google.inject.Scopes.SINGLETON;
20import com.google.inject.internal.Errors;
21import com.google.inject.internal.ErrorsException;
limpbizkit53664a72009-02-21 00:25:27 +000022import com.google.inject.internal.ImmutableSet;
limpbizkit76c24b12008-12-25 04:32:41 +000023import com.google.inject.internal.InternalContext;
24import com.google.inject.internal.InternalFactory;
limpbizkit53664a72009-02-21 00:25:27 +000025import com.google.inject.internal.Lists;
26import static com.google.inject.internal.Preconditions.checkNotNull;
27import static com.google.inject.internal.Preconditions.checkState;
limpbizkitc3f92842008-12-30 19:43:47 +000028import com.google.inject.internal.PrivateElementsImpl;
limpbizkit76c24b12008-12-25 04:32:41 +000029import com.google.inject.internal.ProviderInstanceBindingImpl;
30import com.google.inject.internal.Scoping;
limpbizkitfcbdf992008-11-26 02:37:35 +000031import com.google.inject.internal.SourceProvider;
32import com.google.inject.internal.Stopwatch;
33import com.google.inject.spi.Dependency;
34import com.google.inject.spi.Element;
35import com.google.inject.spi.Elements;
36import com.google.inject.spi.InjectionPoint;
limpbizkitc3f92842008-12-30 19:43:47 +000037import com.google.inject.spi.PrivateElements;
limpbizkitee792462009-04-08 23:48:49 +000038import com.google.inject.spi.TypeListenerBinding;
limpbizkitfcbdf992008-11-26 02:37:35 +000039import java.util.List;
limpbizkitfcbdf992008-11-26 02:37:35 +000040import java.util.logging.Logger;
41
42/**
43 * A partially-initialized injector. See {@link InjectorBuilder}, which uses this to build a tree
44 * of injectors in batch.
45 *
46 * @author jessewilson@google.com (Jesse Wilson)
47 */
48class InjectorShell {
49
50 private final List<Element> elements;
51 private final InjectorImpl injector;
limpbizkitc3f92842008-12-30 19:43:47 +000052 private final PrivateElements privateElements;
limpbizkitfcbdf992008-11-26 02:37:35 +000053
54 private InjectorShell(Builder builder, List<Element> elements, InjectorImpl injector) {
limpbizkitc3f92842008-12-30 19:43:47 +000055 this.privateElements = builder.privateElements;
limpbizkitfcbdf992008-11-26 02:37:35 +000056 this.elements = elements;
57 this.injector = injector;
58 }
59
limpbizkitc3f92842008-12-30 19:43:47 +000060 PrivateElements getPrivateElements() {
61 return privateElements;
limpbizkitfcbdf992008-11-26 02:37:35 +000062 }
63
64 InjectorImpl getInjector() {
65 return injector;
66 }
67
68 List<Element> getElements() {
69 return elements;
70 }
71
72 static class Builder {
73 private final List<Element> elements = Lists.newArrayList();
74 private final List<Module> modules = Lists.newArrayList();
75
76 /** lazily constructed */
77 private State state;
78
79 private InjectorImpl parent;
80 private Stage stage;
81
82 /** null unless this exists in a {@link Binder#newPrivateBinder private environment} */
limpbizkitc3f92842008-12-30 19:43:47 +000083 private PrivateElementsImpl privateElements;
limpbizkitfcbdf992008-11-26 02:37:35 +000084
85 Builder parent(InjectorImpl parent) {
86 this.parent = parent;
87 this.state = new InheritingState(parent.state);
88 return this;
89 }
90
91 Builder stage(Stage stage) {
92 this.stage = stage;
93 return this;
94 }
95
limpbizkitc3f92842008-12-30 19:43:47 +000096 Builder privateElements(PrivateElements privateElements) {
97 this.privateElements = (PrivateElementsImpl) privateElements;
98 this.elements.addAll(privateElements.getElements());
limpbizkitfcbdf992008-11-26 02:37:35 +000099 return this;
100 }
101
102 void addModules(Iterable<? extends Module> modules) {
103 for (Module module : modules) {
104 this.modules.add(module);
105 }
106 }
107
108 /** Synchronize on this before calling {@link #build}. */
109 Object lock() {
110 return getState().lock();
111 }
112
113 /**
114 * Creates and returns the injector shells for the current modules. Multiple shells will be
115 * returned if any modules contain {@link Binder#newPrivateBinder private environments}. The
116 * primary injector will be first in the returned list.
117 */
118 List<InjectorShell> build(Initializer initializer, BindingProcessor bindingProcessor,
limpbizkitfcbdf992008-11-26 02:37:35 +0000119 Stopwatch stopwatch, Errors errors) {
120 checkState(stage != null, "Stage not initialized");
limpbizkitc3f92842008-12-30 19:43:47 +0000121 checkState(privateElements == null || parent != null, "PrivateElements with no parent");
limpbizkitfcbdf992008-11-26 02:37:35 +0000122 checkState(state != null, "no state. Did you remember to lock() ?");
123
124 InjectorImpl injector = new InjectorImpl(parent, state, initializer);
limpbizkitc3f92842008-12-30 19:43:47 +0000125 if (privateElements != null) {
126 privateElements.initInjector(injector);
limpbizkitfcbdf992008-11-26 02:37:35 +0000127 }
128
129 // bind Stage and Singleton if this is a top-level injector
130 if (parent == null) {
131 modules.add(0, new RootModule(stage));
132 new TypeConverterBindingProcessor(errors).prepareBuiltInConverters(injector);
133 }
134
135 elements.addAll(Elements.getElements(stage, modules));
136 stopwatch.resetAndLog("Module execution");
137
138 new MessageProcessor(errors).process(injector, elements);
139
limpbizkitbf0d8762009-02-19 09:06:22 +0000140 /*if[AOP]*/
limpbizkitfcbdf992008-11-26 02:37:35 +0000141 InterceptorBindingProcessor interceptors = new InterceptorBindingProcessor(errors);
142 interceptors.process(injector, elements);
limpbizkitfcbdf992008-11-26 02:37:35 +0000143 stopwatch.resetAndLog("Interceptors creation");
limpbizkitbf0d8762009-02-19 09:06:22 +0000144 /*end[AOP]*/
limpbizkitfcbdf992008-11-26 02:37:35 +0000145
limpbizkitee792462009-04-08 23:48:49 +0000146 new TypeListenerBindingProcessor(errors).process(injector, elements);
147 List<TypeListenerBinding> listenerBindings = injector.state.getTypeListenerBindings();
limpbizkit7cef5b02009-03-29 21:16:51 +0000148 injector.membersInjectorStore = new MembersInjectorStore(injector, listenerBindings);
limpbizkita843a952009-04-08 22:24:55 +0000149 stopwatch.resetAndLog("TypeListeners creation");
limpbizkit03b81a62009-03-18 05:34:39 +0000150
limpbizkitfcbdf992008-11-26 02:37:35 +0000151 new ScopeBindingProcessor(errors).process(injector, elements);
152 stopwatch.resetAndLog("Scopes creation");
153
154 new TypeConverterBindingProcessor(errors).process(injector, elements);
155 stopwatch.resetAndLog("Converters creation");
156
157 bindInjector(injector);
158 bindLogger(injector);
159 bindingProcessor.process(injector, elements);
160 stopwatch.resetAndLog("Binding creation");
161
162 List<InjectorShell> injectorShells = Lists.newArrayList();
163 injectorShells.add(new InjectorShell(this, elements, injector));
164
165 // recursively build child shells
limpbizkitc3f92842008-12-30 19:43:47 +0000166 PrivateElementProcessor processor = new PrivateElementProcessor(errors, stage);
limpbizkitfcbdf992008-11-26 02:37:35 +0000167 processor.process(injector, elements);
168 for (Builder builder : processor.getInjectorShellBuilders()) {
limpbizkitc3f92842008-12-30 19:43:47 +0000169 injectorShells.addAll(builder.build(initializer, bindingProcessor, stopwatch, errors));
limpbizkitfcbdf992008-11-26 02:37:35 +0000170 }
171 stopwatch.resetAndLog("Private environment creation");
172
173 return injectorShells;
174 }
175
176 private State getState() {
177 if (state == null) {
178 state = new InheritingState(State.NONE);
179 }
180 return state;
181 }
182 }
183
184 /**
185 * The Injector is a special case because we allow both parent and child injectors to both have
186 * a binding for that key.
187 */
188 private static void bindInjector(InjectorImpl injector) {
189 Key<Injector> key = Key.get(Injector.class);
190 InjectorFactory injectorFactory = new InjectorFactory(injector);
191 injector.state.putBinding(key,
192 new ProviderInstanceBindingImpl<Injector>(injector, key, SourceProvider.UNKNOWN_SOURCE,
limpbizkit76c24b12008-12-25 04:32:41 +0000193 injectorFactory, Scoping.UNSCOPED, injectorFactory,
limpbizkitfcbdf992008-11-26 02:37:35 +0000194 ImmutableSet.<InjectionPoint>of()));
195 }
196
197 private static class InjectorFactory implements InternalFactory<Injector>, Provider<Injector> {
198 private final Injector injector;
199
200 private InjectorFactory(Injector injector) {
201 this.injector = injector;
202 }
203
204 public Injector get(Errors errors, InternalContext context, Dependency<?> dependency)
205 throws ErrorsException {
206 return injector;
207 }
208
209 public Injector get() {
210 return injector;
211 }
212
213 public String toString() {
214 return "Provider<Injector>";
215 }
216 }
217
218 /**
219 * The Logger is a special case because it knows the injection point of the injected member. It's
220 * the only binding that does this.
221 */
222 private static void bindLogger(InjectorImpl injector) {
223 Key<Logger> key = Key.get(Logger.class);
224 LoggerFactory loggerFactory = new LoggerFactory();
225 injector.state.putBinding(key,
226 new ProviderInstanceBindingImpl<Logger>(injector, key,
limpbizkit76c24b12008-12-25 04:32:41 +0000227 SourceProvider.UNKNOWN_SOURCE, loggerFactory, Scoping.UNSCOPED,
228 loggerFactory, ImmutableSet.<InjectionPoint>of()));
limpbizkitfcbdf992008-11-26 02:37:35 +0000229 }
230
231 private static class LoggerFactory implements InternalFactory<Logger>, Provider<Logger> {
232 public Logger get(Errors errors, InternalContext context, Dependency<?> dependency) {
233 InjectionPoint injectionPoint = dependency.getInjectionPoint();
234 return injectionPoint == null
235 ? Logger.getAnonymousLogger()
236 : Logger.getLogger(injectionPoint.getMember().getDeclaringClass().getName());
237 }
238
239 public Logger get() {
240 return Logger.getAnonymousLogger();
241 }
242
243 public String toString() {
244 return "Provider<Logger>";
245 }
246 }
247
248 private static class RootModule implements Module {
249 final Stage stage;
250
251 private RootModule(Stage stage) {
252 this.stage = checkNotNull(stage, "stage");
253 }
254
255 public void configure(Binder binder) {
256 binder = binder.withSource(SourceProvider.UNKNOWN_SOURCE);
257 binder.bind(Stage.class).toInstance(stage);
258 binder.bindScope(Singleton.class, SINGLETON);
259 }
260 }
261}