001/*
002 * (C) Copyright 2006-2008 Nuxeo SAS (http://nuxeo.com/) and contributors.
003 *
004 * All rights reserved. This program and the accompanying materials
005 * are made available under the terms of the GNU Lesser General Public License
006 * (LGPL) version 2.1 which accompanies this distribution, and is available at
007 * http://www.gnu.org/licenses/lgpl.html
008 *
009 * This library is distributed in the hope that it will be useful,
010 * but WITHOUT ANY WARRANTY; without even the implied warranty of
011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012 * Lesser General Public License for more details.
013 *
014 * Contributors:
015 *     bstefanescu
016 *
017 * $Id$
018 */
019
020package org.nuxeo.runtime.annotations;
021
022import java.lang.annotation.Annotation;
023import java.lang.reflect.Method;
024import java.util.ArrayList;
025import java.util.HashMap;
026import java.util.Map;
027
028/**
029 * @author <a href="mailto:bs@nuxeo.com">Bogdan Stefanescu</a>
030 */
031public class AnnotatedClass<T> {
032
033    protected AnnotatedClass<?> superClass;
034
035    protected final Class<T> clazz;
036
037    protected final Map<Class<? extends Annotation>, Annotation> annotations;
038
039    protected final Map<Method, AnnotatedMethod> methods;
040
041    public AnnotatedClass(Class<T> clazz) {
042        this.clazz = clazz;
043        methods = new HashMap<Method, AnnotatedMethod>();
044        annotations = new HashMap<Class<? extends Annotation>, Annotation>();
045    }
046
047    public Class<?> getAnnotatedClass() {
048        return clazz;
049    }
050
051    @SuppressWarnings("unchecked")
052    public <A extends Annotation> A getAnnotation(Class<A> annotationClass) {
053        return (A) annotations.get(annotationClass);
054    }
055
056    public <A extends Annotation> A getDeclaredAnnotation(Class<A> annotationClass) {
057        return clazz.getAnnotation(annotationClass);
058    }
059
060    public Annotation[] getAnnotations() {
061        return annotations.values().toArray(new Annotation[annotations.size()]);
062    }
063
064    public Annotation[] getDeclaredAnnotations() {
065        return clazz.getDeclaredAnnotations();
066    }
067
068    public boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) {
069        return annotations.containsKey(annotationClass);
070    }
071
072    public boolean isDeclaringAnnotation(Class<? extends Annotation> annotationClass) {
073        return clazz.isAnnotationPresent(annotationClass);
074    }
075
076    public AnnotatedMethod getAnnotatedMethod(Method method) {
077        return methods.get(method);
078    }
079
080    public AnnotatedMethod getAnnotatedMethod(String name, Class<?>... parameterTypes) throws NoSuchMethodException {
081        return getAnnotatedMethod(clazz.getMethod(name, parameterTypes));
082    }
083
084    public AnnotatedMethod getDeclaredAnnotatedMethod(Method method) {
085        AnnotatedMethod am = methods.get(method);
086        return am != null && am.method.getDeclaringClass() == clazz ? am : null;
087    }
088
089    public boolean hasAnnotatedMethods() {
090        return !methods.isEmpty();
091    }
092
093    public boolean isDeclaringAnnotatedMethods() {
094        if (methods.isEmpty()) {
095            return false;
096        }
097        for (AnnotatedMethod am : methods.values()) {
098            if (am.method.getDeclaringClass() == clazz) {
099                return true;
100            }
101        }
102        return false;
103    }
104
105    public AnnotatedMethod[] getAnnotatedMethods() {
106        return methods.values().toArray(new AnnotatedMethod[methods.size()]);
107    }
108
109    public AnnotatedMethod[] getDeclaredAnnotatedMethods() {
110        ArrayList<AnnotatedMethod> result = new ArrayList<AnnotatedMethod>();
111        for (AnnotatedMethod am : methods.values()) {
112            if (am.method.getDeclaringClass() == clazz) {
113                result.add(am);
114            }
115        }
116        return result.toArray(new AnnotatedMethod[result.size()]);
117    }
118
119    // TODO: cache this?
120    public AnnotatedMethod[] getAnnotatedMethods(Class<? extends Annotation> annotationClass) {
121        ArrayList<AnnotatedMethod> result = new ArrayList<AnnotatedMethod>();
122        for (AnnotatedMethod am : methods.values()) {
123            if (am.annotations.containsKey(annotationClass)) {
124                result.add(am);
125            }
126        }
127        return result.toArray(new AnnotatedMethod[result.size()]);
128    }
129
130    public AnnotatedMethod[] getDeclaredAnnotatedMethods(Class<? extends Annotation> annotationClass) {
131        ArrayList<AnnotatedMethod> result = new ArrayList<AnnotatedMethod>();
132        for (AnnotatedMethod am : methods.values()) {
133            if (am.method.getDeclaringClass() == clazz && am.annotations.containsKey(annotationClass)) {
134                result.add(am);
135            }
136        }
137        return result.toArray(new AnnotatedMethod[result.size()]);
138    }
139
140    public void addMethod(AnnotatedMethod method) {
141        methods.put(method.method, method);
142        // TODO cache annotations to annotated method?
143    }
144
145    @Override
146    public int hashCode() {
147        return clazz.hashCode();
148    }
149
150    @Override
151    public boolean equals(Object obj) {
152        if (obj == this) {
153            return true;
154        }
155        if (obj == null) {
156            return false;
157        }
158        if (obj.getClass() == AnnotatedClass.class) {
159            return ((AnnotatedClass<?>) obj).clazz == clazz;
160        }
161        return false;
162    }
163
164    @Override
165    public String toString() {
166        return "AnnotatedCass: " + clazz;
167    }
168
169}