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
015package org.apache.tapestry.annotations;
016
017import java.lang.annotation.Annotation;
018import java.lang.reflect.Method;
019import java.util.Map;
020
021import org.apache.hivemind.ClassResolver;
022import org.apache.hivemind.ErrorLog;
023import org.apache.hivemind.Location;
024import org.apache.hivemind.Resource;
025import org.apache.hivemind.util.ClasspathResource;
026import org.apache.tapestry.enhance.EnhancementOperation;
027import org.apache.tapestry.enhance.EnhancementWorker;
028import org.apache.tapestry.spec.IComponentSpecification;
029import org.apache.tapestry.util.DescribedLocation;
030
031/**
032 * Implementation of {@link org.apache.tapestry.enhance.EnhancementWorker} that finds class and
033 * method annotations and delegates out to specific
034 * {@link org.apache.tapestry.annotations.ClassAnnotationEnhancementWorker} and
035 * {@link org.apache.tapestry.annotations.MethodAnnotationEnhancementWorker} instances.
036 * 
037 * @author Howard M. Lewis Ship
038 * @since 4.0
039 */
040public class AnnotationEnhancementWorker implements EnhancementWorker
041{
042    private ClassResolver _classResolver;
043
044    private ErrorLog _errorLog;
045
046    private Map _methodWorkers;
047
048    private Map _classWorkers;
049
050    private SecondaryAnnotationWorker _secondaryAnnotationWorker;
051
052    public void setClassWorkers(Map classWorkers)
053    {
054        _classWorkers = classWorkers;
055    }
056
057    public void performEnhancement(EnhancementOperation op, IComponentSpecification spec)
058    {
059        Class clazz = op.getBaseClass();
060
061        Resource classResource = newClassResource(clazz);
062
063        for (Annotation a : clazz.getAnnotations())
064        {
065            performClassEnhancement(op, spec, clazz, a, classResource);
066        }
067
068        for (Method m : clazz.getMethods())
069        {
070            performMethodEnhancement(op, spec, m, classResource);
071        }
072    }
073
074    private ClasspathResource newClassResource(Class clazz)
075    {
076        return new ClasspathResource(_classResolver, clazz.getName().replace('.', '/'));
077    }
078
079    void performClassEnhancement(EnhancementOperation op, IComponentSpecification spec,
080            Class clazz, Annotation annotation, Resource classResource)
081    {
082        ClassAnnotationEnhancementWorker worker = (ClassAnnotationEnhancementWorker) _classWorkers
083                .get(annotation.annotationType());
084
085        if (worker == null)
086            return;
087
088        try
089        {
090            Location location = new DescribedLocation(classResource, AnnotationMessages
091                    .classAnnotation(annotation, clazz));
092
093            worker.performEnhancement(op, spec, clazz, location);
094        }
095        catch (Exception ex)
096        {
097            _errorLog.error(AnnotationMessages.failureProcessingClassAnnotation(
098                    annotation,
099                    clazz,
100                    ex), null, ex);
101        }
102
103    }
104
105    void performMethodEnhancement(EnhancementOperation op, IComponentSpecification spec,
106            Method method, Resource classResource)
107    {
108        for (Annotation a : method.getAnnotations())
109        {
110            performMethodEnhancement(op, spec, method, a, classResource);
111        }
112
113        try
114        {
115            // Remember; _secondaryWorker is a chain-of-command, so this returns true
116            // if any command in the chain returns true.
117
118            if (_secondaryAnnotationWorker.canEnhance(method))
119                _secondaryAnnotationWorker.peformEnhancement(op, spec, method, classResource);
120        }
121        catch (Exception ex)
122        {
123            _errorLog.error(AnnotationMessages.failureEnhancingMethod(method, ex), null, ex);
124        }
125    }
126
127    void performMethodEnhancement(EnhancementOperation op, IComponentSpecification spec,
128            Method method, Annotation annotation, Resource classResource)
129    {
130        MethodAnnotationEnhancementWorker worker = (MethodAnnotationEnhancementWorker) _methodWorkers
131                .get(annotation.annotationType());
132
133        if (worker == null)
134            return;
135
136        try
137        {
138            Location location = AnnotationUtils.buildLocationForAnnotation(
139                    method,
140                    annotation,
141                    classResource);
142            worker.performEnhancement(op, spec, method, location);
143        }
144        catch (Exception ex)
145        {
146            _errorLog.error(
147                    AnnotationMessages.failureProcessingAnnotation(annotation, method, ex),
148                    null,
149                    ex);
150        }
151
152    }
153
154    public void setMethodWorkers(Map methodWorkers)
155    {
156        _methodWorkers = methodWorkers;
157    }
158
159    public void setErrorLog(ErrorLog errorLog)
160    {
161        _errorLog = errorLog;
162    }
163
164    public void setClassResolver(ClassResolver classResolver)
165    {
166        _classResolver = classResolver;
167    }
168
169    public void setSecondaryAnnotationWorker(SecondaryAnnotationWorker secondaryWorker)
170    {
171        _secondaryAnnotationWorker = secondaryWorker;
172    }
173}