001: /*
002: * Copyright (C) 2007 Google Inc.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016:
017: package com.google.inject;
018:
019: import com.google.inject.BinderImpl.CreationListener;
020: import com.google.inject.binder.ScopedBindingBuilder;
021: import com.google.inject.binder.AnnotatedBindingBuilder;
022: import com.google.inject.util.Annotations;
023: import com.google.inject.util.Objects;
024: import com.google.inject.util.StackTraceElements;
025: import com.google.inject.util.ToStringBuilder;
026: import java.lang.annotation.Annotation;
027: import java.util.logging.Level;
028: import java.util.logging.Logger;
029:
030: /**
031: * Binds a {@link com.google.inject.Key} to an implementation in a given scope.
032: */
033: class BindingBuilderImpl<T> implements AnnotatedBindingBuilder<T> {
034:
035: private static final Logger logger = Logger
036: .getLogger(BindingBuilderImpl.class.getName());
037:
038: final Object source;
039: Key<T> key;
040: InternalFactory<? extends T> factory;
041: T instance;
042: Scope scope;
043: boolean preload = false;
044: private BinderImpl binder;
045:
046: BindingBuilderImpl(BinderImpl binder, Key<T> key, Object source) {
047: this .binder = binder;
048: this .key = Objects.nonNull(key, "key");
049: this .source = source;
050: }
051:
052: Object getSource() {
053: return source;
054: }
055:
056: Key<T> getKey() {
057: return key;
058: }
059:
060: public BindingBuilderImpl<T> annotatedWith(
061: Class<? extends Annotation> annotationType) {
062: if (this .key.hasAnnotationType()) {
063: binder.addError(source,
064: ErrorMessages.ANNOTATION_ALREADY_SPECIFIED);
065: } else {
066: boolean retainedAtRuntime = Annotations
067: .isRetainedAtRuntime(annotationType);
068: boolean bindingAnnotation = Key
069: .isBindingAnnotation(annotationType);
070:
071: if (!retainedAtRuntime) {
072: binder.addError(StackTraceElements
073: .forType(annotationType),
074: ErrorMessages.MISSING_RUNTIME_RETENTION, binder
075: .source());
076: }
077:
078: if (!bindingAnnotation) {
079: binder.addError(StackTraceElements
080: .forType(annotationType),
081: ErrorMessages.MISSING_BINDING_ANNOTATION,
082: binder.source());
083: }
084:
085: if (retainedAtRuntime && bindingAnnotation) {
086: this .key = Key.get(this .key.getTypeLiteral(),
087: annotationType);
088: }
089: }
090: return this ;
091: }
092:
093: public BindingBuilderImpl<T> annotatedWith(Annotation annotation) {
094: if (this .key.hasAnnotationType()) {
095: binder.addError(source,
096: ErrorMessages.ANNOTATION_ALREADY_SPECIFIED);
097: } else {
098: Class<? extends Annotation> annotationType = annotation
099: .annotationType();
100:
101: boolean retainedAtRuntime = Annotations
102: .isRetainedAtRuntime(annotationType);
103: boolean bindingAnnotation = Key
104: .isBindingAnnotation(annotationType);
105:
106: if (!retainedAtRuntime) {
107: binder.addError(StackTraceElements
108: .forType(annotationType),
109: ErrorMessages.MISSING_RUNTIME_RETENTION, binder
110: .source());
111: }
112:
113: if (!bindingAnnotation) {
114: binder.addError(StackTraceElements
115: .forType(annotationType),
116: ErrorMessages.MISSING_BINDING_ANNOTATION,
117: binder.source());
118: }
119:
120: if (retainedAtRuntime && bindingAnnotation) {
121: this .key = Key.get(this .key.getTypeLiteral(),
122: annotation);
123: }
124: }
125: return this ;
126: }
127:
128: public ScopedBindingBuilder to(Class<? extends T> implementation) {
129: return to(TypeLiteral.get(implementation));
130: }
131:
132: public ScopedBindingBuilder to(
133: TypeLiteral<? extends T> implementation) {
134: return to(Key.get(implementation));
135: }
136:
137: public ScopedBindingBuilder to(Key<? extends T> targetKey) {
138: ensureImplementationIsNotSet();
139:
140: if (key.equals(targetKey)) {
141: binder.addError(source, ErrorMessages.RECURSIVE_BINDING);
142: }
143:
144: final FactoryProxy<? extends T> factoryProxy = new FactoryProxy<T>(
145: key, targetKey, source);
146: this .factory = factoryProxy;
147: binder.creationListeners.add(factoryProxy);
148: return this ;
149: }
150:
151: public void toInstance(T instance) {
152: ensureImplementationIsNotSet();
153: this .instance = Objects.nonNull(instance, "instance");
154: this .factory = new ConstantFactory<T>(instance);
155: registerInstanceForInjection(instance);
156: if (this .scope != null) {
157: binder.addError(source,
158: ErrorMessages.SINGLE_INSTANCE_AND_SCOPE);
159: }
160: }
161:
162: /**
163: * Binds to instances from the given factory.
164: */
165: BindingBuilderImpl<T> to(InternalFactory<? extends T> factory) {
166: ensureImplementationIsNotSet();
167: this .factory = factory;
168: return this ;
169: }
170:
171: public ScopedBindingBuilder toProvider(
172: Provider<? extends T> provider) {
173: ensureImplementationIsNotSet();
174: this .factory = new InternalFactoryToProviderAdapter<T>(
175: provider, source);
176: registerInstanceForInjection(provider);
177: return this ;
178: }
179:
180: public BindingBuilderImpl<T> toProvider(
181: Class<? extends Provider<? extends T>> providerType) {
182: return toProvider(Key.get(providerType));
183: }
184:
185: public BindingBuilderImpl<T> toProvider(
186: Key<? extends Provider<? extends T>> providerKey) {
187: ensureImplementationIsNotSet();
188:
189: final BoundProviderFactory<T> boundProviderFactory = new BoundProviderFactory<T>(
190: providerKey, source);
191: binder.creationListeners.add(boundProviderFactory);
192: this .factory = boundProviderFactory;
193:
194: return this ;
195: }
196:
197: /**
198: * Adds an error message if the implementation has already been bound.
199: */
200: private void ensureImplementationIsNotSet() {
201: if (factory != null) {
202: binder.addError(source,
203: ErrorMessages.IMPLEMENTATION_ALREADY_SET);
204: }
205: }
206:
207: public void in(Class<? extends Annotation> scopeAnnotation) {
208: // this method not test-covered
209: ensureScopeNotSet();
210:
211: // We could defer this lookup to when we create the Injector, but this
212: // is fine for now.
213: this .scope = binder.scopes.get(Objects.nonNull(scopeAnnotation,
214: "scope annotation"));
215: if (this .scope == null) {
216: binder.addError(source, ErrorMessages.SCOPE_NOT_FOUND, "@"
217: + scopeAnnotation.getSimpleName());
218: }
219: }
220:
221: public void in(Scope scope) {
222: ensureScopeNotSet();
223: this .scope = Objects.nonNull(scope, "scope");
224: }
225:
226: private void ensureScopeNotSet() {
227: // Scoping isn't allowed when we have only one instance.
228: if (this .instance != null) {
229: binder.addError(source,
230: ErrorMessages.SINGLE_INSTANCE_AND_SCOPE);
231: return;
232: }
233:
234: if (this .scope != null) {
235: binder.addError(source, ErrorMessages.SCOPE_ALREADY_SET);
236: }
237: }
238:
239: public void asEagerSingleton() {
240: in(Scopes.SINGLETON);
241: this .preload = true;
242: }
243:
244: boolean shouldPreload() {
245: return preload;
246: }
247:
248: InternalFactory<? extends T> getInternalFactory(
249: InjectorImpl injector) {
250: if (this .factory == null && !key.hasAnnotationType()) {
251: // Try an implicit binding.
252: final ImplicitImplementation<T> implicitImplementation = new ImplicitImplementation<T>(
253: key, scope, source);
254: binder.creationListeners.add(implicitImplementation);
255:
256: // We need to record the scope. If it's singleton, we'll preload in prod.
257: if (this .scope == null) {
258: // We can ignore errors because the error will already have been
259: // recorded.
260: this .scope = Scopes.getScopeForType(key
261: .getTypeLiteral().getRawType(), binder.scopes,
262: IGNORE_ERRORS);
263: }
264:
265: return implicitImplementation;
266: }
267:
268: return Scopes.scope(this .key, injector, this .factory, scope);
269: }
270:
271: boolean isSingletonScoped() {
272: return this .scope == Scopes.SINGLETON;
273: }
274:
275: void registerInstanceForInjection(final Object o) {
276: binder.instanceInjectors.add(new CreationListener() {
277: public void notify(InjectorImpl injector) {
278: try {
279: injector.injectMembers(o);
280: } catch (Exception e) {
281: String className = e.getClass().getSimpleName();
282: String message = ErrorMessages.getRootMessage(e);
283: String logMessage = String.format(
284: ErrorMessages.ERROR_INJECTING_MEMBERS, o,
285: message);
286: logger.log(Level.INFO, logMessage, e);
287: binder
288: .addError(
289: source,
290: ErrorMessages.ERROR_INJECTING_MEMBERS_SEE_LOG,
291: className, o, message);
292: }
293: }
294: });
295: }
296:
297: /**
298: * A placeholder which enables us to swap in the real factory once the
299: * container is created.
300: */
301: private static class FactoryProxy<T> implements InternalFactory<T>,
302: CreationListener {
303:
304: private final Key<T> key;
305: private final Key<? extends T> targetKey;
306: private final Object source;
307:
308: InternalFactory<? extends T> targetFactory;
309:
310: FactoryProxy(Key<T> key, Key<? extends T> targetKey,
311: Object source) {
312: this .key = key;
313: this .targetKey = targetKey;
314: this .source = source;
315: }
316:
317: public void notify(final InjectorImpl injector) {
318: injector.withDefaultSource(source, new Runnable() {
319: public void run() {
320: targetFactory = injector.getInternalFactory(null,
321: targetKey);
322: }
323: });
324: }
325:
326: public T get(InternalContext context) {
327: return targetFactory.get(context);
328: }
329:
330: public String toString() {
331: return new ToStringBuilder(FactoryProxy.class).add("key",
332: key).add("provider", targetFactory).toString();
333: }
334: }
335:
336: private static class ImplicitImplementation<T> implements
337: InternalFactory<T>, CreationListener {
338:
339: private final Key<T> key;
340: private final Object source;
341: private final Scope scope;
342: InternalFactory<? extends T> implicitFactory;
343:
344: ImplicitImplementation(Key<T> key, Scope scope, Object source) {
345: this .key = key;
346: this .scope = scope;
347: this .source = source;
348: }
349:
350: public void notify(final InjectorImpl injector) {
351: injector.withDefaultSource(source, new Runnable() {
352: public void run() {
353: implicitFactory = injector.getImplicitBinding(null,
354: (Class) key.getTypeLiteral().getRawType(),
355: scope);
356: }
357: });
358: }
359:
360: public T get(InternalContext context) {
361: return implicitFactory.get(context);
362: }
363:
364: public String toString() {
365: return new ToStringBuilder(FactoryProxy.class).add("key",
366: key).add("provider", implicitFactory).toString();
367: }
368: }
369:
370: static ErrorHandler IGNORE_ERRORS = new ErrorHandler() {
371: public void handle(Object source, String message) {
372: }
373:
374: public void handle(Object source, String message,
375: Object... arguments) {
376: }
377: };
378: }
|