blob: 2b41a1588ca96e51b87a8e8763e3235a2442411a [file] [log] [blame]
crazyboblee66b415a2006-08-25 02:01:19 +00001/**
2 * Copyright (C) 2006 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
crazyboblee7c5b2c42007-01-20 02:05:20 +000019import com.google.inject.util.Objects;
crazybobleeef83bd22007-02-01 00:52:57 +000020import com.google.inject.util.Stopwatch;
crazybobleee3adfd62007-02-02 21:30:08 +000021import com.google.inject.util.ToStringBuilder;
crazyboblee7c5b2c42007-01-20 02:05:20 +000022import static com.google.inject.util.Objects.nonNull;
crazybobleee3adfd62007-02-02 21:30:08 +000023import com.google.inject.spi.ConstructionProxyFactory;
24import com.google.inject.spi.DefaultConstructionProxyFactory;
crazybobleee039bac2007-02-02 21:42:09 +000025import com.google.inject.spi.Message;
crazyboblee7c5b2c42007-01-20 02:05:20 +000026
crazyboblee66b415a2006-08-25 02:01:19 +000027import java.lang.reflect.Member;
28import java.util.ArrayList;
29import java.util.Arrays;
30import java.util.HashMap;
crazyboblee235d0682007-01-31 02:25:21 +000031import java.util.LinkedHashSet;
crazyboblee66b415a2006-08-25 02:01:19 +000032import java.util.List;
33import java.util.Map;
crazyboblee07e41822006-11-21 01:27:08 +000034import java.util.Properties;
crazyboblee7c5b2c42007-01-20 02:05:20 +000035import java.util.Set;
crazyboblee235d0682007-01-31 02:25:21 +000036import java.util.HashSet;
crazyboblee66b415a2006-08-25 02:01:19 +000037import java.util.logging.Logger;
38
39/**
crazyboblee7c5b2c42007-01-20 02:05:20 +000040 * Builds a dependency injection {@link Container}. Binds {@link Key}s to
crazyboblee235d0682007-01-31 02:25:21 +000041 * implementations. A binding implementation could be anything from a constant
42 * value to an object in the HTTP session.
crazyboblee66b415a2006-08-25 02:01:19 +000043 *
crazyboblee7c5b2c42007-01-20 02:05:20 +000044 * <p>Not safe for concurrent use.
45 *
46 * <p>Default bindings include:
crazyboblee66b415a2006-08-25 02:01:19 +000047 *
48 * <ul>
crazyboblee78e1cc12007-01-26 02:18:06 +000049 * <li>A {@code Factory<T>} for each binding of type {@code T}
crazyboblee7c5b2c42007-01-20 02:05:20 +000050 * <li>The {@link Container} iself
51 * <li>The {@link Logger} for the class being injected
crazyboblee66b415a2006-08-25 02:01:19 +000052 * </ul>
53 *
crazyboblee07e41822006-11-21 01:27:08 +000054 * <p>Converts constants as needed from {@code String} to any primitive type
crazyboblee7c5b2c42007-01-20 02:05:20 +000055 * in addition to {@code enum} and {@code Class<?>}.
crazyboblee07e41822006-11-21 01:27:08 +000056 *
crazyboblee66b415a2006-08-25 02:01:19 +000057 * @author crazybob@google.com (Bob Lee)
58 */
59public final class ContainerBuilder {
60
crazyboblee63b592b2007-01-25 02:45:24 +000061 private static final Logger logger =
62 Logger.getLogger(ContainerBuilder.class.getName());
63
crazyboblee7c5b2c42007-01-20 02:05:20 +000064 final List<BindingBuilder<?>> bindingBuilders =
65 new ArrayList<BindingBuilder<?>>();
66 final List<ConstantBindingBuilder> constantBindingBuilders =
67 new ArrayList<ConstantBindingBuilder>();
68 final List<LinkedBindingBuilder<?>> linkedBindingBuilders =
69 new ArrayList<LinkedBindingBuilder<?>>();
crazyboblee63b592b2007-01-25 02:45:24 +000070 final Map<String, Scope> scopes = new HashMap<String, Scope>();
crazyboblee7c5b2c42007-01-20 02:05:20 +000071
crazybobleeef83bd22007-02-01 00:52:57 +000072 final List<StaticInjection> staticInjections =
73 new ArrayList<StaticInjection>();
crazyboblee7c5b2c42007-01-20 02:05:20 +000074
crazybobleea6e73982007-02-02 00:21:07 +000075 ContainerImpl container;
crazyboblee66b415a2006-08-25 02:01:19 +000076
crazyboblee7c5b2c42007-01-20 02:05:20 +000077 /**
78 * Keeps error messages in order and prevents duplicates.
79 */
crazybobleee039bac2007-02-02 21:42:09 +000080 Set<Message> errorMessages = new LinkedHashSet<Message>();
crazyboblee7c5b2c42007-01-20 02:05:20 +000081
crazyboblee66b415a2006-08-25 02:01:19 +000082 private static final InternalFactory<Container> CONTAINER_FACTORY =
83 new InternalFactory<Container>() {
crazyboblee7c5b2c42007-01-20 02:05:20 +000084 public Container get(InternalContext context) {
crazyboblee66b415a2006-08-25 02:01:19 +000085 return context.getContainer();
86 }
87 };
88
89 private static final InternalFactory<Logger> LOGGER_FACTORY =
90 new InternalFactory<Logger>() {
crazyboblee7c5b2c42007-01-20 02:05:20 +000091 public Logger get(InternalContext context) {
crazyboblee66b415a2006-08-25 02:01:19 +000092 Member member = context.getExternalContext().getMember();
93 return member == null ? Logger.getAnonymousLogger()
94 : Logger.getLogger(member.getDeclaringClass().getName());
95 }
96 };
97
crazyboblee7c5b2c42007-01-20 02:05:20 +000098 static final String UNKNOWN_SOURCE = "[unknown source]";
99
crazyboblee63b592b2007-01-25 02:45:24 +0000100 static final Scope DEFAULT_SCOPE = new Scope() {
101 public <T> Factory<T> scope(Key<T> key, Factory<T> creator) {
crazyboblee7289ac12007-02-01 00:28:09 +0000102 // We special case optimize default scope, so this never actually runs.
103 throw new AssertionError();
crazyboblee63b592b2007-01-25 02:45:24 +0000104 }
105 };
106
crazybobleee3adfd62007-02-02 21:30:08 +0000107 final ConstructionProxyFactory constructionProxyFactory;
108
crazyboblee66b415a2006-08-25 02:01:19 +0000109 /**
110 * Constructs a new builder.
crazybobleee3adfd62007-02-02 21:30:08 +0000111 *
112 * @param constructionProxyFactory to use when constructing objects
crazyboblee66b415a2006-08-25 02:01:19 +0000113 */
crazybobleee3adfd62007-02-02 21:30:08 +0000114 public ContainerBuilder(ConstructionProxyFactory constructionProxyFactory) {
crazyboblee2af06372007-02-01 02:07:53 +0000115 put(Scopes.DEFAULT_SCOPE, DEFAULT_SCOPE);
116 put(Scopes.CONTAINER_SCOPE, ContainerScope.INSTANCE);
crazyboblee63b592b2007-01-25 02:45:24 +0000117
crazyboblee7c5b2c42007-01-20 02:05:20 +0000118 bind(Container.class).to(CONTAINER_FACTORY);
119 bind(Logger.class).to(LOGGER_FACTORY);
crazybobleee3adfd62007-02-02 21:30:08 +0000120
121 this.constructionProxyFactory = nonNull(constructionProxyFactory,
122 "construction proxy factory");
123 }
124
125 /**
126 * Constructs a new builder.
127 */
128 public ContainerBuilder() {
129 this(new DefaultConstructionProxyFactory());
crazyboblee66b415a2006-08-25 02:01:19 +0000130 }
131
crazyboblee4727ee22007-01-30 03:13:38 +0000132 final List<Validation> validations = new ArrayList<Validation>();
133
134 /**
135 * Registers a type to be validated for injection when we create the
136 * container.
137 */
138 void validate(final Object source, final Class<?> type) {
139 validations.add(new Validation() {
crazybobleeef83bd22007-02-01 00:52:57 +0000140 public void run(final ContainerImpl container) {
141 container.withErrorHandler(new ConfigurationErrorHandler(source),
142 new Runnable() {
143 public void run() {
144 container.getConstructor(type);
145 }
146 });
crazyboblee4727ee22007-01-30 03:13:38 +0000147 }
148 });
149 }
150
crazyboblee235d0682007-01-31 02:25:21 +0000151 /**
152 * A validation command to run after we create the container but before
153 * we return it to the client.
154 */
crazyboblee4727ee22007-01-30 03:13:38 +0000155 interface Validation {
156 void run(ContainerImpl container);
157 }
158
crazyboblee66b415a2006-08-25 02:01:19 +0000159 /**
crazybobleedac49912007-01-29 23:17:41 +0000160 * Maps a {@link Scope} instance to a given scope name. Scopes should be
161 * mapped before used in bindings. @{@link Scoped#value()} references this
162 * name.
crazyboblee63b592b2007-01-25 02:45:24 +0000163 */
164 public void put(String name, Scope scope) {
165 if (scopes.containsKey(nonNull(name, "name"))) {
crazybobleee039bac2007-02-02 21:42:09 +0000166 addError(source(), ErrorMessages.DUPLICATE_SCOPES, name);
crazyboblee63b592b2007-01-25 02:45:24 +0000167 } else {
crazyboblee235d0682007-01-31 02:25:21 +0000168 scopes.put(nonNull(name, "name"), nonNull(scope, "scope"));
crazyboblee63b592b2007-01-25 02:45:24 +0000169 }
170 }
171
172 /**
crazyboblee7c5b2c42007-01-20 02:05:20 +0000173 * Binds the given key.
174 */
175 public <T> BindingBuilder<T> bind(Key<T> key) {
crazyboblee66b415a2006-08-25 02:01:19 +0000176 ensureNotCreated();
crazyboblee7c5b2c42007-01-20 02:05:20 +0000177 BindingBuilder<T> builder = new BindingBuilder<T>(key).from(source());
178 bindingBuilders.add(builder);
179 return builder;
crazyboblee66b415a2006-08-25 02:01:19 +0000180 }
181
182 /**
crazyboblee7c5b2c42007-01-20 02:05:20 +0000183 * Binds the given type.
crazyboblee66b415a2006-08-25 02:01:19 +0000184 */
crazyboblee0baa9fc2007-01-31 02:38:54 +0000185 public <T> BindingBuilder<T> bind(TypeLiteral<T> typeLiteral) {
186 return bind(Key.get(typeLiteral));
crazyboblee66b415a2006-08-25 02:01:19 +0000187 }
188
189 /**
crazyboblee7c5b2c42007-01-20 02:05:20 +0000190 * Binds the given type.
crazyboblee66b415a2006-08-25 02:01:19 +0000191 */
crazyboblee7c5b2c42007-01-20 02:05:20 +0000192 public <T> BindingBuilder<T> bind(Class<T> clazz) {
193 return bind(Key.get(clazz));
crazyboblee66b415a2006-08-25 02:01:19 +0000194 }
195
196 /**
crazyboblee7c5b2c42007-01-20 02:05:20 +0000197 * Links the given key to another key effectively creating an alias for a
198 * binding.
crazyboblee66b415a2006-08-25 02:01:19 +0000199 */
crazyboblee7c5b2c42007-01-20 02:05:20 +0000200 public <T> LinkedBindingBuilder<T> link(Key<T> key) {
201 ensureNotCreated();
202 LinkedBindingBuilder<T> builder =
203 new LinkedBindingBuilder<T>(key).from(source());
204 linkedBindingBuilders.add(builder);
205 return builder;
crazyboblee66b415a2006-08-25 02:01:19 +0000206 }
207
208 /**
crazyboblee7c5b2c42007-01-20 02:05:20 +0000209 * Binds a constant to the given name.
crazyboblee66b415a2006-08-25 02:01:19 +0000210 */
crazyboblee7c5b2c42007-01-20 02:05:20 +0000211 public ConstantBindingBuilder bind(String name) {
212 ensureNotCreated();
213 return bind(name, source());
crazyboblee66b415a2006-08-25 02:01:19 +0000214 }
215
216 /**
crazyboblee7c5b2c42007-01-20 02:05:20 +0000217 * Binds a constant to the given name from the given source.
crazyboblee66b415a2006-08-25 02:01:19 +0000218 */
crazyboblee7c5b2c42007-01-20 02:05:20 +0000219 private ConstantBindingBuilder bind(String name, Object source) {
220 ConstantBindingBuilder builder =
221 new ConstantBindingBuilder(Objects.nonNull(name, "name")).from(source);
222 constantBindingBuilders.add(builder);
223 return builder;
crazyboblee66b415a2006-08-25 02:01:19 +0000224 }
225
226 /**
crazyboblee63b592b2007-01-25 02:45:24 +0000227 * Binds a string constant for each property.
crazyboblee66b415a2006-08-25 02:01:19 +0000228 */
crazyboblee041e9332007-01-29 22:58:35 +0000229 public void bindProperties(Map<String, String> properties) {
crazyboblee7c5b2c42007-01-20 02:05:20 +0000230 ensureNotCreated();
231 Object source = source();
crazyboblee07e41822006-11-21 01:27:08 +0000232 for (Map.Entry<String, String> entry : properties.entrySet()) {
crazyboblee7c5b2c42007-01-20 02:05:20 +0000233 String key = entry.getKey();
234 String value = entry.getValue();
235 bind(key, source).to(value);
crazyboblee07e41822006-11-21 01:27:08 +0000236 }
crazyboblee07e41822006-11-21 01:27:08 +0000237 }
238
239 /**
crazyboblee63b592b2007-01-25 02:45:24 +0000240 * Binds a string constant for each property.
crazyboblee07e41822006-11-21 01:27:08 +0000241 */
crazyboblee041e9332007-01-29 22:58:35 +0000242 public void bindProperties(Properties properties) {
donald.brown263c5bc2006-11-16 18:39:55 +0000243 ensureNotCreated();
crazyboblee7c5b2c42007-01-20 02:05:20 +0000244 Object source = source();
245 for (Map.Entry<Object, Object> entry : properties.entrySet()) {
246 String key = (String) entry.getKey();
247 String value = (String) entry.getValue();
248 bind(key, source).to(value);
donald.brown263c5bc2006-11-16 18:39:55 +0000249 }
donald.brown263c5bc2006-11-16 18:39:55 +0000250 }
251
252 /**
crazyboblee4776db72007-01-29 23:27:30 +0000253 * Upon successful creation, the {@link Container} will inject static fields
254 * and methods in the given classes.
crazyboblee66b415a2006-08-25 02:01:19 +0000255 *
256 * @param types for which static members will be injected
257 */
crazyboblee4776db72007-01-29 23:27:30 +0000258 public void requestStaticInjection(Class<?>... types) {
crazybobleeef83bd22007-02-01 00:52:57 +0000259 staticInjections.add(new StaticInjection(source(), types));
crazyboblee041e9332007-01-29 22:58:35 +0000260 }
261
262 /**
263 * Applies the given module to this builder.
264 */
265 public void apply(Module module) {
266 module.configure(this);
crazyboblee66b415a2006-08-25 02:01:19 +0000267 }
268
crazyboblee235d0682007-01-31 02:25:21 +0000269 void addError(Object source, String message, Object... arguments) {
270 new ConfigurationErrorHandler(source).handle(message, arguments);
271 }
272
273 void addError(Object source, String message) {
274 new ConfigurationErrorHandler(source).handle(message);
275 }
276
crazyboblee66b415a2006-08-25 02:01:19 +0000277 /**
crazyboblee7c5b2c42007-01-20 02:05:20 +0000278 * Adds an error message to be reported at creation time.
crazyboblee66b415a2006-08-25 02:01:19 +0000279 */
crazybobleee039bac2007-02-02 21:42:09 +0000280 void add(Message errorMessage) {
crazyboblee7c5b2c42007-01-20 02:05:20 +0000281 errorMessages.add(errorMessage);
crazyboblee66b415a2006-08-25 02:01:19 +0000282 }
283
crazyboblee9bb62022007-02-01 00:06:53 +0000284 Stopwatch stopwatch = new Stopwatch();
285
crazyboblee66b415a2006-08-25 02:01:19 +0000286 /**
287 * Creates a {@link Container} instance. Injects static members for classes
crazyboblee4776db72007-01-29 23:27:30 +0000288 * which were registered using {@link #requestStaticInjection(Class...)}.
crazyboblee66b415a2006-08-25 02:01:19 +0000289 *
crazyboblee235d0682007-01-31 02:25:21 +0000290 * @param preload If true, the container will load all container-scoped
291 * bindings now. If false, the container will lazily load them. Eager
292 * loading is appropriate for production use (catch errors early and take
293 * any performance hit up front) while lazy loading can speed development.
294 *
crazyboblee9bb62022007-02-01 00:06:53 +0000295 * @throws ContainerCreationException if configuration errors are found. The
296 * expectation is that the application will log this exception and exit.
crazyboblee66b415a2006-08-25 02:01:19 +0000297 * @throws IllegalStateException if called more than once
298 */
crazyboblee9bb62022007-02-01 00:06:53 +0000299 public synchronized Container create(boolean preload)
300 throws ContainerCreationException {
crazyboblee9bb62022007-02-01 00:06:53 +0000301 stopwatch.resetAndLog(logger, "Configuration");
302
303 // Create the container.
crazybobleea6e73982007-02-02 00:21:07 +0000304 ensureNotCreated();
305 Map<Key<?>, Binding<?>> bindings =
306 new HashMap<Key<?>, Binding<?>>();
crazybobleee3adfd62007-02-02 21:30:08 +0000307 container = new ContainerImpl(constructionProxyFactory, bindings);
crazyboblee7c5b2c42007-01-20 02:05:20 +0000308
crazybobleea6e73982007-02-02 00:21:07 +0000309 createConstantBindings();
crazyboblee7c5b2c42007-01-20 02:05:20 +0000310
crazyboblee9bb62022007-02-01 00:06:53 +0000311 // Commands to execute before returning the Container instance.
crazybobleea6e73982007-02-02 00:21:07 +0000312 final List<ContextualCallable<Void>> preloaders =
313 new ArrayList<ContextualCallable<Void>>();
crazyboblee7c5b2c42007-01-20 02:05:20 +0000314
crazybobleea6e73982007-02-02 00:21:07 +0000315 createBindings(preload, preloaders);
316 createLinkedBindings();
crazyboblee7c5b2c42007-01-20 02:05:20 +0000317
crazyboblee9bb62022007-02-01 00:06:53 +0000318 stopwatch.resetAndLog(logger, "Binding creation");
319
320 // Run validations.
321 for (Validation validation : validations) {
322 validation.run(container);
crazyboblee7c5b2c42007-01-20 02:05:20 +0000323 }
324
crazyboblee9bb62022007-02-01 00:06:53 +0000325 stopwatch.resetAndLog(logger, "Validation");
326
crazybobleeef83bd22007-02-01 00:52:57 +0000327 for (StaticInjection staticInjection : staticInjections) {
328 staticInjection.createInjectors(container);
329 }
330
331 stopwatch.resetAndLog(logger, "Static validation");
332
crazybobleeabc4dd02007-02-01 01:44:36 +0000333 // Blow up if we encountered errors.
crazyboblee9bb62022007-02-01 00:06:53 +0000334 if (!errorMessages.isEmpty()) {
crazybobleee039bac2007-02-02 21:42:09 +0000335 throw new ContainerCreationException(errorMessages);
crazyboblee9bb62022007-02-01 00:06:53 +0000336 }
337
338 // Switch to runtime error handling.
339 container.setErrorHandler(new RuntimeErrorHandler());
340
341 // Inject static members.
crazybobleeef83bd22007-02-01 00:52:57 +0000342 for (StaticInjection staticInjection : staticInjections) {
343 staticInjection.runInjectors(container);
344 }
crazyboblee9bb62022007-02-01 00:06:53 +0000345
346 stopwatch.resetAndLog(logger, "Static member injection");
347
348 // Run preloading commands.
crazybobleeabc4dd02007-02-01 01:44:36 +0000349 runPreloaders(container, preloaders);
crazyboblee9bb62022007-02-01 00:06:53 +0000350
351 stopwatch.resetAndLog(logger, "Preloading");
352
353 return container;
354 }
355
crazybobleeabc4dd02007-02-01 01:44:36 +0000356 private void runPreloaders(ContainerImpl container,
crazybobleea6e73982007-02-02 00:21:07 +0000357 final List<ContextualCallable<Void>> preloaders) {
358 container.callInContext(new ContextualCallable<Void>() {
crazybobleeabc4dd02007-02-01 01:44:36 +0000359 public Void call(InternalContext context) {
crazybobleea6e73982007-02-02 00:21:07 +0000360 for (ContextualCallable<Void> preloader : preloaders) {
crazybobleeabc4dd02007-02-01 01:44:36 +0000361 preloader.call(context);
362 }
363 return null;
364 }
365 });
366 }
367
crazybobleea6e73982007-02-02 00:21:07 +0000368 private void createLinkedBindings() {
crazyboblee7c5b2c42007-01-20 02:05:20 +0000369 for (LinkedBindingBuilder<?> builder : linkedBindingBuilders) {
crazybobleea6e73982007-02-02 00:21:07 +0000370 createLinkedBinding(builder);
crazyboblee7c5b2c42007-01-20 02:05:20 +0000371 }
crazyboblee9bb62022007-02-01 00:06:53 +0000372 }
crazyboblee7c5b2c42007-01-20 02:05:20 +0000373
crazybobleea6e73982007-02-02 00:21:07 +0000374 private <T> void createLinkedBinding(
375 LinkedBindingBuilder<T> builder) {
376 // TODO: Support linking to a later-declared link?
377 Key<? extends T> destinationKey = builder.getDestination();
378 if (destinationKey == null) {
crazybobleee039bac2007-02-02 21:42:09 +0000379 addError(builder.getSource(), ErrorMessages.MISSING_LINK_DESTINATION);
crazybobleea6e73982007-02-02 00:21:07 +0000380 return;
381 }
382
383 Binding<? extends T> destination = getBinding(destinationKey);
384 if (destination == null) {
crazybobleee039bac2007-02-02 21:42:09 +0000385 addError(builder.getSource(), ErrorMessages.LINK_DESTINATION_NOT_FOUND,
crazybobleea6e73982007-02-02 00:21:07 +0000386 destinationKey);
387 return;
388 }
389
390 Binding<?> binding =
391 Binding.newInstance(container, builder.getKey(), builder.getSource(),
392 destination.getInternalFactory());
393
394 putBinding(binding);
395 }
396
397 @SuppressWarnings({"unchecked"})
398 private <T> Binding<T> getBinding(Key<T> destinationKey) {
399 return (Binding<T>) container.internalBindings().get(destinationKey);
400 }
401
402 private void createBindings(boolean preload,
403 List<ContextualCallable<Void>> preloaders) {
crazyboblee9bb62022007-02-01 00:06:53 +0000404 for (BindingBuilder<?> builder : bindingBuilders) {
crazybobleea6e73982007-02-02 00:21:07 +0000405 createBinding(builder, preload, preloaders);
406 }
407 }
crazyboblee4727ee22007-01-30 03:13:38 +0000408
crazybobleea6e73982007-02-02 00:21:07 +0000409 private <T> void createBinding(BindingBuilder<T> builder,
410 boolean preload, List<ContextualCallable<Void>> preloaders) {
411 final Key<T> key = builder.getKey();
412 final InternalFactory<? extends T> factory =
413 builder.getInternalFactory(container);
414 Binding<?> binding = Binding.newInstance(
415 container, key, builder.getSource(), factory);
416
417 putBinding(binding);
418
419 // Register to preload if necessary.
420 if (builder.isInContainerScope()) {
421 if (preload || builder.shouldPreload()) {
422 preloaders.add(new BindingPreloader(key, factory));
423 }
424 } else {
425 if (builder.shouldPreload()) {
crazybobleee039bac2007-02-02 21:42:09 +0000426 addError(builder.getSource(), ErrorMessages.PRELOAD_NOT_ALLOWED);
crazyboblee9bb62022007-02-01 00:06:53 +0000427 }
crazyboblee66b415a2006-08-25 02:01:19 +0000428 }
crazyboblee9bb62022007-02-01 00:06:53 +0000429 }
crazyboblee7c5b2c42007-01-20 02:05:20 +0000430
crazybobleea6e73982007-02-02 00:21:07 +0000431 private void createConstantBindings() {
crazyboblee9bb62022007-02-01 00:06:53 +0000432 for (ConstantBindingBuilder builder : constantBindingBuilders) {
crazybobleea6e73982007-02-02 00:21:07 +0000433 createConstantBinding(builder);
434 }
435 }
436
437 @SuppressWarnings({"unchecked"})
438 private <T> void createConstantBinding(ConstantBindingBuilder builder) {
439 if (builder.hasValue()) {
440 Key<T> key = (Key<T>) builder.getKey();
441 InternalFactory<? extends T> factory =
442 (InternalFactory<? extends T>) builder.getInternalFactory();
443 Binding<?> binding =
444 Binding.newInstance(container, key, builder.getSource(), factory);
445 putBinding(binding);
446 } else {
crazybobleee039bac2007-02-02 21:42:09 +0000447 addError(builder.getSource(), ErrorMessages.MISSING_CONSTANT_VALUE);
crazyboblee9bb62022007-02-01 00:06:53 +0000448 }
crazyboblee66b415a2006-08-25 02:01:19 +0000449 }
450
crazyboblee235d0682007-01-31 02:25:21 +0000451 void putFactory(Object source, Map<Key<?>, InternalFactory<?>> factories,
452 Key<?> key, InternalFactory<?> factory) {
453 if (factories.containsKey(key)) {
crazybobleee039bac2007-02-02 21:42:09 +0000454 addError(source, ErrorMessages.BINDING_ALREADY_SET, key);
crazyboblee235d0682007-01-31 02:25:21 +0000455 } else {
456 factories.put(key, factory);
457 }
458 }
459
crazybobleea6e73982007-02-02 00:21:07 +0000460 void putBinding(Binding<?> binding) {
461 Key<?> key = binding.getKey();
462 Map<Key<?>, Binding<?>> bindings = container.internalBindings();
463 Binding<?> original = bindings.get(key);
464 if (bindings.containsKey(key)) {
crazybobleee039bac2007-02-02 21:42:09 +0000465 addError(binding.getSource(), ErrorMessages.BINDING_ALREADY_SET, key,
crazybobleea6e73982007-02-02 00:21:07 +0000466 original.getSource());
467 } else {
468 bindings.put(key, binding);
469 }
470 }
471
crazyboblee66b415a2006-08-25 02:01:19 +0000472 /**
473 * Currently we only support creating one Container instance per builder.
474 * If we want to support creating more than one container per builder,
475 * we should move to a "factory factory" model where we create a factory
476 * instance per Container. Right now, one factory instance would be
crazyboblee235d0682007-01-31 02:25:21 +0000477 * shared across all the containers, which means container-scoped objects
478 * would be shared, etc.
crazyboblee66b415a2006-08-25 02:01:19 +0000479 */
480 private void ensureNotCreated() {
crazybobleea6e73982007-02-02 00:21:07 +0000481 if (container != null) {
crazyboblee66b415a2006-08-25 02:01:19 +0000482 throw new IllegalStateException("Container already created.");
483 }
484 }
485
486 /**
crazyboblee7c5b2c42007-01-20 02:05:20 +0000487 * Binds a {@link Key} to an implementation in a given scope.
488 */
crazyboblee63b592b2007-01-25 02:45:24 +0000489 public class BindingBuilder<T> {
crazyboblee7c5b2c42007-01-20 02:05:20 +0000490
491 Object source = ContainerBuilder.UNKNOWN_SOURCE;
492 Key<T> key;
493 InternalFactory<? extends T> factory;
494 Scope scope;
crazybobleea6e73982007-02-02 00:21:07 +0000495 String scopeName;
crazybobleeabc4dd02007-02-01 01:44:36 +0000496 boolean preload = false;
crazyboblee7c5b2c42007-01-20 02:05:20 +0000497
498 BindingBuilder(Key<T> key) {
499 this.key = nonNull(key, "key");
500 }
501
crazyboblee235d0682007-01-31 02:25:21 +0000502 Object getSource() {
503 return source;
504 }
505
crazyboblee7c5b2c42007-01-20 02:05:20 +0000506 Key<T> getKey() {
507 return key;
508 }
509
crazyboblee63b592b2007-01-25 02:45:24 +0000510 BindingBuilder<T> from(Object source) {
crazyboblee7c5b2c42007-01-20 02:05:20 +0000511 this.source = source;
512 return this;
513 }
514
515 /**
516 * Sets the name of this binding.
517 */
518 public BindingBuilder<T> named(String name) {
519 if (!this.key.hasDefaultName()) {
crazybobleee039bac2007-02-02 21:42:09 +0000520 addError(source, ErrorMessages.NAME_ALREADY_SET);
crazyboblee7c5b2c42007-01-20 02:05:20 +0000521 }
522
523 this.key = this.key.named(name);
524 return this;
525 }
526
527 /**
528 * Binds to instances of the given implementation class. The {@link
529 * Container} will inject the implementation instances as well. Sets the
530 * scope based on the @{@link Scoped} annotation on the implementation
531 * class if present.
532 */
533 public <I extends T> BindingBuilder<T> to(Class<I> implementation) {
crazyboblee0baa9fc2007-01-31 02:38:54 +0000534 return to(TypeLiteral.get(implementation));
crazyboblee7c5b2c42007-01-20 02:05:20 +0000535 }
536
537 /**
538 * Binds to instances of the given implementation type. The {@link
539 * Container} will inject the implementation instances as well. Sets the
540 * scope based on the @{@link Scoped} annotation on the implementation
541 * class if present.
542 */
crazyboblee0baa9fc2007-01-31 02:38:54 +0000543 public <I extends T> BindingBuilder<T> to(TypeLiteral<I> implementation) {
crazyboblee7c5b2c42007-01-20 02:05:20 +0000544 ensureImplementationIsNotSet();
crazyboblee4727ee22007-01-30 03:13:38 +0000545 validate(source, implementation.getRawType());
crazyboblee7289ac12007-02-01 00:28:09 +0000546 this.factory = new DefaultFactory<I>(key, implementation);
crazyboblee7c5b2c42007-01-20 02:05:20 +0000547 setScopeFromType(implementation.getRawType());
548 return this;
549 }
550
551 private void setScopeFromType(Class<?> implementation) {
552 Scoped scoped = implementation.getAnnotation(Scoped.class);
553 if (scoped != null) {
554 in(scoped.value());
555 }
556 }
557
558 /**
559 * Binds to instances from the given factory.
560 */
561 public BindingBuilder<T> to(
562 final ContextualFactory<? extends T> factory) {
563 ensureImplementationIsNotSet();
564
crazyboblee7289ac12007-02-01 00:28:09 +0000565 this.factory = new InternalToContextualFactoryAdapter<T>(factory);
crazyboblee7c5b2c42007-01-20 02:05:20 +0000566
567 return this;
568 }
569
570 /**
571 * Binds to instances from the given factory.
572 */
573 public BindingBuilder<T> to(final Factory<? extends T> factory) {
574 ensureImplementationIsNotSet();
crazyboblee7289ac12007-02-01 00:28:09 +0000575 this.factory = new InternalFactoryToFactoryAdapter<T>(factory);
crazyboblee7c5b2c42007-01-20 02:05:20 +0000576 return this;
577 }
578
579 /**
580 * Binds to the given instance.
581 */
582 BindingBuilder<T> to(T instance) {
583 ensureImplementationIsNotSet();
584 this.factory = new ConstantFactory<T>(instance);
crazybobleea6e73982007-02-02 00:21:07 +0000585 in(Scopes.CONTAINER_SCOPE);
crazyboblee7c5b2c42007-01-20 02:05:20 +0000586 return this;
587 }
588
589 /**
590 * Binds to instances from the given factory.
591 */
592 BindingBuilder<T> to(final InternalFactory<? extends T> factory) {
593 ensureImplementationIsNotSet();
594 this.factory = factory;
595 return this;
596 }
597
598 /**
599 * Adds an error message if the implementation has already been bound.
600 */
601 private void ensureImplementationIsNotSet() {
602 if (factory != null) {
crazybobleee039bac2007-02-02 21:42:09 +0000603 addError(source, ErrorMessages.IMPLEMENTATION_ALREADY_SET);
crazyboblee7c5b2c42007-01-20 02:05:20 +0000604 }
605 }
606
607 /**
crazyboblee63b592b2007-01-25 02:45:24 +0000608 * Specifies the scope. References the name passed to {@link
609 * ContainerBuilder#put(String, Scope)}.
crazyboblee7c5b2c42007-01-20 02:05:20 +0000610 */
crazyboblee63b592b2007-01-25 02:45:24 +0000611 public BindingBuilder<T> in(String scopeName) {
612 ensureScopeNotSet();
crazyboblee7c5b2c42007-01-20 02:05:20 +0000613
crazyboblee63b592b2007-01-25 02:45:24 +0000614 // We could defer this lookup to when we create the container, but this
615 // is fine for now.
crazyboblee235d0682007-01-31 02:25:21 +0000616 this.scope = scopes.get(nonNull(scopeName, "scope name"));
crazyboblee63b592b2007-01-25 02:45:24 +0000617 if (this.scope == null) {
crazybobleee039bac2007-02-02 21:42:09 +0000618 addError(source, ErrorMessages.SCOPE_NOT_FOUND, scopeName,
crazyboblee235d0682007-01-31 02:25:21 +0000619 scopes.keySet());
crazyboblee63b592b2007-01-25 02:45:24 +0000620 }
crazyboblee7c5b2c42007-01-20 02:05:20 +0000621 return this;
622 }
623
crazyboblee63b592b2007-01-25 02:45:24 +0000624 /**
625 * Specifies the scope.
626 */
627 public BindingBuilder<T> in(Scope scope) {
628 ensureScopeNotSet();
629
630 this.scope = nonNull(scope, "scope");
631 return this;
632 }
633
crazyboblee2af06372007-02-01 02:07:53 +0000634 /**
crazybobleea6e73982007-02-02 00:21:07 +0000635 * Specifies container scope (i.e.&nbsp;one instance per container).
crazyboblee2af06372007-02-01 02:07:53 +0000636 */
637 public BindingBuilder<T> inContainerScope() {
638 return in(Scopes.CONTAINER_SCOPE);
639 }
640
crazyboblee63b592b2007-01-25 02:45:24 +0000641 private void ensureScopeNotSet() {
642 if (this.scope != null) {
crazybobleee039bac2007-02-02 21:42:09 +0000643 addError(source, ErrorMessages.SCOPE_ALREADY_SET);
crazyboblee63b592b2007-01-25 02:45:24 +0000644 }
645 }
646
crazybobleeabc4dd02007-02-01 01:44:36 +0000647 /**
648 * Instructs the builder to eagerly load this binding when it creates
649 * the container. Useful for application initialization logic. Currently
650 * only supported for container-scoped bindings.
651 */
652 public BindingBuilder<T> preload() {
653 this.preload = true;
654 return this;
655 }
656
657 boolean shouldPreload() {
658 return preload;
659 }
660
crazyboblee63b592b2007-01-25 02:45:24 +0000661 InternalFactory<? extends T> getInternalFactory(
662 final ContainerImpl container) {
crazyboblee7c5b2c42007-01-20 02:05:20 +0000663 // If an implementation wasn't specified, use the injection type.
664 if (this.factory == null) {
crazyboblee0baa9fc2007-01-31 02:38:54 +0000665 to(key.getType());
crazyboblee7c5b2c42007-01-20 02:05:20 +0000666 }
667
crazyboblee63b592b2007-01-25 02:45:24 +0000668 if (scope == null || scope == DEFAULT_SCOPE) {
crazyboblee7c5b2c42007-01-20 02:05:20 +0000669 return this.factory;
670 }
671
crazyboblee7289ac12007-02-01 00:28:09 +0000672 Factory<T> scoped = scope.scope(this.key,
673 new FactoryToInternalFactoryAdapter<T>(container, this.factory));
674 return new InternalFactoryToFactoryAdapter<T>(scoped);
crazyboblee7c5b2c42007-01-20 02:05:20 +0000675 }
676
crazyboblee235d0682007-01-31 02:25:21 +0000677 boolean isInContainerScope() {
678 return this.scope == ContainerScope.INSTANCE;
crazyboblee7c5b2c42007-01-20 02:05:20 +0000679 }
crazyboblee7289ac12007-02-01 00:28:09 +0000680 }
crazyboblee7c5b2c42007-01-20 02:05:20 +0000681
crazyboblee7289ac12007-02-01 00:28:09 +0000682 /**
683 * Injects new instances of the specified implementation class.
684 */
685 private static class DefaultFactory<T> implements InternalFactory<T> {
crazyboblee7c5b2c42007-01-20 02:05:20 +0000686
crazybobleee3adfd62007-02-02 21:30:08 +0000687 volatile ConstructorInjector<T> constructor;
crazyboblee7c5b2c42007-01-20 02:05:20 +0000688
crazyboblee7289ac12007-02-01 00:28:09 +0000689 private final TypeLiteral<T> implementation;
690 private final Key<? super T> key;
crazyboblee7c5b2c42007-01-20 02:05:20 +0000691
crazyboblee7289ac12007-02-01 00:28:09 +0000692 public DefaultFactory(Key<? super T> key, TypeLiteral<T> implementation) {
693 this.key = key;
694 this.implementation = implementation;
695 }
696
697 @SuppressWarnings("unchecked")
698 public T get(InternalContext context) {
699 if (constructor == null) {
crazybobleee3adfd62007-02-02 21:30:08 +0000700 this.constructor =
701 context.getContainerImpl().getConstructor(implementation);
crazyboblee7c5b2c42007-01-20 02:05:20 +0000702 }
crazyboblee7289ac12007-02-01 00:28:09 +0000703 return (T) constructor.construct(context, key.getRawType());
704 }
crazyboblee7c5b2c42007-01-20 02:05:20 +0000705
crazyboblee7289ac12007-02-01 00:28:09 +0000706 public String toString() {
crazybobleee3adfd62007-02-02 21:30:08 +0000707 return new ToStringBuilder(Factory.class)
708 .add("implementation", implementation)
709 .toString();
crazyboblee7c5b2c42007-01-20 02:05:20 +0000710 }
711 }
712
713 /**
714 * Builds a constant binding.
715 */
crazyboblee63b592b2007-01-25 02:45:24 +0000716 public class ConstantBindingBuilder {
crazyboblee7c5b2c42007-01-20 02:05:20 +0000717
718 final String name;
719 Class<?> type;
720 Object value;
721 Object source = ContainerBuilder.UNKNOWN_SOURCE;
722
723 ConstantBindingBuilder(String name) {
724 this.name = name;
725 }
726
727 Key<?> getKey() {
728 return Key.get(type, name);
729 }
730
731 boolean hasValue() {
732 return type != null;
733 }
734
735 Object getSource() {
736 return source;
737 }
738
739 InternalFactory<?> getInternalFactory() {
740 return new ConstantFactory<Object>(value);
741 }
742
crazyboblee63b592b2007-01-25 02:45:24 +0000743 ConstantBindingBuilder from(Object source) {
crazyboblee7c5b2c42007-01-20 02:05:20 +0000744 this.source = source;
745 return this;
746 }
747
748 /**
749 * Binds constant to the given value.
750 */
crazyboblee78e1cc12007-01-26 02:18:06 +0000751 public void to(String value) {
752 to(String.class, value);
crazyboblee7c5b2c42007-01-20 02:05:20 +0000753 }
754
755 /**
756 * Binds constant to the given value.
757 */
crazyboblee78e1cc12007-01-26 02:18:06 +0000758 public void to(int value) {
759 to(int.class, value);
crazyboblee7c5b2c42007-01-20 02:05:20 +0000760 }
761
762 /**
763 * Binds constant to the given value.
764 */
crazyboblee78e1cc12007-01-26 02:18:06 +0000765 public void to(long value) {
766 to(long.class, value);
crazyboblee7c5b2c42007-01-20 02:05:20 +0000767 }
768
769 /**
770 * Binds constant to the given value.
771 */
crazyboblee78e1cc12007-01-26 02:18:06 +0000772 public void to(boolean value) {
773 to(boolean.class, value);
crazyboblee7c5b2c42007-01-20 02:05:20 +0000774 }
775
776 /**
777 * Binds constant to the given value.
778 */
crazyboblee78e1cc12007-01-26 02:18:06 +0000779 public void to(double value) {
780 to(double.class, value);
crazyboblee7c5b2c42007-01-20 02:05:20 +0000781 }
782
783 /**
784 * Binds constant to the given value.
785 */
crazyboblee78e1cc12007-01-26 02:18:06 +0000786 public void to(float value) {
787 to(float.class, value);
crazyboblee7c5b2c42007-01-20 02:05:20 +0000788 }
789
790 /**
791 * Binds constant to the given value.
792 */
crazyboblee78e1cc12007-01-26 02:18:06 +0000793 public void to(short value) {
794 to(short.class, value);
crazyboblee7c5b2c42007-01-20 02:05:20 +0000795 }
796
797 /**
798 * Binds constant to the given value.
799 */
crazyboblee78e1cc12007-01-26 02:18:06 +0000800 public void to(char value) {
801 to(char.class, value);
crazyboblee7c5b2c42007-01-20 02:05:20 +0000802 }
803
804 /**
805 * Binds constant to the given value.
806 */
crazyboblee78e1cc12007-01-26 02:18:06 +0000807 public void to(Class<?> value) {
808 to(Class.class, value);
crazyboblee7c5b2c42007-01-20 02:05:20 +0000809 }
810
811 /**
812 * Binds constant to the given value.
813 */
crazyboblee78e1cc12007-01-26 02:18:06 +0000814 public <E extends Enum<E>> void to(E value) {
815 to(value.getDeclaringClass(), value);
crazyboblee7c5b2c42007-01-20 02:05:20 +0000816 }
817
818 /**
819 * Maps a constant value to the given type and name.
820 */
crazyboblee78e1cc12007-01-26 02:18:06 +0000821 <T> void to(final Class<T> type, final T value) {
crazyboblee235d0682007-01-31 02:25:21 +0000822 if (this.value != null) {
crazybobleee039bac2007-02-02 21:42:09 +0000823 addError(source, ErrorMessages.CONSTANT_VALUE_ALREADY_SET);
crazyboblee235d0682007-01-31 02:25:21 +0000824 } else {
825 this.type = type;
826 this.value = value;
827 }
crazyboblee7c5b2c42007-01-20 02:05:20 +0000828 }
829 }
830
831 /**
832 * Links one binding to another.
833 */
crazyboblee63b592b2007-01-25 02:45:24 +0000834 public class LinkedBindingBuilder<T> {
crazyboblee7c5b2c42007-01-20 02:05:20 +0000835
836 Key<T> key;
837 Key<? extends T> destination;
838 Object source = ContainerBuilder.UNKNOWN_SOURCE;
839
840 LinkedBindingBuilder(Key<T> key) {
841 this.key = key;
842 }
843
844 Object getSource() {
845 return source;
846 }
847
848 Key<T> getKey() {
849 return key;
850 }
851
852 Key<? extends T> getDestination() {
853 return destination;
854 }
855
crazyboblee63b592b2007-01-25 02:45:24 +0000856 LinkedBindingBuilder<T> from(Object source) {
crazyboblee7c5b2c42007-01-20 02:05:20 +0000857 this.source = source;
858 return this;
859 }
860
861 /**
862 * Links to another binding with the given key.
863 */
crazyboblee78e1cc12007-01-26 02:18:06 +0000864 public void to(Key<? extends T> destination) {
crazyboblee235d0682007-01-31 02:25:21 +0000865 if (this.destination != null) {
crazybobleee039bac2007-02-02 21:42:09 +0000866 addError(source, ErrorMessages.LINK_DESTINATION_ALREADY_SET);
crazyboblee235d0682007-01-31 02:25:21 +0000867 } else {
868 this.destination = destination;
869 }
crazyboblee7c5b2c42007-01-20 02:05:20 +0000870 }
871 }
crazyboblee4727ee22007-01-30 03:13:38 +0000872
crazyboblee235d0682007-01-31 02:25:21 +0000873 /**
874 * Handles errors up until we successfully create the container.
875 */
876 class ConfigurationErrorHandler extends AbstractErrorHandler {
crazyboblee4727ee22007-01-30 03:13:38 +0000877
878 final Object source;
879
880 ConfigurationErrorHandler(Object source) {
881 this.source = source;
882 }
883
884 public void handle(String message) {
crazybobleee039bac2007-02-02 21:42:09 +0000885 add(new Message(source, message));
crazyboblee4727ee22007-01-30 03:13:38 +0000886 }
887
888 public void handle(Throwable t) {
crazybobleee039bac2007-02-02 21:42:09 +0000889 add(new Message(source, t.getMessage()));
crazyboblee4727ee22007-01-30 03:13:38 +0000890 }
891 }
892
crazyboblee235d0682007-01-31 02:25:21 +0000893 /**
894 * Handles errors after the container is created.
895 */
896 class RuntimeErrorHandler extends AbstractErrorHandler {
crazyboblee4727ee22007-01-30 03:13:38 +0000897
898 public void handle(String message) {
899 throw new ConfigurationException(message);
900 }
901
902 public void handle(Throwable t) {
903 throw new ConfigurationException(t);
904 }
905 }
crazyboblee235d0682007-01-31 02:25:21 +0000906
907 final Set<String> skippedClassNames = new HashSet<String>(Arrays.asList(
908 ContainerBuilder.class.getName(),
909 AbstractModule.class.getName()
910 ));
911
912 /**
913 * Instructs the builder to skip the given class in the stack trace when
914 * determining the source of a binding. Use this to keep the container
915 * builder from logging utility methods as the sources of bindings (i.e.
916 * it will skip to the utility methods' callers instead).
917 *
918 * <p>Skipping only takes place after this method is called.
919 */
920 void skipSource(Class<?> clazz) {
921 skippedClassNames.add(clazz.getName());
922 }
923
924 /**
925 * Creates an object pointing to the current location within the
926 * configuration. If we run into a problem later, we'll be able to trace it
927 * back to the original source. Useful for debugging. The default
928 * implementation returns {@code ContainerBuilder}'s caller's {@code
929 * StackTraceElement}.
930 */
931 Object source() {
932 // Search up the stack until we find a class outside of this one.
933 for (final StackTraceElement element : new Throwable().getStackTrace()) {
934 String className = element.getClassName();
935 if (!skippedClassNames.contains(className)) {
936 return element;
937 }
938 }
939 throw new AssertionError();
940 }
crazybobleeef83bd22007-02-01 00:52:57 +0000941
942 /**
943 * A requested static injection.
944 */
945 class StaticInjection {
946
947 final Object source;
948 final Class<?>[] types;
949 final List<ContainerImpl.Injector> injectors =
950 new ArrayList<ContainerImpl.Injector>();
951
952 public StaticInjection(Object source, Class<?>[] types) {
953 this.source = source;
954 this.types = types;
955 }
956
957 void createInjectors(final ContainerImpl container) {
958 container.withErrorHandler(new ConfigurationErrorHandler(source),
959 new Runnable() {
960 public void run() {
961 for (Class<?> clazz : types) {
962 container.addInjectorsForFields(
963 clazz.getDeclaredFields(), true, injectors);
964 container.addInjectorsForMethods(
965 clazz.getDeclaredMethods(), true, injectors);
966 }
967 }
968 });
969 }
970
971 void runInjectors(ContainerImpl container) {
crazybobleea6e73982007-02-02 00:21:07 +0000972 container.callInContext(new ContextualCallable<Void>() {
crazybobleeef83bd22007-02-01 00:52:57 +0000973 public Void call(InternalContext context) {
974 for (ContainerImpl.Injector injector : injectors) {
975 injector.inject(context, null);
976 }
977 return null;
978 }
979 });
980 }
981 }
crazybobleeabc4dd02007-02-01 01:44:36 +0000982
983 static class BindingPreloader
crazybobleea6e73982007-02-02 00:21:07 +0000984 implements ContextualCallable<Void> {
crazybobleeabc4dd02007-02-01 01:44:36 +0000985
986 private final Key<?> key;
987 private final InternalFactory<?> factory;
988
989 public BindingPreloader(Key<?> key, InternalFactory<?> factory) {
990 this.key = key;
991 this.factory = factory;
992 }
993
994 public Void call(InternalContext context) {
995 ExternalContext<?> externalContext =
996 ExternalContext.newInstance(null, key, context.getContainerImpl());
997 context.setExternalContext(externalContext);
998 try {
999 factory.get(context);
1000 return null;
1001 } finally {
1002 context.setExternalContext(null);
1003 }
1004 }
1005 }
crazyboblee66b415a2006-08-25 02:01:19 +00001006}