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