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