blob: ac6466240bc6fec5e6b80a74a881e8b68a03ac3e [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
crazybobleee3adfd62007-02-02 21:30:08 +000019import com.google.inject.spi.ConstructionProxyFactory;
20import com.google.inject.spi.DefaultConstructionProxyFactory;
crazybobleee039bac2007-02-02 21:42:09 +000021import com.google.inject.spi.Message;
crazybobleeb7598a62007-02-03 03:13:34 +000022import com.google.inject.spi.SourceConsumer;
23import com.google.inject.util.Objects;
24import static com.google.inject.util.Objects.nonNull;
25import com.google.inject.util.Stopwatch;
26import com.google.inject.util.ToStringBuilder;
crazybobleee5fbbb02007-02-05 07:00:27 +000027import static com.google.inject.Scopes.*;
crazyboblee7c5b2c42007-01-20 02:05:20 +000028
crazyboblee66b415a2006-08-25 02:01:19 +000029import java.lang.reflect.Member;
crazybobleee5fbbb02007-02-05 07:00:27 +000030import java.lang.annotation.Annotation;
crazyboblee66b415a2006-08-25 02:01:19 +000031import java.util.ArrayList;
crazyboblee66b415a2006-08-25 02:01:19 +000032import java.util.HashMap;
crazyboblee235d0682007-01-31 02:25:21 +000033import java.util.LinkedHashSet;
crazyboblee66b415a2006-08-25 02:01:19 +000034import java.util.List;
35import java.util.Map;
crazyboblee07e41822006-11-21 01:27:08 +000036import java.util.Properties;
crazyboblee7c5b2c42007-01-20 02:05:20 +000037import java.util.Set;
crazyboblee66b415a2006-08-25 02:01:19 +000038import java.util.logging.Logger;
39
40/**
crazyboblee7c5b2c42007-01-20 02:05:20 +000041 * Builds a dependency injection {@link Container}. Binds {@link Key}s to
crazyboblee235d0682007-01-31 02:25:21 +000042 * implementations. A binding implementation could be anything from a constant
43 * value to an object in the HTTP session.
crazyboblee66b415a2006-08-25 02:01:19 +000044 *
crazyboblee7c5b2c42007-01-20 02:05:20 +000045 * <p>Not safe for concurrent use.
46 *
47 * <p>Default bindings include:
crazyboblee66b415a2006-08-25 02:01:19 +000048 *
49 * <ul>
crazyboblee78e1cc12007-01-26 02:18:06 +000050 * <li>A {@code Factory<T>} for each binding of type {@code T}
crazyboblee7c5b2c42007-01-20 02:05:20 +000051 * <li>The {@link Container} iself
52 * <li>The {@link Logger} for the class being injected
crazyboblee66b415a2006-08-25 02:01:19 +000053 * </ul>
54 *
crazyboblee07e41822006-11-21 01:27:08 +000055 * <p>Converts constants as needed from {@code String} to any primitive type
crazyboblee7c5b2c42007-01-20 02:05:20 +000056 * in addition to {@code enum} and {@code Class<?>}.
crazyboblee07e41822006-11-21 01:27:08 +000057 *
crazyboblee66b415a2006-08-25 02:01:19 +000058 * @author crazybob@google.com (Bob Lee)
59 */
crazybobleeb7598a62007-02-03 03:13:34 +000060public final class ContainerBuilder extends SourceConsumer {
crazyboblee66b415a2006-08-25 02:01:19 +000061
crazyboblee63b592b2007-01-25 02:45:24 +000062 private static final Logger logger =
63 Logger.getLogger(ContainerBuilder.class.getName());
64
crazyboblee7c5b2c42007-01-20 02:05:20 +000065 final List<BindingBuilder<?>> bindingBuilders =
66 new ArrayList<BindingBuilder<?>>();
67 final List<ConstantBindingBuilder> constantBindingBuilders =
68 new ArrayList<ConstantBindingBuilder>();
69 final List<LinkedBindingBuilder<?>> linkedBindingBuilders =
70 new ArrayList<LinkedBindingBuilder<?>>();
crazyboblee63b592b2007-01-25 02:45:24 +000071 final Map<String, Scope> scopes = new HashMap<String, Scope>();
crazyboblee7c5b2c42007-01-20 02:05:20 +000072
crazybobleeef83bd22007-02-01 00:52:57 +000073 final List<StaticInjection> staticInjections =
74 new ArrayList<StaticInjection>();
crazyboblee7c5b2c42007-01-20 02:05:20 +000075
crazybobleea6e73982007-02-02 00:21:07 +000076 ContainerImpl container;
crazyboblee66b415a2006-08-25 02:01:19 +000077
crazyboblee7c5b2c42007-01-20 02:05:20 +000078 /**
79 * Keeps error messages in order and prevents duplicates.
80 */
crazybobleee039bac2007-02-02 21:42:09 +000081 Set<Message> errorMessages = new LinkedHashSet<Message>();
crazyboblee7c5b2c42007-01-20 02:05:20 +000082
crazyboblee66b415a2006-08-25 02:01:19 +000083 private static final InternalFactory<Container> CONTAINER_FACTORY =
84 new InternalFactory<Container>() {
crazyboblee7c5b2c42007-01-20 02:05:20 +000085 public Container get(InternalContext context) {
crazyboblee66b415a2006-08-25 02:01:19 +000086 return context.getContainer();
87 }
88 };
89
90 private static final InternalFactory<Logger> LOGGER_FACTORY =
91 new InternalFactory<Logger>() {
crazyboblee7c5b2c42007-01-20 02:05:20 +000092 public Logger get(InternalContext context) {
crazyboblee66b415a2006-08-25 02:01:19 +000093 Member member = context.getExternalContext().getMember();
94 return member == null ? Logger.getAnonymousLogger()
95 : Logger.getLogger(member.getDeclaringClass().getName());
96 }
97 };
98
crazyboblee7c5b2c42007-01-20 02:05:20 +000099 static final String UNKNOWN_SOURCE = "[unknown source]";
100
crazybobleee3adfd62007-02-02 21:30:08 +0000101 final ConstructionProxyFactory constructionProxyFactory;
102
crazyboblee66b415a2006-08-25 02:01:19 +0000103 /**
104 * Constructs a new builder.
crazybobleee3adfd62007-02-02 21:30:08 +0000105 *
106 * @param constructionProxyFactory to use when constructing objects
crazyboblee66b415a2006-08-25 02:01:19 +0000107 */
crazybobleee3adfd62007-02-02 21:30:08 +0000108 public ContainerBuilder(ConstructionProxyFactory constructionProxyFactory) {
crazyboblee68d2f4b2007-02-07 18:47:24 +0000109 scope(DEFAULT_NAME, DEFAULT);
110 scope(CONTAINER_NAME, CONTAINER);
crazyboblee63b592b2007-01-25 02:45:24 +0000111
crazyboblee7c5b2c42007-01-20 02:05:20 +0000112 bind(Container.class).to(CONTAINER_FACTORY);
113 bind(Logger.class).to(LOGGER_FACTORY);
crazybobleee3adfd62007-02-02 21:30:08 +0000114
115 this.constructionProxyFactory = nonNull(constructionProxyFactory,
116 "construction proxy factory");
117 }
118
119 /**
120 * Constructs a new builder.
121 */
122 public ContainerBuilder() {
123 this(new DefaultConstructionProxyFactory());
crazyboblee66b415a2006-08-25 02:01:19 +0000124 }
125
crazyboblee4727ee22007-01-30 03:13:38 +0000126 final List<Validation> validations = new ArrayList<Validation>();
127
128 /**
129 * Registers a type to be validated for injection when we create the
130 * container.
131 */
132 void validate(final Object source, final Class<?> type) {
133 validations.add(new Validation() {
crazybobleeef83bd22007-02-01 00:52:57 +0000134 public void run(final ContainerImpl container) {
135 container.withErrorHandler(new ConfigurationErrorHandler(source),
136 new Runnable() {
137 public void run() {
138 container.getConstructor(type);
139 }
140 });
crazyboblee4727ee22007-01-30 03:13:38 +0000141 }
142 });
143 }
144
crazyboblee235d0682007-01-31 02:25:21 +0000145 /**
146 * A validation command to run after we create the container but before
147 * we return it to the client.
148 */
crazyboblee4727ee22007-01-30 03:13:38 +0000149 interface Validation {
150 void run(ContainerImpl container);
151 }
152
crazyboblee66b415a2006-08-25 02:01:19 +0000153 /**
crazybobleee5fbbb02007-02-05 07:00:27 +0000154 * Adds a new scope. Maps a {@link Scope} instance to a given scope name.
155 * Scopes should be mapped before used in bindings. {@link Scoped#value()}
156 * references this name.
crazyboblee63b592b2007-01-25 02:45:24 +0000157 */
crazybobleee5fbbb02007-02-05 07:00:27 +0000158 public void scope(String name, Scope scope) {
crazyboblee63b592b2007-01-25 02:45:24 +0000159 if (scopes.containsKey(nonNull(name, "name"))) {
crazybobleee039bac2007-02-02 21:42:09 +0000160 addError(source(), ErrorMessages.DUPLICATE_SCOPES, name);
crazyboblee63b592b2007-01-25 02:45:24 +0000161 } else {
crazyboblee235d0682007-01-31 02:25:21 +0000162 scopes.put(nonNull(name, "name"), nonNull(scope, "scope"));
crazyboblee63b592b2007-01-25 02:45:24 +0000163 }
164 }
165
166 /**
crazyboblee7c5b2c42007-01-20 02:05:20 +0000167 * Binds the given key.
168 */
169 public <T> BindingBuilder<T> bind(Key<T> key) {
crazyboblee66b415a2006-08-25 02:01:19 +0000170 ensureNotCreated();
crazyboblee7c5b2c42007-01-20 02:05:20 +0000171 BindingBuilder<T> builder = new BindingBuilder<T>(key).from(source());
172 bindingBuilders.add(builder);
173 return builder;
crazyboblee66b415a2006-08-25 02:01:19 +0000174 }
175
176 /**
crazyboblee7c5b2c42007-01-20 02:05:20 +0000177 * Binds the given type.
crazyboblee66b415a2006-08-25 02:01:19 +0000178 */
crazyboblee0baa9fc2007-01-31 02:38:54 +0000179 public <T> BindingBuilder<T> bind(TypeLiteral<T> typeLiteral) {
180 return bind(Key.get(typeLiteral));
crazyboblee66b415a2006-08-25 02:01:19 +0000181 }
182
183 /**
crazyboblee7c5b2c42007-01-20 02:05:20 +0000184 * Binds the given type.
crazyboblee66b415a2006-08-25 02:01:19 +0000185 */
crazyboblee7c5b2c42007-01-20 02:05:20 +0000186 public <T> BindingBuilder<T> bind(Class<T> clazz) {
187 return bind(Key.get(clazz));
crazyboblee66b415a2006-08-25 02:01:19 +0000188 }
189
190 /**
crazyboblee7c5b2c42007-01-20 02:05:20 +0000191 * Links the given key to another key effectively creating an alias for a
192 * binding.
crazyboblee66b415a2006-08-25 02:01:19 +0000193 */
crazyboblee7c5b2c42007-01-20 02:05:20 +0000194 public <T> LinkedBindingBuilder<T> link(Key<T> key) {
195 ensureNotCreated();
196 LinkedBindingBuilder<T> builder =
197 new LinkedBindingBuilder<T>(key).from(source());
198 linkedBindingBuilders.add(builder);
199 return builder;
crazyboblee66b415a2006-08-25 02:01:19 +0000200 }
201
202 /**
crazyboblee7c5b2c42007-01-20 02:05:20 +0000203 * Binds a constant to the given name.
crazyboblee66b415a2006-08-25 02:01:19 +0000204 */
crazyboblee7c5b2c42007-01-20 02:05:20 +0000205 public ConstantBindingBuilder bind(String name) {
206 ensureNotCreated();
207 return bind(name, source());
crazyboblee66b415a2006-08-25 02:01:19 +0000208 }
209
210 /**
crazyboblee7c5b2c42007-01-20 02:05:20 +0000211 * Binds a constant to the given name from the given source.
crazyboblee66b415a2006-08-25 02:01:19 +0000212 */
crazyboblee7c5b2c42007-01-20 02:05:20 +0000213 private ConstantBindingBuilder bind(String name, Object source) {
214 ConstantBindingBuilder builder =
215 new ConstantBindingBuilder(Objects.nonNull(name, "name")).from(source);
216 constantBindingBuilders.add(builder);
217 return builder;
crazyboblee66b415a2006-08-25 02:01:19 +0000218 }
219
220 /**
crazyboblee63b592b2007-01-25 02:45:24 +0000221 * Binds a string constant for each property.
crazyboblee66b415a2006-08-25 02:01:19 +0000222 */
crazyboblee041e9332007-01-29 22:58:35 +0000223 public void bindProperties(Map<String, String> properties) {
crazyboblee7c5b2c42007-01-20 02:05:20 +0000224 ensureNotCreated();
225 Object source = source();
crazyboblee07e41822006-11-21 01:27:08 +0000226 for (Map.Entry<String, String> entry : properties.entrySet()) {
crazyboblee7c5b2c42007-01-20 02:05:20 +0000227 String key = entry.getKey();
228 String value = entry.getValue();
229 bind(key, source).to(value);
crazyboblee07e41822006-11-21 01:27:08 +0000230 }
crazyboblee07e41822006-11-21 01:27:08 +0000231 }
232
233 /**
crazyboblee63b592b2007-01-25 02:45:24 +0000234 * Binds a string constant for each property.
crazyboblee07e41822006-11-21 01:27:08 +0000235 */
crazyboblee041e9332007-01-29 22:58:35 +0000236 public void bindProperties(Properties properties) {
donald.brown263c5bc2006-11-16 18:39:55 +0000237 ensureNotCreated();
crazyboblee7c5b2c42007-01-20 02:05:20 +0000238 Object source = source();
239 for (Map.Entry<Object, Object> entry : properties.entrySet()) {
240 String key = (String) entry.getKey();
241 String value = (String) entry.getValue();
242 bind(key, source).to(value);
donald.brown263c5bc2006-11-16 18:39:55 +0000243 }
donald.brown263c5bc2006-11-16 18:39:55 +0000244 }
245
246 /**
crazyboblee4776db72007-01-29 23:27:30 +0000247 * Upon successful creation, the {@link Container} will inject static fields
248 * and methods in the given classes.
crazyboblee66b415a2006-08-25 02:01:19 +0000249 *
250 * @param types for which static members will be injected
251 */
crazyboblee4776db72007-01-29 23:27:30 +0000252 public void requestStaticInjection(Class<?>... types) {
crazybobleeef83bd22007-02-01 00:52:57 +0000253 staticInjections.add(new StaticInjection(source(), types));
crazyboblee041e9332007-01-29 22:58:35 +0000254 }
255
256 /**
257 * Applies the given module to this builder.
258 */
crazybobleea3796012007-02-03 11:43:40 +0000259 public void install(Module module) {
crazyboblee041e9332007-01-29 22:58:35 +0000260 module.configure(this);
crazyboblee66b415a2006-08-25 02:01:19 +0000261 }
262
crazyboblee235d0682007-01-31 02:25:21 +0000263 void addError(Object source, String message, Object... arguments) {
264 new ConfigurationErrorHandler(source).handle(message, arguments);
265 }
266
267 void addError(Object source, String message) {
268 new ConfigurationErrorHandler(source).handle(message);
269 }
270
crazyboblee66b415a2006-08-25 02:01:19 +0000271 /**
crazyboblee7c5b2c42007-01-20 02:05:20 +0000272 * Adds an error message to be reported at creation time.
crazyboblee66b415a2006-08-25 02:01:19 +0000273 */
crazybobleee039bac2007-02-02 21:42:09 +0000274 void add(Message errorMessage) {
crazyboblee7c5b2c42007-01-20 02:05:20 +0000275 errorMessages.add(errorMessage);
crazyboblee66b415a2006-08-25 02:01:19 +0000276 }
277
crazyboblee9bb62022007-02-01 00:06:53 +0000278 Stopwatch stopwatch = new Stopwatch();
279
crazyboblee66b415a2006-08-25 02:01:19 +0000280 /**
281 * Creates a {@link Container} instance. Injects static members for classes
crazyboblee4776db72007-01-29 23:27:30 +0000282 * which were registered using {@link #requestStaticInjection(Class...)}.
crazyboblee66b415a2006-08-25 02:01:19 +0000283 *
crazyboblee235d0682007-01-31 02:25:21 +0000284 * @param preload If true, the container will load all container-scoped
285 * bindings now. If false, the container will lazily load them. Eager
286 * loading is appropriate for production use (catch errors early and take
287 * any performance hit up front) while lazy loading can speed development.
288 *
crazyboblee9bb62022007-02-01 00:06:53 +0000289 * @throws ContainerCreationException if configuration errors are found. The
290 * expectation is that the application will log this exception and exit.
crazyboblee66b415a2006-08-25 02:01:19 +0000291 * @throws IllegalStateException if called more than once
292 */
crazyboblee9bb62022007-02-01 00:06:53 +0000293 public synchronized Container create(boolean preload)
294 throws ContainerCreationException {
crazyboblee9bb62022007-02-01 00:06:53 +0000295 stopwatch.resetAndLog(logger, "Configuration");
296
297 // Create the container.
crazybobleea6e73982007-02-02 00:21:07 +0000298 ensureNotCreated();
299 Map<Key<?>, Binding<?>> bindings =
300 new HashMap<Key<?>, Binding<?>>();
crazybobleee3adfd62007-02-02 21:30:08 +0000301 container = new ContainerImpl(constructionProxyFactory, bindings);
crazyboblee7c5b2c42007-01-20 02:05:20 +0000302
crazybobleea6e73982007-02-02 00:21:07 +0000303 createConstantBindings();
crazyboblee7c5b2c42007-01-20 02:05:20 +0000304
crazyboblee9bb62022007-02-01 00:06:53 +0000305 // Commands to execute before returning the Container instance.
crazybobleea6e73982007-02-02 00:21:07 +0000306 final List<ContextualCallable<Void>> preloaders =
307 new ArrayList<ContextualCallable<Void>>();
crazyboblee7c5b2c42007-01-20 02:05:20 +0000308
crazybobleea6e73982007-02-02 00:21:07 +0000309 createBindings(preload, preloaders);
310 createLinkedBindings();
crazyboblee7c5b2c42007-01-20 02:05:20 +0000311
crazyboblee07bd1592007-02-03 07:18:51 +0000312 stopwatch.resetAndLog(logger, "Binding creation");
313
crazyboblee62fcdde2007-02-03 02:10:13 +0000314 container.index();
315
crazyboblee07bd1592007-02-03 07:18:51 +0000316 stopwatch.resetAndLog(logger, "Binding indexing");
crazyboblee9bb62022007-02-01 00:06:53 +0000317
318 // Run validations.
319 for (Validation validation : validations) {
320 validation.run(container);
crazyboblee7c5b2c42007-01-20 02:05:20 +0000321 }
322
crazyboblee9bb62022007-02-01 00:06:53 +0000323 stopwatch.resetAndLog(logger, "Validation");
324
crazybobleeef83bd22007-02-01 00:52:57 +0000325 for (StaticInjection staticInjection : staticInjections) {
326 staticInjection.createInjectors(container);
327 }
328
329 stopwatch.resetAndLog(logger, "Static validation");
330
crazybobleeabc4dd02007-02-01 01:44:36 +0000331 // Blow up if we encountered errors.
crazyboblee9bb62022007-02-01 00:06:53 +0000332 if (!errorMessages.isEmpty()) {
crazybobleee039bac2007-02-02 21:42:09 +0000333 throw new ContainerCreationException(errorMessages);
crazyboblee9bb62022007-02-01 00:06:53 +0000334 }
335
336 // Switch to runtime error handling.
337 container.setErrorHandler(new RuntimeErrorHandler());
338
339 // Inject static members.
crazybobleeef83bd22007-02-01 00:52:57 +0000340 for (StaticInjection staticInjection : staticInjections) {
341 staticInjection.runInjectors(container);
342 }
crazyboblee9bb62022007-02-01 00:06:53 +0000343
344 stopwatch.resetAndLog(logger, "Static member injection");
345
346 // Run preloading commands.
crazybobleeabc4dd02007-02-01 01:44:36 +0000347 runPreloaders(container, preloaders);
crazyboblee9bb62022007-02-01 00:06:53 +0000348
349 stopwatch.resetAndLog(logger, "Preloading");
350
351 return container;
352 }
353
crazybobleeabc4dd02007-02-01 01:44:36 +0000354 private void runPreloaders(ContainerImpl container,
crazybobleea6e73982007-02-02 00:21:07 +0000355 final List<ContextualCallable<Void>> preloaders) {
356 container.callInContext(new ContextualCallable<Void>() {
crazybobleeabc4dd02007-02-01 01:44:36 +0000357 public Void call(InternalContext context) {
crazybobleea6e73982007-02-02 00:21:07 +0000358 for (ContextualCallable<Void> preloader : preloaders) {
crazybobleeabc4dd02007-02-01 01:44:36 +0000359 preloader.call(context);
360 }
361 return null;
362 }
363 });
364 }
365
crazybobleea6e73982007-02-02 00:21:07 +0000366 private void createLinkedBindings() {
crazyboblee7c5b2c42007-01-20 02:05:20 +0000367 for (LinkedBindingBuilder<?> builder : linkedBindingBuilders) {
crazybobleea6e73982007-02-02 00:21:07 +0000368 createLinkedBinding(builder);
crazyboblee7c5b2c42007-01-20 02:05:20 +0000369 }
crazyboblee9bb62022007-02-01 00:06:53 +0000370 }
crazyboblee7c5b2c42007-01-20 02:05:20 +0000371
crazybobleea6e73982007-02-02 00:21:07 +0000372 private <T> void createLinkedBinding(
373 LinkedBindingBuilder<T> builder) {
374 // TODO: Support linking to a later-declared link?
375 Key<? extends T> destinationKey = builder.getDestination();
376 if (destinationKey == null) {
crazybobleee039bac2007-02-02 21:42:09 +0000377 addError(builder.getSource(), ErrorMessages.MISSING_LINK_DESTINATION);
crazybobleea6e73982007-02-02 00:21:07 +0000378 return;
379 }
380
381 Binding<? extends T> destination = getBinding(destinationKey);
382 if (destination == null) {
crazybobleee039bac2007-02-02 21:42:09 +0000383 addError(builder.getSource(), ErrorMessages.LINK_DESTINATION_NOT_FOUND,
crazybobleea6e73982007-02-02 00:21:07 +0000384 destinationKey);
385 return;
386 }
387
388 Binding<?> binding =
389 Binding.newInstance(container, builder.getKey(), builder.getSource(),
390 destination.getInternalFactory());
391
392 putBinding(binding);
393 }
394
395 @SuppressWarnings({"unchecked"})
396 private <T> Binding<T> getBinding(Key<T> destinationKey) {
397 return (Binding<T>) container.internalBindings().get(destinationKey);
398 }
399
400 private void createBindings(boolean preload,
401 List<ContextualCallable<Void>> preloaders) {
crazyboblee9bb62022007-02-01 00:06:53 +0000402 for (BindingBuilder<?> builder : bindingBuilders) {
crazybobleea6e73982007-02-02 00:21:07 +0000403 createBinding(builder, preload, preloaders);
404 }
405 }
crazyboblee4727ee22007-01-30 03:13:38 +0000406
crazybobleea6e73982007-02-02 00:21:07 +0000407 private <T> void createBinding(BindingBuilder<T> builder,
408 boolean preload, List<ContextualCallable<Void>> preloaders) {
409 final Key<T> key = builder.getKey();
410 final InternalFactory<? extends T> factory =
411 builder.getInternalFactory(container);
412 Binding<?> binding = Binding.newInstance(
413 container, key, builder.getSource(), factory);
414
415 putBinding(binding);
416
417 // Register to preload if necessary.
crazybobleee5fbbb02007-02-05 07:00:27 +0000418 if (builder.isContainerScoped()) {
crazybobleea6e73982007-02-02 00:21:07 +0000419 if (preload || builder.shouldPreload()) {
420 preloaders.add(new BindingPreloader(key, factory));
421 }
422 } else {
423 if (builder.shouldPreload()) {
crazybobleee039bac2007-02-02 21:42:09 +0000424 addError(builder.getSource(), ErrorMessages.PRELOAD_NOT_ALLOWED);
crazyboblee9bb62022007-02-01 00:06:53 +0000425 }
crazyboblee66b415a2006-08-25 02:01:19 +0000426 }
crazyboblee9bb62022007-02-01 00:06:53 +0000427 }
crazyboblee7c5b2c42007-01-20 02:05:20 +0000428
crazybobleea6e73982007-02-02 00:21:07 +0000429 private void createConstantBindings() {
crazyboblee9bb62022007-02-01 00:06:53 +0000430 for (ConstantBindingBuilder builder : constantBindingBuilders) {
crazybobleea6e73982007-02-02 00:21:07 +0000431 createConstantBinding(builder);
432 }
433 }
434
435 @SuppressWarnings({"unchecked"})
436 private <T> void createConstantBinding(ConstantBindingBuilder builder) {
437 if (builder.hasValue()) {
438 Key<T> key = (Key<T>) builder.getKey();
439 InternalFactory<? extends T> factory =
440 (InternalFactory<? extends T>) builder.getInternalFactory();
441 Binding<?> binding =
442 Binding.newInstance(container, key, builder.getSource(), factory);
443 putBinding(binding);
444 } else {
crazybobleee039bac2007-02-02 21:42:09 +0000445 addError(builder.getSource(), ErrorMessages.MISSING_CONSTANT_VALUE);
crazyboblee9bb62022007-02-01 00:06:53 +0000446 }
crazyboblee66b415a2006-08-25 02:01:19 +0000447 }
448
crazyboblee235d0682007-01-31 02:25:21 +0000449 void putFactory(Object source, Map<Key<?>, InternalFactory<?>> factories,
450 Key<?> key, InternalFactory<?> factory) {
451 if (factories.containsKey(key)) {
crazybobleee039bac2007-02-02 21:42:09 +0000452 addError(source, ErrorMessages.BINDING_ALREADY_SET, key);
crazyboblee235d0682007-01-31 02:25:21 +0000453 } else {
454 factories.put(key, factory);
455 }
456 }
457
crazybobleea6e73982007-02-02 00:21:07 +0000458 void putBinding(Binding<?> binding) {
459 Key<?> key = binding.getKey();
460 Map<Key<?>, Binding<?>> bindings = container.internalBindings();
461 Binding<?> original = bindings.get(key);
462 if (bindings.containsKey(key)) {
crazybobleee039bac2007-02-02 21:42:09 +0000463 addError(binding.getSource(), ErrorMessages.BINDING_ALREADY_SET, key,
crazybobleea6e73982007-02-02 00:21:07 +0000464 original.getSource());
465 } else {
466 bindings.put(key, binding);
467 }
468 }
469
crazyboblee66b415a2006-08-25 02:01:19 +0000470 /**
471 * Currently we only support creating one Container instance per builder.
472 * If we want to support creating more than one container per builder,
473 * we should move to a "factory factory" model where we create a factory
474 * instance per Container. Right now, one factory instance would be
crazyboblee235d0682007-01-31 02:25:21 +0000475 * shared across all the containers, which means container-scoped objects
476 * would be shared, etc.
crazyboblee66b415a2006-08-25 02:01:19 +0000477 */
478 private void ensureNotCreated() {
crazybobleea6e73982007-02-02 00:21:07 +0000479 if (container != null) {
crazyboblee66b415a2006-08-25 02:01:19 +0000480 throw new IllegalStateException("Container already created.");
481 }
482 }
483
484 /**
crazyboblee7c5b2c42007-01-20 02:05:20 +0000485 * Binds a {@link Key} to an implementation in a given scope.
486 */
crazyboblee63b592b2007-01-25 02:45:24 +0000487 public class BindingBuilder<T> {
crazyboblee7c5b2c42007-01-20 02:05:20 +0000488
489 Object source = ContainerBuilder.UNKNOWN_SOURCE;
490 Key<T> key;
491 InternalFactory<? extends T> factory;
492 Scope scope;
crazybobleea6e73982007-02-02 00:21:07 +0000493 String scopeName;
crazybobleeabc4dd02007-02-01 01:44:36 +0000494 boolean preload = false;
crazyboblee7c5b2c42007-01-20 02:05:20 +0000495
496 BindingBuilder(Key<T> key) {
497 this.key = nonNull(key, "key");
498 }
499
crazyboblee235d0682007-01-31 02:25:21 +0000500 Object getSource() {
501 return source;
502 }
503
crazyboblee7c5b2c42007-01-20 02:05:20 +0000504 Key<T> getKey() {
505 return key;
506 }
507
crazyboblee63b592b2007-01-25 02:45:24 +0000508 BindingBuilder<T> from(Object source) {
crazyboblee7c5b2c42007-01-20 02:05:20 +0000509 this.source = source;
510 return this;
511 }
512
513 /**
514 * Sets the name of this binding.
515 */
516 public BindingBuilder<T> named(String name) {
517 if (!this.key.hasDefaultName()) {
crazybobleee039bac2007-02-02 21:42:09 +0000518 addError(source, ErrorMessages.NAME_ALREADY_SET);
crazyboblee7c5b2c42007-01-20 02:05:20 +0000519 }
520
521 this.key = this.key.named(name);
522 return this;
523 }
524
525 /**
526 * Binds to instances of the given implementation class. The {@link
527 * Container} will inject the implementation instances as well. Sets the
528 * scope based on the @{@link Scoped} annotation on the implementation
529 * class if present.
530 */
531 public <I extends T> BindingBuilder<T> to(Class<I> implementation) {
crazyboblee0baa9fc2007-01-31 02:38:54 +0000532 return to(TypeLiteral.get(implementation));
crazyboblee7c5b2c42007-01-20 02:05:20 +0000533 }
534
535 /**
536 * Binds to instances of the given implementation type. The {@link
537 * Container} will inject the implementation instances as well. Sets the
538 * scope based on the @{@link Scoped} annotation on the implementation
539 * class if present.
540 */
crazyboblee0baa9fc2007-01-31 02:38:54 +0000541 public <I extends T> BindingBuilder<T> to(TypeLiteral<I> implementation) {
crazyboblee7c5b2c42007-01-20 02:05:20 +0000542 ensureImplementationIsNotSet();
crazyboblee4727ee22007-01-30 03:13:38 +0000543 validate(source, implementation.getRawType());
crazyboblee7289ac12007-02-01 00:28:09 +0000544 this.factory = new DefaultFactory<I>(key, implementation);
crazyboblee7c5b2c42007-01-20 02:05:20 +0000545 setScopeFromType(implementation.getRawType());
546 return this;
547 }
548
549 private void setScopeFromType(Class<?> implementation) {
crazybobleee5fbbb02007-02-05 07:00:27 +0000550 for (Annotation annotation : implementation.getAnnotations()) {
551 Class<? extends Annotation> annotationType =
552 annotation.annotationType();
553 if (annotationType == Scoped.class) {
554 in(((Scoped) annotation).value());
555 } else {
556 Scoped scoped = annotationType.getAnnotation(Scoped.class);
557 if (scoped != null) {
558 in(scoped.value());
559 }
560 }
crazyboblee7c5b2c42007-01-20 02:05:20 +0000561 }
562 }
563
564 /**
565 * Binds to instances from the given factory.
566 */
567 public BindingBuilder<T> to(
568 final ContextualFactory<? extends T> factory) {
569 ensureImplementationIsNotSet();
570
crazyboblee7289ac12007-02-01 00:28:09 +0000571 this.factory = new InternalToContextualFactoryAdapter<T>(factory);
crazyboblee7c5b2c42007-01-20 02:05:20 +0000572
573 return this;
574 }
575
576 /**
577 * Binds to instances from the given factory.
578 */
579 public BindingBuilder<T> to(final Factory<? extends T> factory) {
580 ensureImplementationIsNotSet();
crazyboblee7289ac12007-02-01 00:28:09 +0000581 this.factory = new InternalFactoryToFactoryAdapter<T>(factory);
crazyboblee7c5b2c42007-01-20 02:05:20 +0000582 return this;
583 }
584
585 /**
586 * Binds to the given instance.
587 */
crazybobleed543d242007-02-03 08:34:02 +0000588 public BindingBuilder<T> to(T instance) {
crazyboblee7c5b2c42007-01-20 02:05:20 +0000589 ensureImplementationIsNotSet();
590 this.factory = new ConstantFactory<T>(instance);
crazybobleee5fbbb02007-02-05 07:00:27 +0000591 in(CONTAINER);
crazyboblee7c5b2c42007-01-20 02:05:20 +0000592 return this;
593 }
594
595 /**
596 * Binds to instances from the given factory.
597 */
598 BindingBuilder<T> to(final InternalFactory<? extends T> factory) {
599 ensureImplementationIsNotSet();
600 this.factory = factory;
601 return this;
602 }
603
604 /**
605 * Adds an error message if the implementation has already been bound.
606 */
607 private void ensureImplementationIsNotSet() {
608 if (factory != null) {
crazybobleee039bac2007-02-02 21:42:09 +0000609 addError(source, ErrorMessages.IMPLEMENTATION_ALREADY_SET);
crazyboblee7c5b2c42007-01-20 02:05:20 +0000610 }
611 }
612
613 /**
crazyboblee63b592b2007-01-25 02:45:24 +0000614 * Specifies the scope. References the name passed to {@link
crazybobleee5fbbb02007-02-05 07:00:27 +0000615 * ContainerBuilder#scope(String, Scope)}.
crazyboblee7c5b2c42007-01-20 02:05:20 +0000616 */
crazyboblee63b592b2007-01-25 02:45:24 +0000617 public BindingBuilder<T> in(String scopeName) {
618 ensureScopeNotSet();
crazyboblee7c5b2c42007-01-20 02:05:20 +0000619
crazyboblee63b592b2007-01-25 02:45:24 +0000620 // We could defer this lookup to when we create the container, but this
621 // is fine for now.
crazyboblee235d0682007-01-31 02:25:21 +0000622 this.scope = scopes.get(nonNull(scopeName, "scope name"));
crazyboblee63b592b2007-01-25 02:45:24 +0000623 if (this.scope == null) {
crazybobleee039bac2007-02-02 21:42:09 +0000624 addError(source, ErrorMessages.SCOPE_NOT_FOUND, scopeName,
crazyboblee235d0682007-01-31 02:25:21 +0000625 scopes.keySet());
crazyboblee63b592b2007-01-25 02:45:24 +0000626 }
crazyboblee7c5b2c42007-01-20 02:05:20 +0000627 return this;
628 }
629
crazyboblee63b592b2007-01-25 02:45:24 +0000630 /**
631 * Specifies the scope.
632 */
633 public BindingBuilder<T> in(Scope scope) {
634 ensureScopeNotSet();
635
636 this.scope = nonNull(scope, "scope");
637 return this;
638 }
639
crazyboblee2af06372007-02-01 02:07:53 +0000640 /**
crazybobleea6e73982007-02-02 00:21:07 +0000641 * Specifies container scope (i.e.&nbsp;one instance per container).
crazyboblee2af06372007-02-01 02:07:53 +0000642 */
643 public BindingBuilder<T> inContainerScope() {
crazybobleee5fbbb02007-02-05 07:00:27 +0000644 return in(CONTAINER);
crazyboblee2af06372007-02-01 02:07:53 +0000645 }
646
crazyboblee63b592b2007-01-25 02:45:24 +0000647 private void ensureScopeNotSet() {
648 if (this.scope != null) {
crazybobleee039bac2007-02-02 21:42:09 +0000649 addError(source, ErrorMessages.SCOPE_ALREADY_SET);
crazyboblee63b592b2007-01-25 02:45:24 +0000650 }
651 }
652
crazybobleeabc4dd02007-02-01 01:44:36 +0000653 /**
654 * Instructs the builder to eagerly load this binding when it creates
655 * the container. Useful for application initialization logic. Currently
656 * only supported for container-scoped bindings.
657 */
658 public BindingBuilder<T> preload() {
659 this.preload = true;
660 return this;
661 }
662
663 boolean shouldPreload() {
664 return preload;
665 }
666
crazyboblee63b592b2007-01-25 02:45:24 +0000667 InternalFactory<? extends T> getInternalFactory(
668 final ContainerImpl container) {
crazyboblee7c5b2c42007-01-20 02:05:20 +0000669 // If an implementation wasn't specified, use the injection type.
670 if (this.factory == null) {
crazyboblee0baa9fc2007-01-31 02:38:54 +0000671 to(key.getType());
crazyboblee7c5b2c42007-01-20 02:05:20 +0000672 }
673
crazybobleee5fbbb02007-02-05 07:00:27 +0000674 // Default scope does nothing.
675 if (scope == null || scope == DEFAULT) {
crazyboblee7c5b2c42007-01-20 02:05:20 +0000676 return this.factory;
677 }
678
crazyboblee7289ac12007-02-01 00:28:09 +0000679 Factory<T> scoped = scope.scope(this.key,
680 new FactoryToInternalFactoryAdapter<T>(container, this.factory));
681 return new InternalFactoryToFactoryAdapter<T>(scoped);
crazyboblee7c5b2c42007-01-20 02:05:20 +0000682 }
683
crazybobleee5fbbb02007-02-05 07:00:27 +0000684 boolean isContainerScoped() {
685 return this.scope == Scopes.CONTAINER;
crazyboblee7c5b2c42007-01-20 02:05:20 +0000686 }
crazyboblee7289ac12007-02-01 00:28:09 +0000687 }
crazyboblee7c5b2c42007-01-20 02:05:20 +0000688
crazyboblee7289ac12007-02-01 00:28:09 +0000689 /**
690 * Injects new instances of the specified implementation class.
691 */
692 private static class DefaultFactory<T> implements InternalFactory<T> {
crazyboblee7c5b2c42007-01-20 02:05:20 +0000693
crazybobleee3adfd62007-02-02 21:30:08 +0000694 volatile ConstructorInjector<T> constructor;
crazyboblee7c5b2c42007-01-20 02:05:20 +0000695
crazyboblee7289ac12007-02-01 00:28:09 +0000696 private final TypeLiteral<T> implementation;
697 private final Key<? super T> key;
crazyboblee7c5b2c42007-01-20 02:05:20 +0000698
crazyboblee7289ac12007-02-01 00:28:09 +0000699 public DefaultFactory(Key<? super T> key, TypeLiteral<T> implementation) {
700 this.key = key;
701 this.implementation = implementation;
702 }
703
704 @SuppressWarnings("unchecked")
705 public T get(InternalContext context) {
706 if (constructor == null) {
crazybobleee3adfd62007-02-02 21:30:08 +0000707 this.constructor =
708 context.getContainerImpl().getConstructor(implementation);
crazyboblee7c5b2c42007-01-20 02:05:20 +0000709 }
crazyboblee7289ac12007-02-01 00:28:09 +0000710 return (T) constructor.construct(context, key.getRawType());
711 }
crazyboblee7c5b2c42007-01-20 02:05:20 +0000712
crazyboblee7289ac12007-02-01 00:28:09 +0000713 public String toString() {
crazybobleee3adfd62007-02-02 21:30:08 +0000714 return new ToStringBuilder(Factory.class)
715 .add("implementation", implementation)
716 .toString();
crazyboblee7c5b2c42007-01-20 02:05:20 +0000717 }
718 }
719
720 /**
721 * Builds a constant binding.
722 */
crazyboblee63b592b2007-01-25 02:45:24 +0000723 public class ConstantBindingBuilder {
crazyboblee7c5b2c42007-01-20 02:05:20 +0000724
725 final String name;
726 Class<?> type;
727 Object value;
728 Object source = ContainerBuilder.UNKNOWN_SOURCE;
729
730 ConstantBindingBuilder(String name) {
731 this.name = name;
732 }
733
734 Key<?> getKey() {
735 return Key.get(type, name);
736 }
737
738 boolean hasValue() {
739 return type != null;
740 }
741
742 Object getSource() {
743 return source;
744 }
745
746 InternalFactory<?> getInternalFactory() {
747 return new ConstantFactory<Object>(value);
748 }
749
crazyboblee63b592b2007-01-25 02:45:24 +0000750 ConstantBindingBuilder from(Object source) {
crazyboblee7c5b2c42007-01-20 02:05:20 +0000751 this.source = source;
752 return this;
753 }
754
755 /**
756 * Binds constant to the given value.
757 */
crazyboblee78e1cc12007-01-26 02:18:06 +0000758 public void to(String value) {
759 to(String.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(int value) {
766 to(int.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(long value) {
773 to(long.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(boolean value) {
780 to(boolean.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(double value) {
787 to(double.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(float value) {
794 to(float.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(short value) {
801 to(short.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(char value) {
808 to(char.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 void to(Class<?> value) {
815 to(Class.class, value);
crazyboblee7c5b2c42007-01-20 02:05:20 +0000816 }
817
818 /**
819 * Binds constant to the given value.
820 */
crazyboblee78e1cc12007-01-26 02:18:06 +0000821 public <E extends Enum<E>> void to(E value) {
822 to(value.getDeclaringClass(), value);
crazyboblee7c5b2c42007-01-20 02:05:20 +0000823 }
824
825 /**
826 * Maps a constant value to the given type and name.
827 */
crazyboblee78e1cc12007-01-26 02:18:06 +0000828 <T> void to(final Class<T> type, final T value) {
crazyboblee235d0682007-01-31 02:25:21 +0000829 if (this.value != null) {
crazybobleee039bac2007-02-02 21:42:09 +0000830 addError(source, ErrorMessages.CONSTANT_VALUE_ALREADY_SET);
crazyboblee235d0682007-01-31 02:25:21 +0000831 } else {
832 this.type = type;
833 this.value = value;
834 }
crazyboblee7c5b2c42007-01-20 02:05:20 +0000835 }
836 }
837
838 /**
839 * Links one binding to another.
840 */
crazyboblee63b592b2007-01-25 02:45:24 +0000841 public class LinkedBindingBuilder<T> {
crazyboblee7c5b2c42007-01-20 02:05:20 +0000842
843 Key<T> key;
844 Key<? extends T> destination;
845 Object source = ContainerBuilder.UNKNOWN_SOURCE;
846
847 LinkedBindingBuilder(Key<T> key) {
848 this.key = key;
849 }
850
851 Object getSource() {
852 return source;
853 }
854
855 Key<T> getKey() {
856 return key;
857 }
858
859 Key<? extends T> getDestination() {
860 return destination;
861 }
862
crazyboblee63b592b2007-01-25 02:45:24 +0000863 LinkedBindingBuilder<T> from(Object source) {
crazyboblee7c5b2c42007-01-20 02:05:20 +0000864 this.source = source;
865 return this;
866 }
867
868 /**
869 * Links to another binding with the given key.
870 */
crazyboblee78e1cc12007-01-26 02:18:06 +0000871 public void to(Key<? extends T> destination) {
crazyboblee235d0682007-01-31 02:25:21 +0000872 if (this.destination != null) {
crazybobleee039bac2007-02-02 21:42:09 +0000873 addError(source, ErrorMessages.LINK_DESTINATION_ALREADY_SET);
crazyboblee235d0682007-01-31 02:25:21 +0000874 } else {
875 this.destination = destination;
876 }
crazyboblee7c5b2c42007-01-20 02:05:20 +0000877 }
878 }
crazyboblee4727ee22007-01-30 03:13:38 +0000879
crazyboblee235d0682007-01-31 02:25:21 +0000880 /**
881 * Handles errors up until we successfully create the container.
882 */
883 class ConfigurationErrorHandler extends AbstractErrorHandler {
crazyboblee4727ee22007-01-30 03:13:38 +0000884
885 final Object source;
886
887 ConfigurationErrorHandler(Object source) {
888 this.source = source;
889 }
890
891 public void handle(String message) {
crazybobleee039bac2007-02-02 21:42:09 +0000892 add(new Message(source, message));
crazyboblee4727ee22007-01-30 03:13:38 +0000893 }
894
895 public void handle(Throwable t) {
crazybobleee039bac2007-02-02 21:42:09 +0000896 add(new Message(source, t.getMessage()));
crazyboblee4727ee22007-01-30 03:13:38 +0000897 }
898 }
899
crazyboblee235d0682007-01-31 02:25:21 +0000900 /**
901 * Handles errors after the container is created.
902 */
903 class RuntimeErrorHandler extends AbstractErrorHandler {
crazyboblee4727ee22007-01-30 03:13:38 +0000904
905 public void handle(String message) {
906 throw new ConfigurationException(message);
907 }
908
909 public void handle(Throwable t) {
910 throw new ConfigurationException(t);
911 }
912 }
crazyboblee235d0682007-01-31 02:25:21 +0000913
crazybobleeef83bd22007-02-01 00:52:57 +0000914 /**
915 * A requested static injection.
916 */
917 class StaticInjection {
918
919 final Object source;
920 final Class<?>[] types;
921 final List<ContainerImpl.Injector> injectors =
922 new ArrayList<ContainerImpl.Injector>();
923
924 public StaticInjection(Object source, Class<?>[] types) {
925 this.source = source;
926 this.types = types;
927 }
928
929 void createInjectors(final ContainerImpl container) {
930 container.withErrorHandler(new ConfigurationErrorHandler(source),
931 new Runnable() {
932 public void run() {
933 for (Class<?> clazz : types) {
934 container.addInjectorsForFields(
935 clazz.getDeclaredFields(), true, injectors);
936 container.addInjectorsForMethods(
937 clazz.getDeclaredMethods(), true, injectors);
938 }
939 }
940 });
941 }
942
943 void runInjectors(ContainerImpl container) {
crazybobleea6e73982007-02-02 00:21:07 +0000944 container.callInContext(new ContextualCallable<Void>() {
crazybobleeef83bd22007-02-01 00:52:57 +0000945 public Void call(InternalContext context) {
946 for (ContainerImpl.Injector injector : injectors) {
947 injector.inject(context, null);
948 }
949 return null;
950 }
951 });
952 }
953 }
crazybobleeabc4dd02007-02-01 01:44:36 +0000954
955 static class BindingPreloader
crazybobleea6e73982007-02-02 00:21:07 +0000956 implements ContextualCallable<Void> {
crazybobleeabc4dd02007-02-01 01:44:36 +0000957
958 private final Key<?> key;
959 private final InternalFactory<?> factory;
960
961 public BindingPreloader(Key<?> key, InternalFactory<?> factory) {
962 this.key = key;
963 this.factory = factory;
964 }
965
966 public Void call(InternalContext context) {
967 ExternalContext<?> externalContext =
968 ExternalContext.newInstance(null, key, context.getContainerImpl());
969 context.setExternalContext(externalContext);
970 try {
971 factory.get(context);
972 return null;
973 } finally {
974 context.setExternalContext(null);
975 }
976 }
977 }
crazyboblee66b415a2006-08-25 02:01:19 +0000978}