KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > google > inject > BindingBuilderImpl


1 /*
2  * Copyright (C) 2007 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
17 package com.google.inject;
18
19 import com.google.inject.BinderImpl.CreationListener;
20 import com.google.inject.binder.ScopedBindingBuilder;
21 import com.google.inject.binder.AnnotatedBindingBuilder;
22 import com.google.inject.util.Annotations;
23 import com.google.inject.util.Objects;
24 import com.google.inject.util.StackTraceElements;
25 import com.google.inject.util.ToStringBuilder;
26 import java.lang.annotation.Annotation JavaDoc;
27 import java.util.logging.Level JavaDoc;
28 import java.util.logging.Logger JavaDoc;
29
30 /**
31  * Binds a {@link com.google.inject.Key} to an implementation in a given scope.
32  */

33 class BindingBuilderImpl<T> implements AnnotatedBindingBuilder<T> {
34
35   private static final Logger JavaDoc logger
36       = Logger.getLogger(BindingBuilderImpl.class.getName());
37
38   final Object JavaDoc source;
39   Key<T> key;
40   InternalFactory<? extends T> factory;
41   T instance;
42   Scope scope;
43   boolean preload = false;
44   private BinderImpl binder;
45
46   BindingBuilderImpl(BinderImpl binder, Key<T> key, Object JavaDoc source) {
47     this.binder = binder;
48     this.key = Objects.nonNull(key, "key");
49     this.source = source;
50   }
51
52   Object JavaDoc getSource() {
53     return source;
54   }
55
56   Key<T> getKey() {
57     return key;
58   }
59
60   public BindingBuilderImpl<T> annotatedWith(
61       Class JavaDoc<? extends Annotation JavaDoc> annotationType) {
62     if (this.key.hasAnnotationType()) {
63       binder.addError(source, ErrorMessages.ANNOTATION_ALREADY_SPECIFIED);
64     } else {
65       boolean retainedAtRuntime =
66           Annotations.isRetainedAtRuntime(annotationType);
67       boolean bindingAnnotation = Key.isBindingAnnotation(annotationType);
68
69       if (!retainedAtRuntime) {
70         binder.addError(StackTraceElements.forType(annotationType),
71             ErrorMessages.MISSING_RUNTIME_RETENTION, binder.source());
72       }
73
74       if (!bindingAnnotation) {
75         binder.addError(StackTraceElements.forType(annotationType),
76             ErrorMessages.MISSING_BINDING_ANNOTATION, binder.source());
77       }
78
79       if (retainedAtRuntime && bindingAnnotation) {
80         this.key = Key.get(this.key.getTypeLiteral(), annotationType);
81       }
82     }
83     return this;
84   }
85
86   public BindingBuilderImpl<T> annotatedWith(Annotation JavaDoc annotation) {
87     if (this.key.hasAnnotationType()) {
88       binder.addError(source, ErrorMessages.ANNOTATION_ALREADY_SPECIFIED);
89     } else {
90       Class JavaDoc<? extends Annotation JavaDoc> annotationType = annotation.annotationType();
91
92       boolean retainedAtRuntime =
93           Annotations.isRetainedAtRuntime(annotationType);
94       boolean bindingAnnotation = Key.isBindingAnnotation(annotationType);
95
96       if (!retainedAtRuntime) {
97         binder.addError(StackTraceElements.forType(annotationType),
98             ErrorMessages.MISSING_RUNTIME_RETENTION, binder.source());
99       }
100
101       if (!bindingAnnotation) {
102         binder.addError(StackTraceElements.forType(annotationType),
103             ErrorMessages.MISSING_BINDING_ANNOTATION, binder.source());
104       }
105
106       if (retainedAtRuntime && bindingAnnotation) {
107         this.key = Key.get(this.key.getTypeLiteral(), annotation);
108       }
109     }
110     return this;
111   }
112
113   public ScopedBindingBuilder to(Class JavaDoc<? extends T> implementation) {
114     return to(TypeLiteral.get(implementation));
115   }
116
117   public ScopedBindingBuilder to(TypeLiteral<? extends T> implementation) {
118     return to(Key.get(implementation));
119   }
120
121   public ScopedBindingBuilder to(Key<? extends T> targetKey) {
122     ensureImplementationIsNotSet();
123
124     if (key.equals(targetKey)) {
125       binder.addError(source, ErrorMessages.RECURSIVE_BINDING);
126     }
127
128     final FactoryProxy<? extends T> factoryProxy =
129         new FactoryProxy<T>(key, targetKey, source);
130     this.factory = factoryProxy;
131     binder.creationListeners.add(factoryProxy);
132     return this;
133   }
134
135   public void toInstance(T instance) {
136     ensureImplementationIsNotSet();
137     this.instance = Objects.nonNull(instance, "instance");
138     this.factory = new ConstantFactory<T>(instance);
139     registerInstanceForInjection(instance);
140     if (this.scope != null) {
141       binder.addError(source, ErrorMessages.SINGLE_INSTANCE_AND_SCOPE);
142     }
143   }
144
145   /**
146    * Binds to instances from the given factory.
147    */

148   BindingBuilderImpl<T> to(InternalFactory<? extends T> factory) {
149     ensureImplementationIsNotSet();
150     this.factory = factory;
151     return this;
152   }
153
154   public ScopedBindingBuilder toProvider(Provider<? extends T> provider) {
155     ensureImplementationIsNotSet();
156     this.factory = new InternalFactoryToProviderAdapter<T>(provider, source);
157     registerInstanceForInjection(provider);
158     return this;
159   }
160
161   public BindingBuilderImpl<T> toProvider(
162       Class JavaDoc<? extends Provider<? extends T>> providerType) {
163     return toProvider(Key.get(providerType));
164   }
165
166   public BindingBuilderImpl<T> toProvider(
167       Key<? extends Provider<? extends T>> providerKey) {
168     ensureImplementationIsNotSet();
169
170     final BoundProviderFactory<T> boundProviderFactory =
171         new BoundProviderFactory<T>(providerKey, source);
172     binder.creationListeners.add(boundProviderFactory);
173     this.factory = boundProviderFactory;
174
175     return this;
176   }
177
178   /**
179    * Adds an error message if the implementation has already been bound.
180    */

181   private void ensureImplementationIsNotSet() {
182     if (factory != null) {
183       binder.addError(source, ErrorMessages.IMPLEMENTATION_ALREADY_SET);
184     }
185   }
186
187   public void in(Class JavaDoc<? extends Annotation JavaDoc> scopeAnnotation) {
188     // this method not test-covered
189
ensureScopeNotSet();
190
191     // We could defer this lookup to when we create the Injector, but this
192
// is fine for now.
193
this.scope = binder.scopes.get(
194         Objects.nonNull(scopeAnnotation, "scope annotation"));
195     if (this.scope == null) {
196       binder.addError(source, ErrorMessages.SCOPE_NOT_FOUND,
197           "@" + scopeAnnotation.getSimpleName());
198     }
199   }
200
201   public void in(Scope scope) {
202     ensureScopeNotSet();
203     this.scope = Objects.nonNull(scope, "scope");
204   }
205
206   private void ensureScopeNotSet() {
207     // Scoping isn't allowed when we have only one instance.
208
if (this.instance != null) {
209       binder.addError(source, ErrorMessages.SINGLE_INSTANCE_AND_SCOPE);
210       return;
211     }
212
213     if (this.scope != null) {
214       binder.addError(source, ErrorMessages.SCOPE_ALREADY_SET);
215     }
216   }
217
218   public void asEagerSingleton() {
219     in(Scopes.SINGLETON);
220     this.preload = true;
221   }
222
223   boolean shouldPreload() {
224     return preload;
225   }
226
227   InternalFactory<? extends T> getInternalFactory(InjectorImpl injector) {
228     if (this.factory == null && !key.hasAnnotationType()) {
229       // Try an implicit binding.
230
final ImplicitImplementation<T> implicitImplementation =
231           new ImplicitImplementation<T>(key, scope, source);
232       binder.creationListeners.add(implicitImplementation);
233
234       // We need to record the scope. If it's singleton, we'll preload in prod.
235
if (this.scope == null) {
236         // We can ignore errors because the error will already have been
237
// recorded.
238
this.scope = Scopes.getScopeForType(
239             key.getTypeLiteral().getRawType(), binder.scopes, IGNORE_ERRORS);
240       }
241
242       return implicitImplementation;
243     }
244
245     return Scopes.scope(this.key, injector, this.factory, scope);
246   }
247
248   boolean isSingletonScoped() {
249     return this.scope == Scopes.SINGLETON;
250   }
251
252   void registerInstanceForInjection(final Object JavaDoc o) {
253     binder.instanceInjectors.add(new CreationListener() {
254       public void notify(InjectorImpl injector) {
255         try {
256           injector.injectMembers(o);
257         }
258         catch (Exception JavaDoc e) {
259           String JavaDoc className = e.getClass().getSimpleName();
260           String JavaDoc message = ErrorMessages.getRootMessage(e);
261           String JavaDoc logMessage = String.format(
262               ErrorMessages.ERROR_INJECTING_MEMBERS, o, message);
263           logger.log(Level.INFO, logMessage, e);
264           binder.addError(source, ErrorMessages.ERROR_INJECTING_MEMBERS_SEE_LOG,
265               className, o, message);
266         }
267       }
268     });
269   }
270
271   /**
272    * A placeholder which enables us to swap in the real factory once the
273    * container is created.
274    */

275   private static class FactoryProxy<T> implements InternalFactory<T>,
276       CreationListener {
277
278     private final Key<T> key;
279     private final Key<? extends T> targetKey;
280     private final Object JavaDoc source;
281
282     InternalFactory<? extends T> targetFactory;
283
284     FactoryProxy(Key<T> key, Key<? extends T> targetKey, Object JavaDoc source) {
285       this.key = key;
286       this.targetKey = targetKey;
287       this.source = source;
288     }
289
290     public void notify(final InjectorImpl injector) {
291       injector.withDefaultSource(source, new Runnable JavaDoc() {
292         public void run() {
293           targetFactory = injector.getInternalFactory(null, targetKey);
294         }
295       });
296     }
297
298     public T get(InternalContext context) {
299       return targetFactory.get(context);
300     }
301
302     public String JavaDoc toString() {
303       return new ToStringBuilder(FactoryProxy.class)
304           .add("key", key)
305           .add("provider", targetFactory)
306           .toString();
307     }
308   }
309
310   private static class ImplicitImplementation<T> implements InternalFactory<T>,
311       CreationListener {
312
313     private final Key<T> key;
314     private final Object JavaDoc source;
315     private final Scope scope;
316     InternalFactory<? extends T> implicitFactory;
317
318     ImplicitImplementation(Key<T> key, Scope scope, Object JavaDoc source) {
319       this.key = key;
320       this.scope = scope;
321       this.source = source;
322     }
323
324     public void notify(final InjectorImpl injector) {
325       injector.withDefaultSource(source, new Runnable JavaDoc() {
326         public void run() {
327           implicitFactory = injector.getImplicitBinding(null,
328               (Class JavaDoc) key.getTypeLiteral().getRawType(), scope);
329         }
330       });
331     }
332
333     public T get(InternalContext context) {
334       return implicitFactory.get(context);
335     }
336
337     public String JavaDoc toString() {
338       return new ToStringBuilder(FactoryProxy.class)
339           .add("key", key)
340           .add("provider", implicitFactory)
341           .toString();
342     }
343   }
344
345   static ErrorHandler IGNORE_ERRORS = new ErrorHandler() {
346     public void handle(Object JavaDoc source, String JavaDoc message) {}
347     public void handle(Object JavaDoc source, String JavaDoc message, Object JavaDoc... arguments) {}
348   };
349 }
350
Popular Tags