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