/** * Copyright (C) 2009 STMicroelectronics * * This file is part of "Mind Compiler" 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 3 of the * License, or (at your option) any later version. * * This program 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 program. If not, see <http://www.gnu.org/licenses/>. * * Contact: mind@ow2.org * * Authors: Matthieu Leclercq * Contributors: */ package org.ow2.mind.annotation; import java.io.Externalizable; import java.io.IOException; import java.io.ObjectInput; import java.io.ObjectOutput; import java.util.HashMap; import java.util.IdentityHashMap; import java.util.Map; import org.objectweb.fractal.adl.ADLException; import org.objectweb.fractal.adl.Node; import org.objectweb.fractal.adl.merger.MergeException; import org.objectweb.fractal.adl.merger.MergeableDecoration; public final class AnnotationHelper { private AnnotationHelper() { } public static final String ANNOTATION_DECORATION_NAME = "annotations"; public static void addAnnotation(final Node container, final Annotation annotation) throws ADLException { AnnotationDecoration decoration = getDecoration(container); if (decoration == null) { decoration = new AnnotationDecoration(); addDecoration(container, decoration); } decoration.addAnnotation(annotation); } public static <T extends Annotation> T getAnnotation(final Node container, final Class<T> annotationClass) { final AnnotationDecoration decoration = getDecoration(container); if (decoration == null) return null; else return decoration.getAnnotation(annotationClass); } public static Annotation[] getAnnotations(final Node container) { final AnnotationDecoration decoration = getDecoration(container); if (decoration == null) return new Annotation[0]; else return decoration.getAnnotations(); } public static void removeAnnotation(final Node container, final Annotation annotation) { removeAnnotation(container, annotation.getClass()); } public static <T extends Annotation> T removeAnnotation(final Node container, final Class<T> annotationClass) { final AnnotationDecoration decoration = getDecoration(container); if (decoration == null) return null; else return decoration.removeAnnotation(annotationClass); } private static AnnotationDecoration getDecoration(final Node container) { return (AnnotationDecoration) container .astGetDecoration(ANNOTATION_DECORATION_NAME); } private static void addDecoration(final Node container, final AnnotationDecoration decoration) { container.astSetDecoration(ANNOTATION_DECORATION_NAME, decoration); } public static class AnnotationDecoration implements MergeableDecoration, Externalizable { final Map<Class<? extends Annotation>, Annotation> annotations = new IdentityHashMap<Class<? extends Annotation>, Annotation>(); void addAnnotation(final Annotation annotation) throws ADLException { final Annotation previousAnnotation = annotations.put( annotation.getClass(), annotation); if (previousAnnotation != null) { throw new IllegalArgumentException( "Can't specify the same annotation several time on a given element"); } } @SuppressWarnings("unchecked") <T extends Annotation> T getAnnotation(final Class<T> annotationClass) { return (T) annotations.get(annotationClass); } @SuppressWarnings("unchecked") <T extends Annotation> T removeAnnotation(final Class<T> annotationClass) { return (T) annotations.remove(annotationClass); } /** * To be used from string template * * @return a map associating annotation class names to annotation objects. */ public Map<String, Annotation> getAnnotationMap() { final Map<String, Annotation> map = new HashMap<String, Annotation>( annotations.size()); for (final Map.Entry<Class<? extends Annotation>, Annotation> e : annotations .entrySet()) { map.put(e.getKey().getName(), e.getValue()); } return map; } Annotation[] getAnnotations() { return annotations.values().toArray(new Annotation[0]); } public Object mergeDecoration(final Object overridingDecoration) throws MergeException { final AnnotationDecoration newDecoration = new AnnotationDecoration(); if (overridingDecoration == null) { // no overridding annotations // returns only annotations that are marked as "inherited". for (final Annotation overriddenAnno : getAnnotations()) { if (overriddenAnno.isInherited()) { // TODO should we clone the annotation ? newDecoration.annotations.put(overriddenAnno.getClass(), overriddenAnno); } } } else { final AnnotationDecoration overridingAnnotations = (AnnotationDecoration) overridingDecoration; // returns overridingAnnotations + overridden annotations that are // marked as "inherited" newDecoration.annotations.putAll(overridingAnnotations.annotations); for (final Annotation overriddenAnno : getAnnotations()) { if (!newDecoration.annotations.containsKey(overriddenAnno.getClass()) && overriddenAnno.isInherited()) { // TODO should we clone the annotation ? newDecoration.annotations.put(overriddenAnno.getClass(), overriddenAnno); } } } return newDecoration; } public void readExternal(final ObjectInput in) throws IOException, ClassNotFoundException { final int size = in.readInt(); for (int i = 0; i < size; i++) { final String className = in.readUTF(); final Class<? extends Annotation> c = getClass().getClassLoader() .loadClass(className).asSubclass(Annotation.class); final Annotation a = (Annotation) in.readObject(); annotations.put(c, a); } } public void writeExternal(final ObjectOutput out) throws IOException { out.writeInt(annotations.size()); for (final Map.Entry<Class<? extends Annotation>, Annotation> entry : annotations .entrySet()) { out.writeUTF(entry.getKey().getName()); out.writeObject(entry.getValue()); } } } }