/*
* ============================================================================
* GNU Lesser General Public License
* ============================================================================
*
* Beanlet - JSE Application Container.
* Copyright (C) 2006 Leon van Zantvoort
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
*
* Leon van Zantvoort
* 243 Acalanes Drive #11
* Sunnyvale, CA 94086
* USA
*
* zantvoort@users.sourceforge.net
* http://beanlet.org
*/
package org.beanlet.annotation;
import java.lang.annotation.Annotation;
import java.lang.annotation.Inherited;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
/**
*
* @author Leon van Zantvoort
*/
public abstract class AbstractAnnotationDomain implements AnnotationDomain {
/**
* Returns an annotation domain for the specified {@code classes}.
*/
public static AnnotationDomain instance(Class... classes) {
return new ClassAnnotationDomainImpl(classes);
}
private final List<ElementAnnotation> list;
private final ConcurrentMap<Class, List<ElementAnnotation>> classSpecificList;
private final Map<Class<? extends Element>, ElementAnnotationHolder<Element>> elementAnnotationMap;
private final ConcurrentMap<Class, ConcurrentMap<Class<? extends Element>, ElementAnnotationHolder<Element>>> classSpecificElementAnnotationMap;
private final Map<Element, List<Annotation>> declaredAnnotationMap;
private final ConcurrentMap<TypeElement, List<Annotation>> typeAnnotationMap;
private final Map<Class<? extends Annotation>, AnnotationDeclarationImpl>
declarationMap;
private final List<AnnotationDeclaration> declarationList;
/**
* Constructs an annotation domain for the specified {@code classes}.
*
* @throws IllegalArgumentException
*/
public AbstractAnnotationDomain(List<ElementAnnotation> elementAnnotations)
throws NullPointerException, IllegalArgumentException {
if (elementAnnotations == null) {
throw new NullPointerException();
}
// Defensive copy.
list = new ArrayList<ElementAnnotation>(elementAnnotations);
classSpecificList = new ConcurrentHashMap<Class, List<ElementAnnotation>>();
elementAnnotationMap = new HashMap<Class<? extends Element>, ElementAnnotationHolder<Element>>();
classSpecificElementAnnotationMap = new ConcurrentHashMap<Class, ConcurrentMap<Class<? extends Element>, ElementAnnotationHolder<Element>>>();
declaredAnnotationMap = new HashMap<Element, List<Annotation>>();
typeAnnotationMap = new ConcurrentHashMap<TypeElement, List<Annotation>>();
declarationMap = new HashMap<Class<? extends Annotation>, AnnotationDeclarationImpl>();
declarationList = new ArrayList<AnnotationDeclaration>();
Set<Object> dups = new HashSet<Object>();
Map<Class<? extends Annotation>, List<ElementAnnotation<Element, Annotation>>> map =
new HashMap<Class<? extends Annotation>, List<ElementAnnotation<Element, Annotation>>>();
for (ElementAnnotation ea : elementAnnotations) {
Class<? extends Element> e = ea.getElement().getClass();
Class<? extends Annotation> t = ea.getAnnotation().annotationType();
if (!dups.add(Arrays.asList(ea.getElement(), t))) {
throw new IllegalArgumentException("duplicate element annotation: " + ea);
}
ElementAnnotationHolder<Element> holder = elementAnnotationMap.get(e);
if (holder == null) {
holder = new ElementAnnotationHolder<Element>();
elementAnnotationMap.put(e, holder);
}
@SuppressWarnings("unchecked")
ElementAnnotation<Element, Annotation> tmp =
(ElementAnnotation<Element, Annotation>) ea;
holder.elementAnnotations.add(tmp);
List<Annotation> l1 = declaredAnnotationMap.get(ea.getElement());
if (l1 == null) {
l1 = new ArrayList<Annotation>();
declaredAnnotationMap.put(ea.getElement(), l1);
}
l1.add(ea.getAnnotation());
List<ElementAnnotation<Element, Annotation>> l2 = map.get(t);
if (l2 == null) {
l2 = new ArrayList<ElementAnnotation<Element, Annotation>>();
map.put(t, l2);
}
l2.add(tmp);
}
for (Map.Entry<Class<? extends Annotation>, List<ElementAnnotation<Element, Annotation>>> entry : map.entrySet()) {
@SuppressWarnings("unchecked")
AnnotationDeclarationImpl d =
new AnnotationDeclarationImpl(entry.getKey(),
entry.getValue());
declarationMap.put(entry.getKey(), d);
declarationList.add(d);
}
}
public List<AnnotationDeclaration> getDeclarations() {
return Collections.unmodifiableList(declarationList);
}
public <T extends Annotation> AnnotationDeclaration<T> getDeclaration(
Class<T> annotationClass) {
@SuppressWarnings("unchecked")
AnnotationDeclaration<T> declaration = (AnnotationDeclaration<T>) declarationMap.get(annotationClass);
if (declaration == null) {
declaration = new AnnotationDeclarationImpl<T>(annotationClass);
}
return declaration;
}
protected <E extends Element, T extends Annotation> ElementAnnotation<E, T>
getElementAnnotation(E element, Class<T> annotationClass) {
@SuppressWarnings("unchecked")
AnnotationDeclarationImpl<T> declaration = (AnnotationDeclarationImpl<T>) declarationMap.get(annotationClass);
return declaration == null ? null : declaration.getElementAnnotation(element);
}
public List<ElementAnnotation> getElements() {
return Collections.unmodifiableList(list);
}
public List<ElementAnnotation> getElements(Class<?> cls) {
List<ElementAnnotation> list = classSpecificList.get(cls);
if (list == null) {
list = new ArrayList<ElementAnnotation>();
for (ElementAnnotation ea : getElements()) {
Element e = ea.getElement();
if (e.isElementOf(cls) && !e.isOverridden(cls)) {
list.add(ea);
}
}
classSpecificList.putIfAbsent(cls, list);
}
return Collections.unmodifiableList(list);
}
public <E extends Element> List<ElementAnnotation<E, Annotation>> getTypedElements(Class<E> elementClass) {
@SuppressWarnings("unchecked")
ElementAnnotationHolder<E> holder = (ElementAnnotationHolder<E>) elementAnnotationMap.get(elementClass);
final List<ElementAnnotation<E, Annotation>> list;
if (holder == null) {
list = Collections.emptyList();
} else {
list = Collections.unmodifiableList(holder.elementAnnotations);
}
return list;
}
public <E extends Element> List<ElementAnnotation<E, Annotation>> getTypedElements(Class<E> elementClass, Class<?> cls) {
ConcurrentMap<Class<? extends Element>, ElementAnnotationHolder<Element>> map =
classSpecificElementAnnotationMap.get(cls);
if (map == null) {
map = new ConcurrentHashMap<Class<? extends Element>, ElementAnnotationHolder<Element>>();
classSpecificElementAnnotationMap.putIfAbsent(cls, map);
}
@SuppressWarnings("unchecked")
ElementAnnotationHolder<Element> holder = map.get(elementClass);
if (holder == null) {
holder = new ElementAnnotationHolder<Element>();
for (ElementAnnotation<E, Annotation> ea : getTypedElements(elementClass)) {
@SuppressWarnings("unchecked")
ElementAnnotation<Element, Annotation> tmp = (ElementAnnotation<Element, Annotation>) ea;
Element e = tmp.getElement();
if (e.isElementOf(cls) && !e.isOverridden(cls)) {
holder.elementAnnotations.add(tmp);
}
}
map.put(elementClass, holder);
}
@SuppressWarnings("unchecked")
ElementAnnotationHolder<E> h = (ElementAnnotationHolder<E>) holder;
return Collections.unmodifiableList(h.elementAnnotations);
}
public List<Annotation> getAnnotations(Element element) {
final List<Annotation> list;
if (element instanceof TypeElement) {
List<Annotation> tmp = typeAnnotationMap.get(element);
if (tmp == null) {
tmp = new ArrayList<Annotation>();
Set<Class<? extends Annotation>> types =
new HashSet<Class<? extends Annotation>>();
Class<?> cls = ((TypeElement) element).getType();
for (Annotation annotation : getDeclaredAnnotations(element)) {
types.add(annotation.annotationType());
tmp.add(annotation);
}
while ((cls = cls.getSuperclass()) != null) {
Element e = TypeElement.instance(cls);
for (Annotation annotation : getDeclaredAnnotations(e)) {
if (annotation.annotationType().isAnnotationPresent(Inherited.class) &&
types.add(annotation.annotationType())) {
tmp.add(annotation);
}
}
}
typeAnnotationMap.putIfAbsent((TypeElement) element, tmp);
}
list = Collections.unmodifiableList(tmp);
} else {
list = getDeclaredAnnotations(element);
}
return list;
}
public List<Annotation> getDeclaredAnnotations(Element element) {
List<Annotation> list = declaredAnnotationMap.get(element);
if (list == null) {
return Collections.emptyList();
} else {
return Collections.unmodifiableList(list);
}
}
public String toString() {
return String.valueOf(getElements());
}
private class ElementAnnotationHolder<E extends Element> {
private final List<ElementAnnotation<E, Annotation>> elementAnnotations =
new ArrayList<ElementAnnotation<E, Annotation>>();
}
}