001    // Copyright 2005 The Apache Software Foundation
002    //
003    // Licensed under the Apache License, Version 2.0 (the "License");
004    // you may not use this file except in compliance with the License.
005    // You may obtain a copy of the License at
006    //
007    //     http://www.apache.org/licenses/LICENSE-2.0
008    //
009    // Unless required by applicable law or agreed to in writing, software
010    // distributed under the License is distributed on an "AS IS" BASIS,
011    // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012    // See the License for the specific language governing permissions and
013    // limitations under the License.
014    
015    package org.apache.tapestry.annotations;
016    
017    import java.lang.annotation.Annotation;
018    import java.lang.reflect.Method;
019    import java.util.ArrayList;
020    import java.util.Collections;
021    import java.util.List;
022    import java.util.Map;
023    
024    import org.apache.hivemind.ClassResolver;
025    import org.apache.hivemind.ErrorLog;
026    import org.apache.hivemind.Location;
027    import org.apache.hivemind.Resource;
028    import org.apache.hivemind.impl.DefaultClassResolver;
029    import org.apache.tapestry.enhance.EnhancementOperation;
030    import org.apache.tapestry.spec.IComponentSpecification;
031    import org.apache.tapestry.util.DescribedLocation;
032    import static org.easymock.EasyMock.expect;
033    import static org.easymock.EasyMock.expectLastCall;
034    import org.testng.annotations.Test;
035    
036    /**
037     * Tests for {@link org.apache.tapestry.annotations.AnnotationEnhancementWorker}.
038     * 
039     * @author Howard M. Lewis Ship
040     * @since 4.0
041     */
042    @Test
043    public class AnnotationEnhancementWorkerTest extends BaseAnnotationTestCase
044    {
045        protected EnhancementOperation newOp(Class baseClass)
046        {
047            EnhancementOperation op = newMock(EnhancementOperation.class);
048    
049            expect(op.getBaseClass()).andReturn(baseClass);
050    
051            return op;
052        }
053    
054        protected Map newMap(Class annotationClass, Object worker)
055        {
056            return Collections.singletonMap(annotationClass, worker);
057        }
058        
059        /**
060         * No method annotations registered.
061         */
062        public void test_No_Annotations()
063        {
064            EnhancementOperation op = newOp(AnnotatedPage.class);
065            IComponentSpecification spec = newSpec();
066    
067            replay();
068    
069            AnnotationEnhancementWorker worker = new AnnotationEnhancementWorker();
070            worker.setMethodWorkers(Collections.EMPTY_MAP);
071            worker.setSecondaryAnnotationWorkers(Collections.EMPTY_LIST);
072            
073            worker.performEnhancement(op, spec);
074    
075            verify();
076        }
077    
078        public void test_Annotation_Match()
079        {
080            ClassResolver resolver = new DefaultClassResolver();
081    
082            EnhancementOperation op = newOp(AnnotatedPage.class);
083            IComponentSpecification spec = newSpec();
084    
085            MethodAnnotationEnhancementWorker methodWorker = newMethodAnnotationEnhancementWorker();
086    
087            Method m = findMethod(AnnotatedPage.class, "getInjectedObject");
088    
089            Location location = newMethodLocation(AnnotatedPage.class, m, InjectObject.class);
090    
091            methodWorker.performEnhancement(op, spec, m, location);
092    
093            replay();
094    
095            AnnotationEnhancementWorker worker = new AnnotationEnhancementWorker();
096            worker.setMethodWorkers(newMap(InjectObject.class, methodWorker));
097            worker.setClassResolver(resolver);
098            worker.setSecondaryAnnotationWorkers(Collections.EMPTY_LIST);
099            
100            worker.performEnhancement(op, spec);
101    
102            verify();
103        }
104    
105        protected MethodAnnotationEnhancementWorker newMethodAnnotationEnhancementWorker()
106        {
107            return newMock(MethodAnnotationEnhancementWorker.class);
108        }
109    
110        private DescribedLocation newClassLocation(Class baseClass, Class annotationClass)
111        {
112            Resource classResource = newResource(baseClass);
113            Annotation annotation = baseClass.getAnnotation(annotationClass);
114    
115            return new DescribedLocation(classResource, AnnotationMessages.classAnnotation(
116                    annotation,
117                    baseClass));
118        }
119    
120        public void test_Annotation_With_Subclass()
121        {
122            ClassResolver resolver = new DefaultClassResolver();
123    
124            EnhancementOperation op = newOp(AnnotatedPageSubclass.class);
125            IComponentSpecification spec = newSpec();
126    
127            MethodAnnotationEnhancementWorker methodWorker = newMethodAnnotationEnhancementWorker();
128    
129            Method m = findMethod(AnnotatedPageSubclass.class, "getInjectedObject");
130    
131            Location location = newMethodLocation(AnnotatedPageSubclass.class, m, InjectObject.class);
132    
133            methodWorker.performEnhancement(op, spec, m, location);
134    
135            replay();
136    
137            AnnotationEnhancementWorker worker = new AnnotationEnhancementWorker();
138            worker.setMethodWorkers(newMap(InjectObject.class, methodWorker));
139            worker.setClassResolver(resolver);
140            worker.setSecondaryAnnotationWorkers(Collections.EMPTY_LIST);
141    
142            worker.performEnhancement(op, spec);
143    
144            verify();
145        }
146    
147        public void test_Annotation_Failure()
148        {
149            ClassResolver resolver = new DefaultClassResolver();
150    
151            ErrorLog log = newErrorLog();
152            Throwable t = new RuntimeException("Woops!");
153    
154            EnhancementOperation op = newOp(AnnotatedPage.class);
155            IComponentSpecification spec = newSpec();
156    
157            MethodAnnotationEnhancementWorker methodWorker = newMethodAnnotationEnhancementWorker();
158    
159            Method m = findMethod(AnnotatedPage.class, "getInjectedObject");
160    
161            Location location = newMethodLocation(AnnotatedPage.class, m, InjectObject.class);
162    
163            methodWorker.performEnhancement(op, spec, m, location);
164            expectLastCall().andThrow(t);
165    
166            log.error("An error occured processing annotation "
167                    + "@org.apache.tapestry.annotations.InjectObject(value=barney) of "
168                    + "public abstract java.lang.Object org.apache.tapestry.annotations.AnnotatedPage.getInjectedObject(): Woops!",
169                    null,
170                    t);
171    
172            replay();
173    
174            AnnotationEnhancementWorker worker = new AnnotationEnhancementWorker();
175            worker.setMethodWorkers(newMap(InjectObject.class, methodWorker));
176            worker.setErrorLog(log);
177            worker.setClassResolver(resolver);
178            worker.setSecondaryAnnotationWorkers(Collections.EMPTY_LIST);
179    
180            worker.performEnhancement(op, spec);
181    
182            verify();
183        }
184    
185        public void test_Class_Annotation()
186        {
187            ClassResolver resolver = new DefaultClassResolver();
188    
189            EnhancementOperation op = newOp(DeprecatedBean.class);
190            IComponentSpecification spec = newSpec();
191    
192            ClassAnnotationEnhancementWorker classWorker = newMock(ClassAnnotationEnhancementWorker.class);
193    
194            DescribedLocation location = newClassLocation(DeprecatedBean.class, Deprecated.class);
195    
196            classWorker.performEnhancement(op, spec, DeprecatedBean.class, location);
197    
198            replay();
199    
200            AnnotationEnhancementWorker worker = new AnnotationEnhancementWorker();
201            worker.setClassWorkers(newMap(Deprecated.class, classWorker));
202            worker.setClassResolver(resolver);
203            worker.setSecondaryAnnotationWorkers(Collections.EMPTY_LIST);
204            
205            worker.performEnhancement(op, spec);
206    
207            verify();
208        }
209    
210        public void test_Class_Annotation_Failure()
211        {
212            ClassResolver resolver = new DefaultClassResolver();
213    
214            ErrorLog log = newErrorLog();
215            EnhancementOperation op = newOp(DeprecatedBean.class);
216            IComponentSpecification spec = newSpec();
217    
218            ClassAnnotationEnhancementWorker classWorker = newMock(ClassAnnotationEnhancementWorker.class);
219    
220            Throwable t = new RuntimeException("Simulated failure.");
221    
222            DescribedLocation location = newClassLocation(DeprecatedBean.class, Deprecated.class);
223    
224            classWorker.performEnhancement(op, spec, DeprecatedBean.class, location);
225            expectLastCall().andThrow(t);
226    
227            log.error("An error occured processing annotation @java.lang.Deprecated() of "
228                    + "class org.apache.tapestry.annotations.DeprecatedBean: Simulated failure.",
229                    null,
230                    t);
231    
232            replay();
233    
234            AnnotationEnhancementWorker worker = new AnnotationEnhancementWorker();
235            worker.setClassWorkers(newMap(Deprecated.class, classWorker));
236            worker.setErrorLog(log);
237            worker.setClassResolver(resolver);
238            worker.setSecondaryAnnotationWorkers(Collections.EMPTY_LIST);
239            
240            worker.performEnhancement(op, spec);
241    
242            verify();
243        }
244    
245        public void test_Class_Annotation_No_Match()
246        {
247            EnhancementOperation op = newOp(DeprecatedBean.class);
248            IComponentSpecification spec = newSpec();
249    
250            replay();
251    
252            AnnotationEnhancementWorker worker = new AnnotationEnhancementWorker();
253            worker.setClassWorkers(Collections.EMPTY_MAP);
254            worker.setSecondaryAnnotationWorkers(Collections.EMPTY_LIST);
255            
256            worker.performEnhancement(op, spec);
257    
258            verify();
259        }
260    
261        public void test_Secondary_EnhancementWorker()
262        {
263            SecondaryAnnotationWorker secondary = newSecondaryAnnotationWorker();
264            
265            List<SecondaryAnnotationWorker> secWorkers = new ArrayList<SecondaryAnnotationWorker>();
266            secWorkers.add(secondary);
267            
268            EnhancementOperation op = newOp();
269            IComponentSpecification spec = newSpec();
270            Method method = findMethod(AnnotatedPage.class, "getPropertyWithInitialValue");
271    
272            Resource classResource = newResource(AnnotatedPage.class);
273    
274            expect(secondary.canEnhance(method)).andReturn(true);
275    
276            secondary.peformEnhancement(op, spec, method, classResource);
277    
278            replay();
279            
280            AnnotationEnhancementWorker worker = new AnnotationEnhancementWorker();
281            worker.setSecondaryAnnotationWorkers(secWorkers);
282            worker.setMethodWorkers(Collections.EMPTY_MAP);
283            
284            worker.performMethodEnhancement(op, spec, method, classResource);
285    
286            verify();
287        }
288    
289        public void test_Secondary_EnhancementWorker_Failure()
290        {
291            SecondaryAnnotationWorker secondary = newSecondaryAnnotationWorker();
292            
293            List<SecondaryAnnotationWorker> secWorkers = new ArrayList<SecondaryAnnotationWorker>();
294            secWorkers.add(secondary);
295            
296            EnhancementOperation op = newOp();
297            IComponentSpecification spec = newSpec();
298            ErrorLog log = newErrorLog();
299    
300            Method method = findMethod(AnnotatedPage.class, "getPropertyWithInitialValue");
301    
302            Resource classResource = newResource(AnnotatedPage.class);
303    
304            RuntimeException cause = new RuntimeException("Forced.");
305    
306            expect(secondary.canEnhance(method)).andThrow(cause);
307            
308            log.error(AnnotationMessages.failureEnhancingMethod(method, cause), null, cause);
309            
310            replay();
311            
312            AnnotationEnhancementWorker worker = new AnnotationEnhancementWorker();
313            worker.setSecondaryAnnotationWorkers(secWorkers);
314            worker.setMethodWorkers(Collections.EMPTY_MAP);
315            worker.setErrorLog(log);
316            
317            worker.performMethodEnhancement(op, spec, method, classResource);
318    
319            verify();
320        }
321    
322        protected SecondaryAnnotationWorker newSecondaryAnnotationWorker()
323        {
324            return newMock(SecondaryAnnotationWorker.class);
325        }
326    }