001    /* $Id: MethodHandler.java 992091 2010-09-02 19:58:12Z simonetripodi $
002     *
003     * Licensed to the Apache Software Foundation (ASF) under one or more
004     * contributor license agreements.  See the NOTICE file distributed with
005     * this work for additional information regarding copyright ownership.
006     * The ASF licenses this file to You under the Apache License, Version 2.0
007     * (the "License"); you may not use this file except in compliance with
008     * the License.  You may obtain a copy of the License at
009     *
010     *      http://www.apache.org/licenses/LICENSE-2.0
011     *
012     * Unless required by applicable law or agreed to in writing, software
013     * distributed under the License is distributed on an "AS IS" BASIS,
014     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015     * See the License for the specific language governing permissions and
016     * limitations under the License.
017     */
018    package org.apache.commons.digester.annotations.handlers;
019    
020    import java.lang.annotation.Annotation;
021    import java.lang.reflect.Method;
022    import java.lang.reflect.Modifier;
023    
024    import org.apache.commons.digester.Rule;
025    import org.apache.commons.digester.annotations.AnnotationRuleProvider;
026    import org.apache.commons.digester.annotations.CreationRule;
027    import org.apache.commons.digester.annotations.DigesterLoaderHandler;
028    import org.apache.commons.digester.annotations.DigesterLoadingException;
029    import org.apache.commons.digester.annotations.DigesterRule;
030    import org.apache.commons.digester.annotations.DigesterRuleList;
031    import org.apache.commons.digester.annotations.FromAnnotationsRuleSet;
032    import org.apache.commons.digester.annotations.utils.AnnotationUtils;
033    
034    /**
035     * Handler that takes care to create the
036     * {@link org.apache.commons.digester.annotations.providers.SetNextRuleProvider}
037     * and
038     * {@link org.apache.commons.digester.annotations.providers.SetRootRuleProvider}.
039     *
040     * @since 2.1
041     */
042    public final class MethodHandler implements DigesterLoaderHandler<Annotation, Method> {
043    
044        /**
045         * The default args size the method has to have in order to be analyzed.
046         */
047        private static final int SUPPORTED_ARGS = 1;
048    
049        /**
050         * {@inheritDoc}
051         */
052        public void handle(Annotation annotation, Method element, FromAnnotationsRuleSet ruleSet) {
053            if (SUPPORTED_ARGS != element.getParameterTypes().length) {
054                DigesterRule rule = annotation.annotationType().getAnnotation(DigesterRule.class);
055    
056                throw new DigesterLoadingException("Methods annotated with digester annotation rule @"
057                        + rule.reflectsRule().getName()
058                        + " must have just one argument");
059            }
060    
061            Object explicitTypesObject = AnnotationUtils.getAnnotationValue(annotation);
062            if (explicitTypesObject == null
063                    || !explicitTypesObject.getClass().isArray()
064                    || Class.class != explicitTypesObject.getClass().getComponentType()) {
065                throw new DigesterLoadingException("Impossible to apply this handler, @"
066                        + annotation.getClass().getName()
067                        + ".value() has to be of type 'Class<?>[]'");
068            }
069    
070            Class<?>[] explicitTypes = (Class<?>[]) explicitTypesObject;
071            Class<?> paramType = element.getParameterTypes()[0];
072    
073            if (explicitTypes.length > 0) {
074                for (Class<?> explicitType : explicitTypes) {
075                    if (!paramType.isAssignableFrom(explicitType)) {
076                        throw new DigesterLoadingException("Impossible to handle annotation "
077                                + annotation
078                                + " on method "
079                                + element.toGenericString()
080                                + ", "
081                                + explicitType.getName()
082                                + " has to be a "
083                                + paramType.getName());
084                    }
085    
086                    this.doHandle(annotation, element, explicitType, ruleSet);
087                }
088            } else {
089                this.doHandle(annotation, element, paramType, ruleSet);
090            }
091        }
092    
093        private void doHandle(Annotation methodAnnotation, Method method, Class<?> type, FromAnnotationsRuleSet ruleSet) {
094            if (type.isInterface()
095                    && Modifier.isAbstract(type.getModifiers())) {
096                throw new DigesterLoadingException("Impossible to proceed analyzing "
097                        + methodAnnotation
098                        + ", specified type '"
099                        + type.getName()
100                        + "' is an interface/abstract");
101            }
102    
103            for (Annotation annotation : type.getAnnotations()) {
104                this.doHandle(methodAnnotation, annotation, method, type, ruleSet);
105            }
106        }
107    
108        @SuppressWarnings("unchecked")
109        private <A extends Annotation, R extends Rule> void doHandle(A methodAnnotation,
110                Annotation annotation,
111                Method method,
112                Class<?> type,
113                FromAnnotationsRuleSet ruleSet) {
114            if (annotation.annotationType().isAnnotationPresent(DigesterRule.class)
115                    && annotation.annotationType().isAnnotationPresent(CreationRule.class)) {
116                ruleSet.addRules(type);
117    
118                DigesterRule digesterRule = methodAnnotation.annotationType().getAnnotation(DigesterRule.class);
119                Class<? extends AnnotationRuleProvider<A, Method, R>> providerType =
120                    (Class<? extends AnnotationRuleProvider<A, Method, R>>) digesterRule.providedBy();
121                ruleSet.addRuleProvider(AnnotationUtils.getAnnotationPattern(annotation),
122                        providerType,
123                        methodAnnotation,
124                        method);
125            } else if (annotation.annotationType().isAnnotationPresent(DigesterRuleList.class)) {
126                // check if it is one of the *.List annotation
127                Annotation[] annotations = AnnotationUtils.getAnnotationsArrayValue(annotation);
128                if (annotations != null) {
129                    // if it is an annotations array, process them
130                    for (Annotation ptr : annotations) {
131                        this.doHandle(methodAnnotation, ptr, method, type, ruleSet);
132                    }
133                }
134            }
135        }
136    
137    }