View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.onami.factoryannotation;
20  
21  import static com.google.common.base.Preconditions.checkNotNull;
22  
23  import java.lang.annotation.Annotation;
24  import java.lang.reflect.Field;
25  import java.util.List;
26  import java.util.Set;
27  
28  import com.google.common.collect.ImmutableSet;
29  import com.google.inject.Binder;
30  import com.google.inject.Key;
31  import com.google.inject.ProvisionException;
32  import com.google.inject.TypeLiteral;
33  import com.google.inject.matcher.Matchers;
34  import com.google.inject.spi.BindingTargetVisitor;
35  import com.google.inject.spi.DefaultBindingTargetVisitor;
36  import com.google.inject.spi.Dependency;
37  import com.google.inject.spi.DependencyAndSource;
38  import com.google.inject.spi.HasDependencies;
39  import com.google.inject.spi.InjectionPoint;
40  import com.google.inject.spi.ProviderInstanceBinding;
41  import com.google.inject.spi.ProviderWithExtensionVisitor;
42  import com.google.inject.spi.ProvisionListener;
43  import com.google.inject.spi.TypeEncounter;
44  import com.google.inject.spi.TypeListener;
45  
46  final class FactoryAnnotationProviderFactory<T, A extends Annotation>
47      extends DefaultBindingTargetVisitor<T, Object>
48      implements TypeListener, ProviderWithExtensionVisitor<T>, HasDependencies, ProvisionListener,
49      FactoryAnnotationBinding<T, A>
50  {
51  
52      private final Class<A> annotationType;
53  
54      private final FactoryAnnotationProvider<T, A> factoryAnnotationProvider;
55  
56      private final Key<FactoryAnnotationProvider<T, A>> targetKey;
57  
58      private final TypeLiteral<T> elementTypeLiteral;
59  
60      private final FactoryAnnotationProvisionListener<T, A> provisionListener;
61  
62      private final ThreadLocal<A> provision = new ThreadLocal<A>();
63  
64      @SuppressWarnings( "unchecked" )
65      FactoryAnnotationProviderFactory( final Binder binder, final Class<A> annotationType,
66                                        final FactoryAnnotationProvider<T, A> factoryAnnotationProvider,
67                                        final FactoryAnnotationProvisionListener<T, A> listener, final boolean cacheable )
68      {
69  
70          this.annotationType = annotationType;
71  
72          this.provisionListener = listener;
73  
74          this.targetKey = (Key<FactoryAnnotationProvider<T, A>>) Key.get( factoryAnnotationProvider.getClass() );
75  
76          this.elementTypeLiteral = TypeLiteral.get( factoryAnnotationProvider.getInjectionType() );
77  
78          final FactoryAnnotationProvider<T, A> adapter =
79              new FactoryAnnotationProviderInjectionAdapter<T, A>( factoryAnnotationProvider );
80  
81          // Request injection of the FactoryAnnotationProvider and the adapter before we
82          // want to use it to meet possible requirements of the inner
83          // implementation
84          binder.requestInjection( adapter );
85          binder.requestInjection( factoryAnnotationProvider );
86  
87          // If values can be cached initialize the caching map
88          if ( cacheable )
89          {
90              this.factoryAnnotationProvider = new ProvisionCacheIdentityProviderFacade<T, A>( adapter, elementTypeLiteral );
91  
92              // Now we need to request injection for cache provider as well
93              binder.requestInjection( this.factoryAnnotationProvider );
94  
95          }
96          else
97          {
98              this.factoryAnnotationProvider = adapter;
99          }
100 
101         binder.bindListener( Matchers.any(), this );
102         binder.bindListener( Matchers.any(), (ProvisionListener) this );
103     }
104 
105     public T get()
106     {
107         final A annotation = provision.get();
108         if ( annotation == null )
109         {
110             throw new ProvisionException( "No legal provision" );
111         }
112 
113         // Delete value from ThreadLocal store
114         provision.set( null );
115 
116         // Return the provisioned (real) value
117         return factoryAnnotationProvider.buildValue( annotation );
118     }
119 
120     public <I> void hear( final TypeLiteral<I> type, final TypeEncounter<I> encounter )
121     {
122 
123         // Search for fields that needs to be injected
124         for ( final Field field : type.getRawType().getDeclaredFields() )
125         {
126             if ( field.isAnnotationPresent( annotationType ) )
127             {
128                 final A annotation = annotationType.cast( field.getAnnotation( annotationType ) );
129 
130                 final Set<InjectionPoint> injectionPoints =
131                     InjectionPoint.forInstanceMethodsAndFields( type.getRawType() );
132 
133                 FactoryAnnotationProvision<T, A> identityProvision = null;
134                 if ( injectionPoints.size() > 0 )
135                 {
136                     for ( final InjectionPoint ip : injectionPoints )
137                     {
138                         if ( ip.getMember().equals( field ) )
139                         {
140                             identityProvision = FactoryAnnotationProvisionImpl.wrapInjectionPoint( ip, annotation );
141                         }
142                     }
143 
144                 }
145 
146                 if ( identityProvision == null )
147                 {
148                     identityProvision =
149                         new FactoryAnnotationProvisionImpl<T, A>( field, annotation, field.getAnnotations(),
150                                                                   elementTypeLiteral );
151                 }
152 
153                 // Register a MembersInjector per field which actually will do
154                 // the injection for Guice
155                 encounter.register( FactoryAnnotationSingleFieldMemberInjector.buildMemberInjector( factoryAnnotationProvider,
156                                                                                                     field,
157                                                                                                     provisionListener,
158                                                                                                     annotation,
159                                                                                                     identityProvision ) );
160 
161             }
162         }
163     }
164 
165     public <I> void onProvision( final ProvisionInvocation<I> provision )
166     {
167         final List<DependencyAndSource> dependencies = provision.getDependencyChain();
168 
169         // OK here we are at constructor or method injection so let's get the
170         // real annotation at the type
171         for ( final DependencyAndSource dependency : dependencies )
172         {
173             if ( dependency.getDependency() == null )
174             {
175                 continue;
176             }
177 
178             final Annotation annotation = dependency.getDependency().getKey().getAnnotation();
179 
180             if ( annotation != null )
181             {
182                 if ( annotation.annotationType().equals( annotationType ) )
183                 {
184                     // We found the real annotation, let's save it for the
185                     // actual provision call!
186                     final A specificAnnotation = annotationType.cast( annotation );
187                     this.provision.set( specificAnnotation );
188 
189                     final InjectionPoint injectionPoint = dependency.getDependency().getInjectionPoint();
190 
191                     if ( injectionPoint == null )
192                     {
193                         checkNotNull( injectionPoint );
194                     }
195 
196                     final FactoryAnnotationProvision<T, A> identityProvision =
197                         FactoryAnnotationProvisionImpl.wrapInjectionPoint( injectionPoint, specificAnnotation );
198 
199                     // Notify listener that an provision will occur
200                     if ( provisionListener != null )
201                     {
202                         provisionListener.beforeInjection( identityProvision, specificAnnotation );
203                     }
204 
205                     // Execute the provision;
206                     T value = factoryAnnotationProvider.getInjectionType().cast( provision.provision() );
207 
208                     // Notify listener about the provisioned value
209                     if ( provisionListener != null )
210                     {
211                         provisionListener.afterInjection( identityProvision, specificAnnotation, value );
212                     }
213 
214                     // Explicitly return at this point
215                     return;
216                 }
217             }
218         }
219     }
220 
221     public Set<Dependency<?>> getDependencies()
222     {
223         return ImmutableSet.<Dependency<?>> of( Dependency.get( targetKey ) );
224     }
225 
226     @SuppressWarnings( "unchecked" )
227     public <B, V> V acceptExtensionVisitor( final BindingTargetVisitor<B, V> visitor,
228                                             final ProviderInstanceBinding<? extends B> binding )
229     {
230 
231         if ( visitor instanceof FactoryAnnotationBindungTargetVisitor )
232         {
233             return ( (FactoryAnnotationBindungTargetVisitor<T, V>) visitor ).visit( this );
234 
235         }
236         else
237         {
238             return visitor.visit( binding );
239         }
240     }
241 
242     public TypeLiteral<T> getElementTypeLiteral()
243     {
244         return elementTypeLiteral;
245     }
246 
247     public Class<A> getAnnotationType()
248     {
249         return annotationType;
250     }
251 
252     public boolean acceptAnnotation( A annotation )
253     {
254         return getAnnotationType().equals( annotation.annotationType() );
255     }
256 
257 }