blob: afd9154c778754c3a0ab43dd665d7894c7b1a438 [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
limpbizkit5ae41eb2009-06-06 17:51:27 +000017package com.google.inject.internal;
limpbizkitfcbdf992008-11-26 02:37:35 +000018
limpbizkit5ae41eb2009-06-06 17:51:27 +000019import com.google.inject.Binder;
20import com.google.inject.Injector;
21import com.google.inject.Key;
22import com.google.inject.Module;
23import com.google.inject.Provider;
limpbizkitfcbdf992008-11-26 02:37:35 +000024import static com.google.inject.Scopes.SINGLETON;
limpbizkit5ae41eb2009-06-06 17:51:27 +000025import com.google.inject.Singleton;
26import com.google.inject.Stage;
limpbizkit53664a72009-02-21 00:25:27 +000027import static com.google.inject.internal.Preconditions.checkNotNull;
28import static com.google.inject.internal.Preconditions.checkState;
limpbizkitfcbdf992008-11-26 02:37:35 +000029import com.google.inject.spi.Dependency;
30import com.google.inject.spi.Element;
31import com.google.inject.spi.Elements;
32import com.google.inject.spi.InjectionPoint;
limpbizkitc3f92842008-12-30 19:43:47 +000033import com.google.inject.spi.PrivateElements;
limpbizkitee792462009-04-08 23:48:49 +000034import com.google.inject.spi.TypeListenerBinding;
limpbizkitfcbdf992008-11-26 02:37:35 +000035import java.util.List;
limpbizkitfcbdf992008-11-26 02:37:35 +000036import java.util.logging.Logger;
37
38/**
39 * A partially-initialized injector. See {@link InjectorBuilder}, which uses this to build a tree
40 * of injectors in batch.
41 *
42 * @author jessewilson@google.com (Jesse Wilson)
43 */
limpbizkit5ae41eb2009-06-06 17:51:27 +000044final class InjectorShell {
limpbizkitfcbdf992008-11-26 02:37:35 +000045
46 private final List<Element> elements;
47 private final InjectorImpl injector;
limpbizkitc3f92842008-12-30 19:43:47 +000048 private final PrivateElements privateElements;
limpbizkitfcbdf992008-11-26 02:37:35 +000049
50 private InjectorShell(Builder builder, List<Element> elements, InjectorImpl injector) {
limpbizkitc3f92842008-12-30 19:43:47 +000051 this.privateElements = builder.privateElements;
limpbizkitfcbdf992008-11-26 02:37:35 +000052 this.elements = elements;
53 this.injector = injector;
54 }
55
limpbizkit5ae41eb2009-06-06 17:51:27 +000056 private PrivateElements getPrivateElements() {
limpbizkitc3f92842008-12-30 19:43:47 +000057 return privateElements;
limpbizkitfcbdf992008-11-26 02:37:35 +000058 }
59
60 InjectorImpl getInjector() {
61 return injector;
62 }
63
64 List<Element> getElements() {
65 return elements;
66 }
67
68 static class Builder {
69 private final List<Element> elements = Lists.newArrayList();
70 private final List<Module> modules = Lists.newArrayList();
71
72 /** lazily constructed */
73 private State state;
74
75 private InjectorImpl parent;
76 private Stage stage;
77
78 /** null unless this exists in a {@link Binder#newPrivateBinder private environment} */
limpbizkitc3f92842008-12-30 19:43:47 +000079 private PrivateElementsImpl privateElements;
limpbizkitfcbdf992008-11-26 02:37:35 +000080
81 Builder parent(InjectorImpl parent) {
82 this.parent = parent;
83 this.state = new InheritingState(parent.state);
84 return this;
85 }
86
87 Builder stage(Stage stage) {
88 this.stage = stage;
89 return this;
90 }
91
limpbizkitc3f92842008-12-30 19:43:47 +000092 Builder privateElements(PrivateElements privateElements) {
93 this.privateElements = (PrivateElementsImpl) privateElements;
94 this.elements.addAll(privateElements.getElements());
limpbizkitfcbdf992008-11-26 02:37:35 +000095 return this;
96 }
97
98 void addModules(Iterable<? extends Module> modules) {
99 for (Module module : modules) {
100 this.modules.add(module);
101 }
102 }
103
104 /** Synchronize on this before calling {@link #build}. */
105 Object lock() {
106 return getState().lock();
107 }
108
109 /**
110 * Creates and returns the injector shells for the current modules. Multiple shells will be
111 * returned if any modules contain {@link Binder#newPrivateBinder private environments}. The
112 * primary injector will be first in the returned list.
113 */
114 List<InjectorShell> build(Initializer initializer, BindingProcessor bindingProcessor,
limpbizkitfcbdf992008-11-26 02:37:35 +0000115 Stopwatch stopwatch, Errors errors) {
116 checkState(stage != null, "Stage not initialized");
limpbizkitc3f92842008-12-30 19:43:47 +0000117 checkState(privateElements == null || parent != null, "PrivateElements with no parent");
limpbizkitfcbdf992008-11-26 02:37:35 +0000118 checkState(state != null, "no state. Did you remember to lock() ?");
119
120 InjectorImpl injector = new InjectorImpl(parent, state, initializer);
limpbizkitc3f92842008-12-30 19:43:47 +0000121 if (privateElements != null) {
122 privateElements.initInjector(injector);
limpbizkitfcbdf992008-11-26 02:37:35 +0000123 }
124
125 // bind Stage and Singleton if this is a top-level injector
126 if (parent == null) {
127 modules.add(0, new RootModule(stage));
128 new TypeConverterBindingProcessor(errors).prepareBuiltInConverters(injector);
129 }
130
131 elements.addAll(Elements.getElements(stage, modules));
132 stopwatch.resetAndLog("Module execution");
133
134 new MessageProcessor(errors).process(injector, elements);
135
limpbizkitbf0d8762009-02-19 09:06:22 +0000136 /*if[AOP]*/
limpbizkitfcbdf992008-11-26 02:37:35 +0000137 InterceptorBindingProcessor interceptors = new InterceptorBindingProcessor(errors);
138 interceptors.process(injector, elements);
limpbizkitfcbdf992008-11-26 02:37:35 +0000139 stopwatch.resetAndLog("Interceptors creation");
limpbizkitbf0d8762009-02-19 09:06:22 +0000140 /*end[AOP]*/
limpbizkitfcbdf992008-11-26 02:37:35 +0000141
limpbizkitee792462009-04-08 23:48:49 +0000142 new TypeListenerBindingProcessor(errors).process(injector, elements);
143 List<TypeListenerBinding> listenerBindings = injector.state.getTypeListenerBindings();
limpbizkit7cef5b02009-03-29 21:16:51 +0000144 injector.membersInjectorStore = new MembersInjectorStore(injector, listenerBindings);
limpbizkita843a952009-04-08 22:24:55 +0000145 stopwatch.resetAndLog("TypeListeners creation");
limpbizkit03b81a62009-03-18 05:34:39 +0000146
limpbizkitfcbdf992008-11-26 02:37:35 +0000147 new ScopeBindingProcessor(errors).process(injector, elements);
148 stopwatch.resetAndLog("Scopes creation");
149
150 new TypeConverterBindingProcessor(errors).process(injector, elements);
151 stopwatch.resetAndLog("Converters creation");
152
153 bindInjector(injector);
154 bindLogger(injector);
155 bindingProcessor.process(injector, elements);
156 stopwatch.resetAndLog("Binding creation");
157
158 List<InjectorShell> injectorShells = Lists.newArrayList();
159 injectorShells.add(new InjectorShell(this, elements, injector));
160
161 // recursively build child shells
limpbizkitc3f92842008-12-30 19:43:47 +0000162 PrivateElementProcessor processor = new PrivateElementProcessor(errors, stage);
limpbizkitfcbdf992008-11-26 02:37:35 +0000163 processor.process(injector, elements);
164 for (Builder builder : processor.getInjectorShellBuilders()) {
limpbizkitc3f92842008-12-30 19:43:47 +0000165 injectorShells.addAll(builder.build(initializer, bindingProcessor, stopwatch, errors));
limpbizkitfcbdf992008-11-26 02:37:35 +0000166 }
167 stopwatch.resetAndLog("Private environment creation");
168
169 return injectorShells;
170 }
171
172 private State getState() {
173 if (state == null) {
174 state = new InheritingState(State.NONE);
175 }
176 return state;
177 }
178 }
179
180 /**
181 * The Injector is a special case because we allow both parent and child injectors to both have
182 * a binding for that key.
183 */
184 private static void bindInjector(InjectorImpl injector) {
185 Key<Injector> key = Key.get(Injector.class);
186 InjectorFactory injectorFactory = new InjectorFactory(injector);
187 injector.state.putBinding(key,
188 new ProviderInstanceBindingImpl<Injector>(injector, key, SourceProvider.UNKNOWN_SOURCE,
limpbizkit76c24b12008-12-25 04:32:41 +0000189 injectorFactory, Scoping.UNSCOPED, injectorFactory,
limpbizkitfcbdf992008-11-26 02:37:35 +0000190 ImmutableSet.<InjectionPoint>of()));
191 }
192
193 private static class InjectorFactory implements InternalFactory<Injector>, Provider<Injector> {
194 private final Injector injector;
195
196 private InjectorFactory(Injector injector) {
197 this.injector = injector;
198 }
199
200 public Injector get(Errors errors, InternalContext context, Dependency<?> dependency)
201 throws ErrorsException {
202 return injector;
203 }
204
205 public Injector get() {
206 return injector;
207 }
208
209 public String toString() {
210 return "Provider<Injector>";
211 }
212 }
213
214 /**
215 * The Logger is a special case because it knows the injection point of the injected member. It's
216 * the only binding that does this.
217 */
218 private static void bindLogger(InjectorImpl injector) {
219 Key<Logger> key = Key.get(Logger.class);
220 LoggerFactory loggerFactory = new LoggerFactory();
221 injector.state.putBinding(key,
222 new ProviderInstanceBindingImpl<Logger>(injector, key,
limpbizkit76c24b12008-12-25 04:32:41 +0000223 SourceProvider.UNKNOWN_SOURCE, loggerFactory, Scoping.UNSCOPED,
224 loggerFactory, ImmutableSet.<InjectionPoint>of()));
limpbizkitfcbdf992008-11-26 02:37:35 +0000225 }
226
227 private static class LoggerFactory implements InternalFactory<Logger>, Provider<Logger> {
228 public Logger get(Errors errors, InternalContext context, Dependency<?> dependency) {
229 InjectionPoint injectionPoint = dependency.getInjectionPoint();
230 return injectionPoint == null
231 ? Logger.getAnonymousLogger()
232 : Logger.getLogger(injectionPoint.getMember().getDeclaringClass().getName());
233 }
234
235 public Logger get() {
236 return Logger.getAnonymousLogger();
237 }
238
239 public String toString() {
240 return "Provider<Logger>";
241 }
242 }
243
244 private static class RootModule implements Module {
245 final Stage stage;
246
247 private RootModule(Stage stage) {
248 this.stage = checkNotNull(stage, "stage");
249 }
250
251 public void configure(Binder binder) {
252 binder = binder.withSource(SourceProvider.UNKNOWN_SOURCE);
253 binder.bind(Stage.class).toInstance(stage);
254 binder.bindScope(Singleton.class, SINGLETON);
255 }
256 }
257}