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.util.Map;
026import java.util.concurrent.ConcurrentHashMap;
027
028/**
029 * @author <a href="mailto:bs@nuxeo.com">Bogdan Stefanescu</a>
030 */
031@SuppressWarnings("unchecked")
032public class AnnotationManager {
033
034    protected Map<Class<?>, AnnotatedClass<?>> classCache;
035
036    public AnnotationManager() {
037        classCache = createCache();
038    }
039
040    protected Map<Class<?>, AnnotatedClass<?>> createCache() {
041        return new ConcurrentHashMap<Class<?>, AnnotatedClass<?>>();
042    }
043
044    public void flushCache() {
045        classCache = createCache();
046    }
047
048    public <T> AnnotatedClass<T> getAnnotatedClass(Class<T> clazz) {
049        // use a local variable to avoid problem when flushing cache
050        // in another thread while this method is executing
051        Map<Class<?>, AnnotatedClass<?>> cache = classCache;
052        AnnotatedClass<T> aclass = (AnnotatedClass<T>) cache.get(clazz);
053        if (aclass == null) {
054            aclass = load(clazz);
055            cache.put(clazz, aclass);
056        }
057        return aclass;
058    }
059
060    public <T> AnnotatedClass<T> lookup(Class<T> clazz) {
061        return (AnnotatedClass<T>) classCache.get(clazz);
062    }
063
064    public <T> AnnotatedClass<T> load(Class<T> clazz) {
065        AnnotatedClass<T> aclass = new AnnotatedClass<T>(clazz);
066        Class<?> zuper = clazz.getSuperclass();
067        MethodAnnotations mannos = new MethodAnnotations();
068
069        // collect super class annotations
070        if (zuper != null) {
071            AnnotatedClass<?> azuper = getAnnotatedClass(zuper);
072            aclass.annotations.putAll(azuper.annotations);
073            for (AnnotatedMethod am : azuper.getAnnotatedMethods()) {
074                mannos.addSuperMethod(am);
075            }
076        }
077
078        // collect interface annotations
079        for (Class<?> itf : clazz.getInterfaces()) {
080            AnnotatedClass<?> aitf = getAnnotatedClass(itf);
081            aclass.annotations.putAll(aitf.annotations);
082            for (AnnotatedMethod am : aitf.getAnnotatedMethods()) {
083                mannos.addSuperMethod(am);
084            }
085        }
086
087        // finally add class own annotations
088        mannos.addMethods(clazz);
089        for (Annotation anno : clazz.getAnnotations()) {
090            aclass.annotations.put(anno.annotationType(), anno);
091        }
092
093        // create annotated methods from collected methods
094        for (MethodAnnotations.Entry entry : mannos.entries) {
095            AnnotatedMethod am = new AnnotatedMethod(aclass, entry.method, entry.annos);
096            aclass.addMethod(am);
097        }
098        return aclass;
099    }
100
101}