/**
* 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.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
import org.objectweb.fractal.adl.CompilerError;
import org.objectweb.fractal.adl.error.GenericErrors;
import org.ow2.mind.annotation.ast.AnnotationArgument;
import org.ow2.mind.annotation.ast.AnnotationNode;
import org.ow2.mind.value.ValueEvaluationException;
import org.ow2.mind.value.ValueEvaluator;
import org.ow2.mind.value.ast.Value;
import com.google.inject.Inject;
public class BasicAnnotationFactory implements AnnotationFactory {
@Inject
protected ValueEvaluator evaluatorItf;
@Inject
protected AnnotationLocator annotationLocatorItf;
// ---------------------------------------------------------------------------
// Implementation of the AnnotationFactory interface
// ---------------------------------------------------------------------------
public Annotation newAnnotation(final AnnotationNode annotationNode,
final Map<Object, Object> context)
throws AnnotationInitializationException {
final String type = annotationNode.getType();
final Class<? extends Annotation> annotationClass;
try {
annotationClass = annotationLocatorItf.findAnnotationClass(type, context)
.asSubclass(Annotation.class);
} catch (final ClassNotFoundException e) {
throw new AnnotationInitializationException("Unknown annotation type",
annotationNode, e);
} catch (final ClassCastException e) {
throw new AnnotationInitializationException(
"Invalid annotation type, do not reference an annotation class",
annotationNode, e);
}
final Annotation annotation;
try {
annotation = annotationClass.newInstance();
} catch (final InstantiationException e) {
throw new CompilerError(GenericErrors.INTERNAL_ERROR, e,
"Invalid annotation class \"" + type
+ "\", can't instantiate annotation");
} catch (final IllegalAccessException e) {
throw new CompilerError(GenericErrors.INTERNAL_ERROR, e,
"Invalid annotation class \"" + type
+ "\", can't instantiate annotation");
}
// Build map of annotation fields by looking for public field with the
// 'AnnotationElement' annotation.
final Field[] fields = annotationClass.getFields();
final Map<String, Field> annotationFields = new HashMap<String, Field>();
for (final Field field : fields) {
final AnnotationElement e = field.getAnnotation(AnnotationElement.class);
if (e != null) {
annotationFields.put(field.getName(), field);
}
}
for (final AnnotationArgument argument : annotationNode
.getAnnotationArguments()) {
final Field field = annotationFields.remove(argument.getName());
if (field == null) {
throw new AnnotationInitializationException(
"No such annotation argument \"" + argument.getName() + "\"",
argument);
}
final Class<?> fieldType = field.getType();
final Object arguementValue;
try {
// Check if the captured annotation type is compatible with the
// expected type.
final AnnotationElementType annotationElementType = field
.getAnnotation(AnnotationElementType.class);
if (annotationElementType != null) {
boolean notValid = true;
for (final Class<? extends Value> validType : annotationElementType
.validTypes()) {
if (validType.isAssignableFrom(argument.getValue().getClass())) {
notValid = false;
}
}
if (notValid) {
throw new AnnotationInitializationException(
"Invalid annotation type for argument \"" + argument.getName()
+ "\".", argument);
}
}
arguementValue = evaluatorItf.evaluate(argument.getValue(), fieldType,
context);
} catch (final ValueEvaluationException e) {
throw new AnnotationInitializationException(
"Invalid argument value for argument \"" + argument.getName()
+ "\"", argument, e);
}
try {
field.set(annotation, arguementValue);
} catch (final IllegalArgumentException e) {
throw new CompilerError(GenericErrors.INTERNAL_ERROR, e,
"Fail to set value of annnotation element");
} catch (final IllegalAccessException e) {
throw new CompilerError(GenericErrors.INTERNAL_ERROR, e,
"Fail to set value of annnotation element");
}
}
// checks that non-initialized fields have a default value.
for (final Field field : annotationFields.values()) {
final AnnotationElement annotationElement = field
.getAnnotation(AnnotationElement.class);
if (!annotationElement.hasDefaultValue()) {
throw new AnnotationInitializationException(
"Missing argument value for argument \"" + field.getName() + "\"",
annotationNode);
}
}
return annotation;
}
}