1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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
82
83
84 binder.requestInjection( adapter );
85 binder.requestInjection( factoryAnnotationProvider );
86
87
88 if ( cacheable )
89 {
90 this.factoryAnnotationProvider = new ProvisionCacheIdentityProviderFacade<T, A>( adapter, elementTypeLiteral );
91
92
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
114 provision.set( null );
115
116
117 return factoryAnnotationProvider.buildValue( annotation );
118 }
119
120 public <I> void hear( final TypeLiteral<I> type, final TypeEncounter<I> encounter )
121 {
122
123
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
154
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
170
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
185
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
200 if ( provisionListener != null )
201 {
202 provisionListener.beforeInjection( identityProvision, specificAnnotation );
203 }
204
205
206 T value = factoryAnnotationProvider.getInjectionType().cast( provision.provision() );
207
208
209 if ( provisionListener != null )
210 {
211 provisionListener.afterInjection( identityProvision, specificAnnotation, value );
212 }
213
214
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 }