blob: c8bd2240ed1458996e93eb5843287a79cd26d9ba [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;
crazyboblee7c5b2c42007-01-20 02:05:20 +000021import static com.google.inject.util.Objects.nonNull;
22
crazyboblee66b415a2006-08-25 02:01:19 +000023import java.lang.reflect.Member;
24import java.util.ArrayList;
25import java.util.Arrays;
26import java.util.HashMap;
crazyboblee235d0682007-01-31 02:25:21 +000027import java.util.LinkedHashSet;
crazyboblee66b415a2006-08-25 02:01:19 +000028import java.util.List;
29import java.util.Map;
crazyboblee07e41822006-11-21 01:27:08 +000030import java.util.Properties;
crazyboblee7c5b2c42007-01-20 02:05:20 +000031import java.util.Set;
crazyboblee235d0682007-01-31 02:25:21 +000032import java.util.HashSet;
crazyboblee66b415a2006-08-25 02:01:19 +000033import java.util.logging.Logger;
34
35/**
crazyboblee7c5b2c42007-01-20 02:05:20 +000036 * Builds a dependency injection {@link Container}. Binds {@link Key}s to
crazyboblee235d0682007-01-31 02:25:21 +000037 * implementations. A binding implementation could be anything from a constant
38 * value to an object in the HTTP session.
crazyboblee66b415a2006-08-25 02:01:19 +000039 *
crazyboblee7c5b2c42007-01-20 02:05:20 +000040 * <p>Not safe for concurrent use.
41 *
42 * <p>Default bindings include:
crazyboblee66b415a2006-08-25 02:01:19 +000043 *
44 * <ul>
crazyboblee78e1cc12007-01-26 02:18:06 +000045 * <li>A {@code Factory<T>} for each binding of type {@code T}
crazyboblee7c5b2c42007-01-20 02:05:20 +000046 * <li>The {@link Container} iself
47 * <li>The {@link Logger} for the class being injected
crazyboblee66b415a2006-08-25 02:01:19 +000048 * </ul>
49 *
crazyboblee07e41822006-11-21 01:27:08 +000050 * <p>Converts constants as needed from {@code String} to any primitive type
crazyboblee7c5b2c42007-01-20 02:05:20 +000051 * in addition to {@code enum} and {@code Class<?>}.
crazyboblee07e41822006-11-21 01:27:08 +000052 *
crazyboblee66b415a2006-08-25 02:01:19 +000053 * @author crazybob@google.com (Bob Lee)
54 */
55public final class ContainerBuilder {
56
crazyboblee63b592b2007-01-25 02:45:24 +000057 private static final Logger logger =
58 Logger.getLogger(ContainerBuilder.class.getName());
59
crazyboblee7c5b2c42007-01-20 02:05:20 +000060 final List<BindingBuilder<?>> bindingBuilders =
61 new ArrayList<BindingBuilder<?>>();
62 final List<ConstantBindingBuilder> constantBindingBuilders =
63 new ArrayList<ConstantBindingBuilder>();
64 final List<LinkedBindingBuilder<?>> linkedBindingBuilders =
65 new ArrayList<LinkedBindingBuilder<?>>();
crazyboblee63b592b2007-01-25 02:45:24 +000066 final Map<String, Scope> scopes = new HashMap<String, Scope>();
crazyboblee7c5b2c42007-01-20 02:05:20 +000067
crazybobleeef83bd22007-02-01 00:52:57 +000068 final List<StaticInjection> staticInjections =
69 new ArrayList<StaticInjection>();
crazyboblee7c5b2c42007-01-20 02:05:20 +000070
crazyboblee66b415a2006-08-25 02:01:19 +000071 boolean created;
72
crazyboblee7c5b2c42007-01-20 02:05:20 +000073 /**
74 * Keeps error messages in order and prevents duplicates.
75 */
76 Set<ErrorMessage> errorMessages = new LinkedHashSet<ErrorMessage>();
77
crazyboblee66b415a2006-08-25 02:01:19 +000078 private static final InternalFactory<Container> CONTAINER_FACTORY =
79 new InternalFactory<Container>() {
crazyboblee7c5b2c42007-01-20 02:05:20 +000080 public Container get(InternalContext context) {
crazyboblee66b415a2006-08-25 02:01:19 +000081 return context.getContainer();
82 }
83 };
84
85 private static final InternalFactory<Logger> LOGGER_FACTORY =
86 new InternalFactory<Logger>() {
crazyboblee7c5b2c42007-01-20 02:05:20 +000087 public Logger get(InternalContext context) {
crazyboblee66b415a2006-08-25 02:01:19 +000088 Member member = context.getExternalContext().getMember();
89 return member == null ? Logger.getAnonymousLogger()
90 : Logger.getLogger(member.getDeclaringClass().getName());
91 }
92 };
93
crazyboblee7c5b2c42007-01-20 02:05:20 +000094 static final String UNKNOWN_SOURCE = "[unknown source]";
95
crazyboblee63b592b2007-01-25 02:45:24 +000096 static final Scope DEFAULT_SCOPE = new Scope() {
97 public <T> Factory<T> scope(Key<T> key, Factory<T> creator) {
crazyboblee7289ac12007-02-01 00:28:09 +000098 // We special case optimize default scope, so this never actually runs.
99 throw new AssertionError();
crazyboblee63b592b2007-01-25 02:45:24 +0000100 }
101 };
102
crazyboblee66b415a2006-08-25 02:01:19 +0000103 /**
104 * Constructs a new builder.
105 */
106 public ContainerBuilder() {
crazyboblee63b592b2007-01-25 02:45:24 +0000107 put(Scopes.DEFAULT, DEFAULT_SCOPE);
crazyboblee235d0682007-01-31 02:25:21 +0000108 put(Scopes.CONTAINER, ContainerScope.INSTANCE);
crazyboblee63b592b2007-01-25 02:45:24 +0000109
crazyboblee7c5b2c42007-01-20 02:05:20 +0000110 bind(Container.class).to(CONTAINER_FACTORY);
111 bind(Logger.class).to(LOGGER_FACTORY);
crazyboblee66b415a2006-08-25 02:01:19 +0000112 }
113
crazyboblee4727ee22007-01-30 03:13:38 +0000114 final List<Validation> validations = new ArrayList<Validation>();
115
116 /**
117 * Registers a type to be validated for injection when we create the
118 * container.
119 */
120 void validate(final Object source, final Class<?> type) {
121 validations.add(new Validation() {
crazybobleeef83bd22007-02-01 00:52:57 +0000122 public void run(final ContainerImpl container) {
123 container.withErrorHandler(new ConfigurationErrorHandler(source),
124 new Runnable() {
125 public void run() {
126 container.getConstructor(type);
127 }
128 });
crazyboblee4727ee22007-01-30 03:13:38 +0000129 }
130 });
131 }
132
crazyboblee235d0682007-01-31 02:25:21 +0000133 /**
134 * A validation command to run after we create the container but before
135 * we return it to the client.
136 */
crazyboblee4727ee22007-01-30 03:13:38 +0000137 interface Validation {
138 void run(ContainerImpl container);
139 }
140
crazyboblee66b415a2006-08-25 02:01:19 +0000141 /**
crazybobleedac49912007-01-29 23:17:41 +0000142 * Maps a {@link Scope} instance to a given scope name. Scopes should be
143 * mapped before used in bindings. @{@link Scoped#value()} references this
144 * name.
crazyboblee63b592b2007-01-25 02:45:24 +0000145 */
146 public void put(String name, Scope scope) {
147 if (scopes.containsKey(nonNull(name, "name"))) {
crazyboblee235d0682007-01-31 02:25:21 +0000148 addError(source(), ErrorMessage.DUPLICATE_SCOPES, name);
crazyboblee63b592b2007-01-25 02:45:24 +0000149 } else {
crazyboblee235d0682007-01-31 02:25:21 +0000150 scopes.put(nonNull(name, "name"), nonNull(scope, "scope"));
crazyboblee63b592b2007-01-25 02:45:24 +0000151 }
152 }
153
154 /**
crazyboblee7c5b2c42007-01-20 02:05:20 +0000155 * Binds the given key.
156 */
157 public <T> BindingBuilder<T> bind(Key<T> key) {
crazyboblee66b415a2006-08-25 02:01:19 +0000158 ensureNotCreated();
crazyboblee7c5b2c42007-01-20 02:05:20 +0000159 BindingBuilder<T> builder = new BindingBuilder<T>(key).from(source());
160 bindingBuilders.add(builder);
161 return builder;
crazyboblee66b415a2006-08-25 02:01:19 +0000162 }
163
164 /**
crazyboblee7c5b2c42007-01-20 02:05:20 +0000165 * Binds the given type.
crazyboblee66b415a2006-08-25 02:01:19 +0000166 */
crazyboblee0baa9fc2007-01-31 02:38:54 +0000167 public <T> BindingBuilder<T> bind(TypeLiteral<T> typeLiteral) {
168 return bind(Key.get(typeLiteral));
crazyboblee66b415a2006-08-25 02:01:19 +0000169 }
170
171 /**
crazyboblee7c5b2c42007-01-20 02:05:20 +0000172 * Binds the given type.
crazyboblee66b415a2006-08-25 02:01:19 +0000173 */
crazyboblee7c5b2c42007-01-20 02:05:20 +0000174 public <T> BindingBuilder<T> bind(Class<T> clazz) {
175 return bind(Key.get(clazz));
crazyboblee66b415a2006-08-25 02:01:19 +0000176 }
177
178 /**
crazyboblee7c5b2c42007-01-20 02:05:20 +0000179 * Links the given key to another key effectively creating an alias for a
180 * binding.
crazyboblee66b415a2006-08-25 02:01:19 +0000181 */
crazyboblee7c5b2c42007-01-20 02:05:20 +0000182 public <T> LinkedBindingBuilder<T> link(Key<T> key) {
183 ensureNotCreated();
184 LinkedBindingBuilder<T> builder =
185 new LinkedBindingBuilder<T>(key).from(source());
186 linkedBindingBuilders.add(builder);
187 return builder;
crazyboblee66b415a2006-08-25 02:01:19 +0000188 }
189
190 /**
crazyboblee7c5b2c42007-01-20 02:05:20 +0000191 * Binds a constant to the given name.
crazyboblee66b415a2006-08-25 02:01:19 +0000192 */
crazyboblee7c5b2c42007-01-20 02:05:20 +0000193 public ConstantBindingBuilder bind(String name) {
194 ensureNotCreated();
195 return bind(name, source());
crazyboblee66b415a2006-08-25 02:01:19 +0000196 }
197
198 /**
crazyboblee7c5b2c42007-01-20 02:05:20 +0000199 * Binds a constant to the given name from the given source.
crazyboblee66b415a2006-08-25 02:01:19 +0000200 */
crazyboblee7c5b2c42007-01-20 02:05:20 +0000201 private ConstantBindingBuilder bind(String name, Object source) {
202 ConstantBindingBuilder builder =
203 new ConstantBindingBuilder(Objects.nonNull(name, "name")).from(source);
204 constantBindingBuilders.add(builder);
205 return builder;
crazyboblee66b415a2006-08-25 02:01:19 +0000206 }
207
208 /**
crazyboblee63b592b2007-01-25 02:45:24 +0000209 * Binds a string constant for each property.
crazyboblee66b415a2006-08-25 02:01:19 +0000210 */
crazyboblee041e9332007-01-29 22:58:35 +0000211 public void bindProperties(Map<String, String> properties) {
crazyboblee7c5b2c42007-01-20 02:05:20 +0000212 ensureNotCreated();
213 Object source = source();
crazyboblee07e41822006-11-21 01:27:08 +0000214 for (Map.Entry<String, String> entry : properties.entrySet()) {
crazyboblee7c5b2c42007-01-20 02:05:20 +0000215 String key = entry.getKey();
216 String value = entry.getValue();
217 bind(key, source).to(value);
crazyboblee07e41822006-11-21 01:27:08 +0000218 }
crazyboblee07e41822006-11-21 01:27:08 +0000219 }
220
221 /**
crazyboblee63b592b2007-01-25 02:45:24 +0000222 * Binds a string constant for each property.
crazyboblee07e41822006-11-21 01:27:08 +0000223 */
crazyboblee041e9332007-01-29 22:58:35 +0000224 public void bindProperties(Properties properties) {
donald.brown263c5bc2006-11-16 18:39:55 +0000225 ensureNotCreated();
crazyboblee7c5b2c42007-01-20 02:05:20 +0000226 Object source = source();
227 for (Map.Entry<Object, Object> entry : properties.entrySet()) {
228 String key = (String) entry.getKey();
229 String value = (String) entry.getValue();
230 bind(key, source).to(value);
donald.brown263c5bc2006-11-16 18:39:55 +0000231 }
donald.brown263c5bc2006-11-16 18:39:55 +0000232 }
233
234 /**
crazyboblee4776db72007-01-29 23:27:30 +0000235 * Upon successful creation, the {@link Container} will inject static fields
236 * and methods in the given classes.
crazyboblee66b415a2006-08-25 02:01:19 +0000237 *
238 * @param types for which static members will be injected
239 */
crazyboblee4776db72007-01-29 23:27:30 +0000240 public void requestStaticInjection(Class<?>... types) {
crazybobleeef83bd22007-02-01 00:52:57 +0000241 staticInjections.add(new StaticInjection(source(), types));
crazyboblee041e9332007-01-29 22:58:35 +0000242 }
243
244 /**
245 * Applies the given module to this builder.
246 */
247 public void apply(Module module) {
248 module.configure(this);
crazyboblee66b415a2006-08-25 02:01:19 +0000249 }
250
crazyboblee235d0682007-01-31 02:25:21 +0000251 void addError(Object source, String message, Object... arguments) {
252 new ConfigurationErrorHandler(source).handle(message, arguments);
253 }
254
255 void addError(Object source, String message) {
256 new ConfigurationErrorHandler(source).handle(message);
257 }
258
crazyboblee66b415a2006-08-25 02:01:19 +0000259 /**
crazyboblee7c5b2c42007-01-20 02:05:20 +0000260 * Adds an error message to be reported at creation time.
crazyboblee66b415a2006-08-25 02:01:19 +0000261 */
crazyboblee7c5b2c42007-01-20 02:05:20 +0000262 void add(ErrorMessage errorMessage) {
263 errorMessages.add(errorMessage);
crazyboblee66b415a2006-08-25 02:01:19 +0000264 }
265
crazyboblee9bb62022007-02-01 00:06:53 +0000266 Stopwatch stopwatch = new Stopwatch();
267
crazyboblee66b415a2006-08-25 02:01:19 +0000268 /**
269 * Creates a {@link Container} instance. Injects static members for classes
crazyboblee4776db72007-01-29 23:27:30 +0000270 * which were registered using {@link #requestStaticInjection(Class...)}.
crazyboblee66b415a2006-08-25 02:01:19 +0000271 *
crazyboblee235d0682007-01-31 02:25:21 +0000272 * @param preload If true, the container will load all container-scoped
273 * bindings now. If false, the container will lazily load them. Eager
274 * loading is appropriate for production use (catch errors early and take
275 * any performance hit up front) while lazy loading can speed development.
276 *
crazyboblee9bb62022007-02-01 00:06:53 +0000277 * @throws ContainerCreationException if configuration errors are found. The
278 * expectation is that the application will log this exception and exit.
crazyboblee66b415a2006-08-25 02:01:19 +0000279 * @throws IllegalStateException if called more than once
280 */
crazyboblee9bb62022007-02-01 00:06:53 +0000281 public synchronized Container create(boolean preload)
282 throws ContainerCreationException {
283 // Only one Container per builder.
crazyboblee66b415a2006-08-25 02:01:19 +0000284 ensureNotCreated();
285 created = true;
crazyboblee7c5b2c42007-01-20 02:05:20 +0000286
crazyboblee9bb62022007-02-01 00:06:53 +0000287 stopwatch.resetAndLog(logger, "Configuration");
288
289 // Create the container.
crazyboblee7c5b2c42007-01-20 02:05:20 +0000290 HashMap<Key<?>, InternalFactory<?>> factories =
291 new HashMap<Key<?>, InternalFactory<?>>();
crazyboblee63b592b2007-01-25 02:45:24 +0000292 ContainerImpl container = new ContainerImpl(factories);
crazyboblee7c5b2c42007-01-20 02:05:20 +0000293
crazyboblee9bb62022007-02-01 00:06:53 +0000294 createConstantBindings(factories);
crazyboblee7c5b2c42007-01-20 02:05:20 +0000295
crazyboblee9bb62022007-02-01 00:06:53 +0000296 // Commands to execute before returning the Container instance.
crazyboblee235d0682007-01-31 02:25:21 +0000297 final List<ContainerImpl.ContextualCallable<Void>> preloaders =
crazyboblee7c5b2c42007-01-20 02:05:20 +0000298 new ArrayList<ContainerImpl.ContextualCallable<Void>>();
299
crazyboblee9bb62022007-02-01 00:06:53 +0000300 createBindings(container, factories, preload, preloaders);
301 createLinkedBindings(factories);
crazyboblee7c5b2c42007-01-20 02:05:20 +0000302
crazyboblee9bb62022007-02-01 00:06:53 +0000303 stopwatch.resetAndLog(logger, "Binding creation");
304
305 // Run validations.
306 for (Validation validation : validations) {
307 validation.run(container);
crazyboblee7c5b2c42007-01-20 02:05:20 +0000308 }
309
crazyboblee9bb62022007-02-01 00:06:53 +0000310 stopwatch.resetAndLog(logger, "Validation");
311
crazybobleeef83bd22007-02-01 00:52:57 +0000312 for (StaticInjection staticInjection : staticInjections) {
313 staticInjection.createInjectors(container);
314 }
315
316 stopwatch.resetAndLog(logger, "Static validation");
317
crazybobleeabc4dd02007-02-01 01:44:36 +0000318 // Blow up if we encountered errors.
crazyboblee9bb62022007-02-01 00:06:53 +0000319 if (!errorMessages.isEmpty()) {
320 throw new ContainerCreationException(createErrorMessage());
321 }
322
323 // Switch to runtime error handling.
324 container.setErrorHandler(new RuntimeErrorHandler());
325
326 // Inject static members.
crazybobleeef83bd22007-02-01 00:52:57 +0000327 for (StaticInjection staticInjection : staticInjections) {
328 staticInjection.runInjectors(container);
329 }
crazyboblee9bb62022007-02-01 00:06:53 +0000330
331 stopwatch.resetAndLog(logger, "Static member injection");
332
333 // Run preloading commands.
crazybobleeabc4dd02007-02-01 01:44:36 +0000334 runPreloaders(container, preloaders);
crazyboblee9bb62022007-02-01 00:06:53 +0000335
336 stopwatch.resetAndLog(logger, "Preloading");
337
338 return container;
339 }
340
crazybobleeabc4dd02007-02-01 01:44:36 +0000341 private void runPreloaders(ContainerImpl container,
342 final List<ContainerImpl.ContextualCallable<Void>> preloaders) {
343 container.callInContext(new ContainerImpl.ContextualCallable<Void>() {
344 public Void call(InternalContext context) {
345 for (ContainerImpl.ContextualCallable<Void> preloader : preloaders) {
346 preloader.call(context);
347 }
348 return null;
349 }
350 });
351 }
352
crazyboblee9bb62022007-02-01 00:06:53 +0000353 private String createErrorMessage() {
354 StringBuilder error = new StringBuilder();
355 error.append("Guice configuration errors:\n\n");
356 int index = 1;
357 for (ErrorMessage errorMessage : errorMessages) {
358 error.append(index++)
359 .append(") ")
360 .append("Error at ")
361 .append(errorMessage.getSource())
362 .append(':')
363 .append('\n')
364 .append(" ")
365 .append(errorMessage.getMessage())
366 .append("\n\n");
367 }
368 error.append(errorMessages.size()).append(" error[s]\n");
369 return error.toString();
370 }
371
372 private void createLinkedBindings(
373 HashMap<Key<?>, InternalFactory<?>> factories) {
crazyboblee7c5b2c42007-01-20 02:05:20 +0000374 for (LinkedBindingBuilder<?> builder : linkedBindingBuilders) {
375 // TODO: Support alias to a later-declared alias.
376 Key<?> destination = builder.getDestination();
377 if (destination == null) {
crazyboblee235d0682007-01-31 02:25:21 +0000378 addError(builder.getSource(), ErrorMessage.MISSING_LINK_DESTINATION);
crazyboblee7c5b2c42007-01-20 02:05:20 +0000379 continue;
380 }
381
382 InternalFactory<?> factory = factories.get(destination);
383 if (factory == null) {
crazyboblee235d0682007-01-31 02:25:21 +0000384 addError(builder.getSource(), ErrorMessage.LINK_DESTINATION_NOT_FOUND,
385 destination);
crazyboblee7c5b2c42007-01-20 02:05:20 +0000386 continue;
387 }
388
crazyboblee235d0682007-01-31 02:25:21 +0000389 putFactory(builder.getSource(), factories, builder.getKey(), factory);
crazyboblee7c5b2c42007-01-20 02:05:20 +0000390 }
crazyboblee9bb62022007-02-01 00:06:53 +0000391 }
crazyboblee7c5b2c42007-01-20 02:05:20 +0000392
crazyboblee9bb62022007-02-01 00:06:53 +0000393 private void createBindings(ContainerImpl container,
394 HashMap<Key<?>, InternalFactory<?>> factories, boolean preload,
395 List<ContainerImpl.ContextualCallable<Void>> preloaders) {
396 for (BindingBuilder<?> builder : bindingBuilders) {
397 final Key<?> key = builder.getKey();
398 final InternalFactory<?> factory = builder.getInternalFactory(container);
399 putFactory(builder.getSource(), factories, key, factory);
crazyboblee4727ee22007-01-30 03:13:38 +0000400
crazybobleeabc4dd02007-02-01 01:44:36 +0000401 if (builder.isInContainerScope()) {
402 if (preload || builder.shouldPreload()) {
403 preloaders.add(new BindingPreloader(key, factory));
404 }
405 } else {
406 if (builder.shouldPreload()) {
407 addError(builder.getSource(), ErrorMessage.PRELOAD_NOT_ALLOWED);
408 }
crazyboblee9bb62022007-02-01 00:06:53 +0000409 }
crazyboblee66b415a2006-08-25 02:01:19 +0000410 }
crazyboblee9bb62022007-02-01 00:06:53 +0000411 }
crazyboblee7c5b2c42007-01-20 02:05:20 +0000412
crazyboblee7289ac12007-02-01 00:28:09 +0000413 private void createConstantBindings(
414 HashMap<Key<?>, InternalFactory<?>> factories) {
crazyboblee9bb62022007-02-01 00:06:53 +0000415 for (ConstantBindingBuilder builder : constantBindingBuilders) {
416 if (builder.hasValue()) {
417 Key<?> key = builder.getKey();
418 InternalFactory<?> factory = builder.getInternalFactory();
419 putFactory(builder.getSource(), factories, key, factory);
420 } else {
421 addError(builder.getSource(), ErrorMessage.MISSING_CONSTANT_VALUE);
422 }
423 }
crazyboblee66b415a2006-08-25 02:01:19 +0000424 }
425
crazyboblee235d0682007-01-31 02:25:21 +0000426 void putFactory(Object source, Map<Key<?>, InternalFactory<?>> factories,
427 Key<?> key, InternalFactory<?> factory) {
428 if (factories.containsKey(key)) {
429 addError(source, ErrorMessage.BINDING_ALREADY_SET, key);
430 } else {
431 factories.put(key, factory);
432 }
433 }
434
crazyboblee66b415a2006-08-25 02:01:19 +0000435 /**
436 * Currently we only support creating one Container instance per builder.
437 * If we want to support creating more than one container per builder,
438 * we should move to a "factory factory" model where we create a factory
439 * instance per Container. Right now, one factory instance would be
crazyboblee235d0682007-01-31 02:25:21 +0000440 * shared across all the containers, which means container-scoped objects
441 * would be shared, etc.
crazyboblee66b415a2006-08-25 02:01:19 +0000442 */
443 private void ensureNotCreated() {
444 if (created) {
445 throw new IllegalStateException("Container already created.");
446 }
447 }
448
449 /**
crazyboblee7c5b2c42007-01-20 02:05:20 +0000450 * Binds a {@link Key} to an implementation in a given scope.
451 */
crazyboblee63b592b2007-01-25 02:45:24 +0000452 public class BindingBuilder<T> {
crazyboblee7c5b2c42007-01-20 02:05:20 +0000453
454 Object source = ContainerBuilder.UNKNOWN_SOURCE;
455 Key<T> key;
456 InternalFactory<? extends T> factory;
457 Scope scope;
crazybobleeabc4dd02007-02-01 01:44:36 +0000458 boolean preload = false;
crazyboblee7c5b2c42007-01-20 02:05:20 +0000459
460 BindingBuilder(Key<T> key) {
461 this.key = nonNull(key, "key");
462 }
463
crazyboblee235d0682007-01-31 02:25:21 +0000464 Object getSource() {
465 return source;
466 }
467
crazyboblee7c5b2c42007-01-20 02:05:20 +0000468 Key<T> getKey() {
469 return key;
470 }
471
crazyboblee63b592b2007-01-25 02:45:24 +0000472 BindingBuilder<T> from(Object source) {
crazyboblee7c5b2c42007-01-20 02:05:20 +0000473 this.source = source;
474 return this;
475 }
476
477 /**
478 * Sets the name of this binding.
479 */
480 public BindingBuilder<T> named(String name) {
481 if (!this.key.hasDefaultName()) {
crazyboblee235d0682007-01-31 02:25:21 +0000482 addError(source, ErrorMessage.NAME_ALREADY_SET);
crazyboblee7c5b2c42007-01-20 02:05:20 +0000483 }
484
485 this.key = this.key.named(name);
486 return this;
487 }
488
489 /**
490 * Binds to instances of the given implementation class. The {@link
491 * Container} will inject the implementation instances as well. Sets the
492 * scope based on the @{@link Scoped} annotation on the implementation
493 * class if present.
494 */
495 public <I extends T> BindingBuilder<T> to(Class<I> implementation) {
crazyboblee0baa9fc2007-01-31 02:38:54 +0000496 return to(TypeLiteral.get(implementation));
crazyboblee7c5b2c42007-01-20 02:05:20 +0000497 }
498
499 /**
500 * Binds to instances of the given implementation type. The {@link
501 * Container} will inject the implementation instances as well. Sets the
502 * scope based on the @{@link Scoped} annotation on the implementation
503 * class if present.
504 */
crazyboblee0baa9fc2007-01-31 02:38:54 +0000505 public <I extends T> BindingBuilder<T> to(TypeLiteral<I> implementation) {
crazyboblee7c5b2c42007-01-20 02:05:20 +0000506 ensureImplementationIsNotSet();
crazyboblee4727ee22007-01-30 03:13:38 +0000507 validate(source, implementation.getRawType());
crazyboblee7289ac12007-02-01 00:28:09 +0000508 this.factory = new DefaultFactory<I>(key, implementation);
crazyboblee7c5b2c42007-01-20 02:05:20 +0000509 setScopeFromType(implementation.getRawType());
510 return this;
511 }
512
513 private void setScopeFromType(Class<?> implementation) {
514 Scoped scoped = implementation.getAnnotation(Scoped.class);
515 if (scoped != null) {
516 in(scoped.value());
517 }
518 }
519
520 /**
521 * Binds to instances from the given factory.
522 */
523 public BindingBuilder<T> to(
524 final ContextualFactory<? extends T> factory) {
525 ensureImplementationIsNotSet();
526
crazyboblee7289ac12007-02-01 00:28:09 +0000527 this.factory = new InternalToContextualFactoryAdapter<T>(factory);
crazyboblee7c5b2c42007-01-20 02:05:20 +0000528
529 return this;
530 }
531
532 /**
533 * Binds to instances from the given factory.
534 */
535 public BindingBuilder<T> to(final Factory<? extends T> factory) {
536 ensureImplementationIsNotSet();
crazyboblee7289ac12007-02-01 00:28:09 +0000537 this.factory = new InternalFactoryToFactoryAdapter<T>(factory);
crazyboblee7c5b2c42007-01-20 02:05:20 +0000538 return this;
539 }
540
541 /**
542 * Binds to the given instance.
543 */
544 BindingBuilder<T> to(T instance) {
545 ensureImplementationIsNotSet();
546 this.factory = new ConstantFactory<T>(instance);
547 return this;
548 }
549
550 /**
551 * Binds to instances from the given factory.
552 */
553 BindingBuilder<T> to(final InternalFactory<? extends T> factory) {
554 ensureImplementationIsNotSet();
555 this.factory = factory;
556 return this;
557 }
558
559 /**
560 * Adds an error message if the implementation has already been bound.
561 */
562 private void ensureImplementationIsNotSet() {
563 if (factory != null) {
crazyboblee235d0682007-01-31 02:25:21 +0000564 addError(source, ErrorMessage.IMPLEMENTATION_ALREADY_SET);
crazyboblee7c5b2c42007-01-20 02:05:20 +0000565 }
566 }
567
568 /**
crazyboblee63b592b2007-01-25 02:45:24 +0000569 * Specifies the scope. References the name passed to {@link
570 * ContainerBuilder#put(String, Scope)}.
crazyboblee7c5b2c42007-01-20 02:05:20 +0000571 */
crazyboblee63b592b2007-01-25 02:45:24 +0000572 public BindingBuilder<T> in(String scopeName) {
573 ensureScopeNotSet();
crazyboblee7c5b2c42007-01-20 02:05:20 +0000574
crazyboblee63b592b2007-01-25 02:45:24 +0000575 // We could defer this lookup to when we create the container, but this
576 // is fine for now.
crazyboblee235d0682007-01-31 02:25:21 +0000577 this.scope = scopes.get(nonNull(scopeName, "scope name"));
crazyboblee63b592b2007-01-25 02:45:24 +0000578 if (this.scope == null) {
crazyboblee235d0682007-01-31 02:25:21 +0000579 addError(source, ErrorMessage.SCOPE_NOT_FOUND, scopeName,
580 scopes.keySet());
crazyboblee63b592b2007-01-25 02:45:24 +0000581 }
crazyboblee7c5b2c42007-01-20 02:05:20 +0000582 return this;
583 }
584
crazyboblee63b592b2007-01-25 02:45:24 +0000585 /**
586 * Specifies the scope.
587 */
588 public BindingBuilder<T> in(Scope scope) {
589 ensureScopeNotSet();
590
591 this.scope = nonNull(scope, "scope");
592 return this;
593 }
594
595 private void ensureScopeNotSet() {
596 if (this.scope != null) {
crazyboblee235d0682007-01-31 02:25:21 +0000597 addError(source, ErrorMessage.SCOPE_ALREADY_SET);
crazyboblee63b592b2007-01-25 02:45:24 +0000598 }
599 }
600
crazybobleeabc4dd02007-02-01 01:44:36 +0000601 /**
602 * Instructs the builder to eagerly load this binding when it creates
603 * the container. Useful for application initialization logic. Currently
604 * only supported for container-scoped bindings.
605 */
606 public BindingBuilder<T> preload() {
607 this.preload = true;
608 return this;
609 }
610
611 boolean shouldPreload() {
612 return preload;
613 }
614
crazyboblee63b592b2007-01-25 02:45:24 +0000615 InternalFactory<? extends T> getInternalFactory(
616 final ContainerImpl container) {
crazyboblee7c5b2c42007-01-20 02:05:20 +0000617 // If an implementation wasn't specified, use the injection type.
618 if (this.factory == null) {
crazyboblee0baa9fc2007-01-31 02:38:54 +0000619 to(key.getType());
crazyboblee7c5b2c42007-01-20 02:05:20 +0000620 }
621
crazyboblee63b592b2007-01-25 02:45:24 +0000622 if (scope == null || scope == DEFAULT_SCOPE) {
crazyboblee7c5b2c42007-01-20 02:05:20 +0000623 return this.factory;
624 }
625
crazyboblee7289ac12007-02-01 00:28:09 +0000626 Factory<T> scoped = scope.scope(this.key,
627 new FactoryToInternalFactoryAdapter<T>(container, this.factory));
628 return new InternalFactoryToFactoryAdapter<T>(scoped);
crazyboblee7c5b2c42007-01-20 02:05:20 +0000629 }
630
crazyboblee235d0682007-01-31 02:25:21 +0000631 boolean isInContainerScope() {
632 return this.scope == ContainerScope.INSTANCE;
crazyboblee7c5b2c42007-01-20 02:05:20 +0000633 }
crazyboblee7289ac12007-02-01 00:28:09 +0000634 }
crazyboblee7c5b2c42007-01-20 02:05:20 +0000635
crazyboblee7289ac12007-02-01 00:28:09 +0000636 /**
637 * Injects new instances of the specified implementation class.
638 */
639 private static class DefaultFactory<T> implements InternalFactory<T> {
crazyboblee7c5b2c42007-01-20 02:05:20 +0000640
crazyboblee7289ac12007-02-01 00:28:09 +0000641 volatile ContainerImpl.ConstructorInjector<T> constructor;
crazyboblee7c5b2c42007-01-20 02:05:20 +0000642
crazyboblee7289ac12007-02-01 00:28:09 +0000643 private final TypeLiteral<T> implementation;
644 private final Key<? super T> key;
crazyboblee7c5b2c42007-01-20 02:05:20 +0000645
crazyboblee7289ac12007-02-01 00:28:09 +0000646 public DefaultFactory(Key<? super T> key, TypeLiteral<T> implementation) {
647 this.key = key;
648 this.implementation = implementation;
649 }
650
651 @SuppressWarnings("unchecked")
652 public T get(InternalContext context) {
653 if (constructor == null) {
654 // This unnecessary cast is a workaround for an annoying compiler
655 // bug I keep running into.
656 Object c = context.getContainerImpl().getConstructor(implementation);
657 this.constructor = (ContainerImpl.ConstructorInjector<T>) c;
crazyboblee7c5b2c42007-01-20 02:05:20 +0000658 }
crazyboblee7289ac12007-02-01 00:28:09 +0000659 return (T) constructor.construct(context, key.getRawType());
660 }
crazyboblee7c5b2c42007-01-20 02:05:20 +0000661
crazyboblee7289ac12007-02-01 00:28:09 +0000662 public String toString() {
663 return implementation.toString();
crazyboblee7c5b2c42007-01-20 02:05:20 +0000664 }
665 }
666
667 /**
668 * Builds a constant binding.
669 */
crazyboblee63b592b2007-01-25 02:45:24 +0000670 public class ConstantBindingBuilder {
crazyboblee7c5b2c42007-01-20 02:05:20 +0000671
672 final String name;
673 Class<?> type;
674 Object value;
675 Object source = ContainerBuilder.UNKNOWN_SOURCE;
676
677 ConstantBindingBuilder(String name) {
678 this.name = name;
679 }
680
681 Key<?> getKey() {
682 return Key.get(type, name);
683 }
684
685 boolean hasValue() {
686 return type != null;
687 }
688
689 Object getSource() {
690 return source;
691 }
692
693 InternalFactory<?> getInternalFactory() {
694 return new ConstantFactory<Object>(value);
695 }
696
crazyboblee63b592b2007-01-25 02:45:24 +0000697 ConstantBindingBuilder from(Object source) {
crazyboblee7c5b2c42007-01-20 02:05:20 +0000698 this.source = source;
699 return this;
700 }
701
702 /**
703 * Binds constant to the given value.
704 */
crazyboblee78e1cc12007-01-26 02:18:06 +0000705 public void to(String value) {
706 to(String.class, value);
crazyboblee7c5b2c42007-01-20 02:05:20 +0000707 }
708
709 /**
710 * Binds constant to the given value.
711 */
crazyboblee78e1cc12007-01-26 02:18:06 +0000712 public void to(int value) {
713 to(int.class, value);
crazyboblee7c5b2c42007-01-20 02:05:20 +0000714 }
715
716 /**
717 * Binds constant to the given value.
718 */
crazyboblee78e1cc12007-01-26 02:18:06 +0000719 public void to(long value) {
720 to(long.class, value);
crazyboblee7c5b2c42007-01-20 02:05:20 +0000721 }
722
723 /**
724 * Binds constant to the given value.
725 */
crazyboblee78e1cc12007-01-26 02:18:06 +0000726 public void to(boolean value) {
727 to(boolean.class, value);
crazyboblee7c5b2c42007-01-20 02:05:20 +0000728 }
729
730 /**
731 * Binds constant to the given value.
732 */
crazyboblee78e1cc12007-01-26 02:18:06 +0000733 public void to(double value) {
734 to(double.class, value);
crazyboblee7c5b2c42007-01-20 02:05:20 +0000735 }
736
737 /**
738 * Binds constant to the given value.
739 */
crazyboblee78e1cc12007-01-26 02:18:06 +0000740 public void to(float value) {
741 to(float.class, value);
crazyboblee7c5b2c42007-01-20 02:05:20 +0000742 }
743
744 /**
745 * Binds constant to the given value.
746 */
crazyboblee78e1cc12007-01-26 02:18:06 +0000747 public void to(short value) {
748 to(short.class, value);
crazyboblee7c5b2c42007-01-20 02:05:20 +0000749 }
750
751 /**
752 * Binds constant to the given value.
753 */
crazyboblee78e1cc12007-01-26 02:18:06 +0000754 public void to(char value) {
755 to(char.class, value);
crazyboblee7c5b2c42007-01-20 02:05:20 +0000756 }
757
758 /**
759 * Binds constant to the given value.
760 */
crazyboblee78e1cc12007-01-26 02:18:06 +0000761 public void to(Class<?> value) {
762 to(Class.class, value);
crazyboblee7c5b2c42007-01-20 02:05:20 +0000763 }
764
765 /**
766 * Binds constant to the given value.
767 */
crazyboblee78e1cc12007-01-26 02:18:06 +0000768 public <E extends Enum<E>> void to(E value) {
769 to(value.getDeclaringClass(), value);
crazyboblee7c5b2c42007-01-20 02:05:20 +0000770 }
771
772 /**
773 * Maps a constant value to the given type and name.
774 */
crazyboblee78e1cc12007-01-26 02:18:06 +0000775 <T> void to(final Class<T> type, final T value) {
crazyboblee235d0682007-01-31 02:25:21 +0000776 if (this.value != null) {
777 addError(source, ErrorMessage.CONSTANT_VALUE_ALREADY_SET);
778 } else {
779 this.type = type;
780 this.value = value;
781 }
crazyboblee7c5b2c42007-01-20 02:05:20 +0000782 }
783 }
784
785 /**
786 * Links one binding to another.
787 */
crazyboblee63b592b2007-01-25 02:45:24 +0000788 public class LinkedBindingBuilder<T> {
crazyboblee7c5b2c42007-01-20 02:05:20 +0000789
790 Key<T> key;
791 Key<? extends T> destination;
792 Object source = ContainerBuilder.UNKNOWN_SOURCE;
793
794 LinkedBindingBuilder(Key<T> key) {
795 this.key = key;
796 }
797
798 Object getSource() {
799 return source;
800 }
801
802 Key<T> getKey() {
803 return key;
804 }
805
806 Key<? extends T> getDestination() {
807 return destination;
808 }
809
crazyboblee63b592b2007-01-25 02:45:24 +0000810 LinkedBindingBuilder<T> from(Object source) {
crazyboblee7c5b2c42007-01-20 02:05:20 +0000811 this.source = source;
812 return this;
813 }
814
815 /**
816 * Links to another binding with the given key.
817 */
crazyboblee78e1cc12007-01-26 02:18:06 +0000818 public void to(Key<? extends T> destination) {
crazyboblee235d0682007-01-31 02:25:21 +0000819 if (this.destination != null) {
820 addError(source, ErrorMessage.LINK_DESTINATION_ALREADY_SET);
821 } else {
822 this.destination = destination;
823 }
crazyboblee7c5b2c42007-01-20 02:05:20 +0000824 }
825 }
crazyboblee4727ee22007-01-30 03:13:38 +0000826
crazyboblee235d0682007-01-31 02:25:21 +0000827 /**
828 * Handles errors up until we successfully create the container.
829 */
830 class ConfigurationErrorHandler extends AbstractErrorHandler {
crazyboblee4727ee22007-01-30 03:13:38 +0000831
832 final Object source;
833
834 ConfigurationErrorHandler(Object source) {
835 this.source = source;
836 }
837
838 public void handle(String message) {
839 add(new ErrorMessage(source, message));
840 }
841
842 public void handle(Throwable t) {
843 add(new ErrorMessage(source, t.getMessage()));
844 }
845 }
846
crazyboblee235d0682007-01-31 02:25:21 +0000847 /**
848 * Handles errors after the container is created.
849 */
850 class RuntimeErrorHandler extends AbstractErrorHandler {
crazyboblee4727ee22007-01-30 03:13:38 +0000851
852 public void handle(String message) {
853 throw new ConfigurationException(message);
854 }
855
856 public void handle(Throwable t) {
857 throw new ConfigurationException(t);
858 }
859 }
crazyboblee235d0682007-01-31 02:25:21 +0000860
861 final Set<String> skippedClassNames = new HashSet<String>(Arrays.asList(
862 ContainerBuilder.class.getName(),
863 AbstractModule.class.getName()
864 ));
865
866 /**
867 * Instructs the builder to skip the given class in the stack trace when
868 * determining the source of a binding. Use this to keep the container
869 * builder from logging utility methods as the sources of bindings (i.e.
870 * it will skip to the utility methods' callers instead).
871 *
872 * <p>Skipping only takes place after this method is called.
873 */
874 void skipSource(Class<?> clazz) {
875 skippedClassNames.add(clazz.getName());
876 }
877
878 /**
879 * Creates an object pointing to the current location within the
880 * configuration. If we run into a problem later, we'll be able to trace it
881 * back to the original source. Useful for debugging. The default
882 * implementation returns {@code ContainerBuilder}'s caller's {@code
883 * StackTraceElement}.
884 */
885 Object source() {
886 // Search up the stack until we find a class outside of this one.
887 for (final StackTraceElement element : new Throwable().getStackTrace()) {
888 String className = element.getClassName();
889 if (!skippedClassNames.contains(className)) {
890 return element;
891 }
892 }
893 throw new AssertionError();
894 }
crazybobleeef83bd22007-02-01 00:52:57 +0000895
896 /**
897 * A requested static injection.
898 */
899 class StaticInjection {
900
901 final Object source;
902 final Class<?>[] types;
903 final List<ContainerImpl.Injector> injectors =
904 new ArrayList<ContainerImpl.Injector>();
905
906 public StaticInjection(Object source, Class<?>[] types) {
907 this.source = source;
908 this.types = types;
909 }
910
911 void createInjectors(final ContainerImpl container) {
912 container.withErrorHandler(new ConfigurationErrorHandler(source),
913 new Runnable() {
914 public void run() {
915 for (Class<?> clazz : types) {
916 container.addInjectorsForFields(
917 clazz.getDeclaredFields(), true, injectors);
918 container.addInjectorsForMethods(
919 clazz.getDeclaredMethods(), true, injectors);
920 }
921 }
922 });
923 }
924
925 void runInjectors(ContainerImpl container) {
926 container.callInContext(new ContainerImpl.ContextualCallable<Void>() {
927 public Void call(InternalContext context) {
928 for (ContainerImpl.Injector injector : injectors) {
929 injector.inject(context, null);
930 }
931 return null;
932 }
933 });
934 }
935 }
crazybobleeabc4dd02007-02-01 01:44:36 +0000936
937 static class BindingPreloader
938 implements ContainerImpl.ContextualCallable<Void> {
939
940 private final Key<?> key;
941 private final InternalFactory<?> factory;
942
943 public BindingPreloader(Key<?> key, InternalFactory<?> factory) {
944 this.key = key;
945 this.factory = factory;
946 }
947
948 public Void call(InternalContext context) {
949 ExternalContext<?> externalContext =
950 ExternalContext.newInstance(null, key, context.getContainerImpl());
951 context.setExternalContext(externalContext);
952 try {
953 factory.get(context);
954 return null;
955 } finally {
956 context.setExternalContext(null);
957 }
958 }
959 }
crazyboblee66b415a2006-08-25 02:01:19 +0000960}