001/*
002 * (C) Copyright 2006-2008 Nuxeo SA (http://nuxeo.com/) and others.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 *
016 * Contributors:
017 *     bstefanescu
018 *
019 * $Id$
020 */
021
022package org.nuxeo.runtime.annotations;
023
024import java.lang.annotation.Annotation;
025import java.lang.reflect.Method;
026import java.util.ArrayList;
027import java.util.HashMap;
028import java.util.Map;
029
030/**
031 * @author <a href="mailto:bs@nuxeo.com">Bogdan Stefanescu</a>
032 */
033public class AnnotatedClass<T> {
034
035    protected AnnotatedClass<?> superClass;
036
037    protected final Class<T> clazz;
038
039    protected final Map<Class<? extends Annotation>, Annotation> annotations;
040
041    protected final Map<Method, AnnotatedMethod> methods;
042
043    public AnnotatedClass(Class<T> clazz) {
044        this.clazz = clazz;
045        methods = new HashMap<>();
046        annotations = new HashMap<>();
047    }
048
049    public Class<?> getAnnotatedClass() {
050        return clazz;
051    }
052
053    @SuppressWarnings("unchecked")
054    public <A extends Annotation> A getAnnotation(Class<A> annotationClass) {
055        return (A) annotations.get(annotationClass);
056    }
057
058    public <A extends Annotation> A getDeclaredAnnotation(Class<A> annotationClass) {
059        return clazz.getAnnotation(annotationClass);
060    }
061
062    public Annotation[] getAnnotations() {
063        return annotations.values().toArray(new Annotation[annotations.size()]);
064    }
065
066    public Annotation[] getDeclaredAnnotations() {
067        return clazz.getDeclaredAnnotations();
068    }
069
070    public boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) {
071        return annotations.containsKey(annotationClass);
072    }
073
074    public boolean isDeclaringAnnotation(Class<? extends Annotation> annotationClass) {
075        return clazz.isAnnotationPresent(annotationClass);
076    }
077
078    public AnnotatedMethod getAnnotatedMethod(Method method) {
079        return methods.get(method);
080    }
081
082    public AnnotatedMethod getAnnotatedMethod(String name, Class<?>... parameterTypes) throws NoSuchMethodException {
083        return getAnnotatedMethod(clazz.getMethod(name, parameterTypes));
084    }
085
086    public AnnotatedMethod getDeclaredAnnotatedMethod(Method method) {
087        AnnotatedMethod am = methods.get(method);
088        return am != null && am.method.getDeclaringClass() == clazz ? am : null;
089    }
090
091    public boolean hasAnnotatedMethods() {
092        return !methods.isEmpty();
093    }
094
095    public boolean isDeclaringAnnotatedMethods() {
096        if (methods.isEmpty()) {
097            return false;
098        }
099        for (AnnotatedMethod am : methods.values()) {
100            if (am.method.getDeclaringClass() == clazz) {
101                return true;
102            }
103        }
104        return false;
105    }
106
107    public AnnotatedMethod[] getAnnotatedMethods() {
108        return methods.values().toArray(new AnnotatedMethod[methods.size()]);
109    }
110
111    public AnnotatedMethod[] getDeclaredAnnotatedMethods() {
112        ArrayList<AnnotatedMethod> result = new ArrayList<>();
113        for (AnnotatedMethod am : methods.values()) {
114            if (am.method.getDeclaringClass() == clazz) {
115                result.add(am);
116            }
117        }
118        return result.toArray(new AnnotatedMethod[result.size()]);
119    }
120
121    // TODO: cache this?
122    public AnnotatedMethod[] getAnnotatedMethods(Class<? extends Annotation> annotationClass) {
123        ArrayList<AnnotatedMethod> result = new ArrayList<>();
124        for (AnnotatedMethod am : methods.values()) {
125            if (am.annotations.containsKey(annotationClass)) {
126                result.add(am);
127            }
128        }
129        return result.toArray(new AnnotatedMethod[result.size()]);
130    }
131
132    public AnnotatedMethod[] getDeclaredAnnotatedMethods(Class<? extends Annotation> annotationClass) {
133        ArrayList<AnnotatedMethod> result = new ArrayList<>();
134        for (AnnotatedMethod am : methods.values()) {
135            if (am.method.getDeclaringClass() == clazz && am.annotations.containsKey(annotationClass)) {
136                result.add(am);
137            }
138        }
139        return result.toArray(new AnnotatedMethod[result.size()]);
140    }
141
142    public void addMethod(AnnotatedMethod method) {
143        methods.put(method.method, method);
144        // TODO cache annotations to annotated method?
145    }
146
147    @Override
148    public int hashCode() {
149        return clazz.hashCode();
150    }
151
152    @Override
153    public boolean equals(Object obj) {
154        if (obj == this) {
155            return true;
156        }
157        if (obj == null) {
158            return false;
159        }
160        if (obj.getClass() == AnnotatedClass.class) {
161            return ((AnnotatedClass<?>) obj).clazz == clazz;
162        }
163        return false;
164    }
165
166    @Override
167    public String toString() {
168        return "AnnotatedCass: " + clazz;
169    }
170
171}