/* * ome.annotations.ApiConstraintChecker * * Copyright 2006 University of Dundee. All rights reserved. * Use is subject to license terms supplied in LICENSE.txt */ package ome.annotations; import java.lang.annotation.Annotation; import java.lang.reflect.Method; import java.util.Arrays; import java.util.Collection; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import ome.conditions.ApiUsageException; import ome.conditions.ValidationException; /** * Checks metadata constraints on API calls. * * @author Josh Moore      <a * href="mailto:josh.moore@gmx.de">josh.moore@gmx.de</a> * @version 1.0 * @since 1.0 */ public class ApiConstraintChecker { private static Logger log = LoggerFactory.getLogger(ApiConstraintChecker.class); public static void errorOnViolation(Class implClass, Method mthd, Object[] args) throws ValidationException { if (implClass == null || mthd == null) { throw new ApiUsageException( "ApiConstraintChecker expects non null class and method " + "arguments."); } if (log.isDebugEnabled()) { log.debug("Checking: " + mthd); } /* get arrays of arguments with parameters */ if (args == null) { args = new Object[] {}; } Class<?>[] paramTypes = mthd.getParameterTypes(); boolean[] validated = new boolean[args.length]; Object[] allAnnotations = AnnotationUtils.findParameterAnnotations( implClass, mthd); for (int j = 0; j < allAnnotations.length; j++) { Annotation[][] anns = (Annotation[][]) allAnnotations[j]; if (anns == null) { continue; } for (int i = 0; i < args.length; i++) { Object arg = args[i]; Annotation[] annotations = anns[i]; validated[i] |= false; for (Annotation annotation : annotations) { if (NotNull.class.equals(annotation.annotationType())) { if (null == arg) { String msg = "Argument " + i + " to " + mthd + " may not be null."; log.warn(msg); throw new ApiUsageException(msg); } } else if (Validate.class.equals(annotation.annotationType())) { validated[i] = true; Validate validator = (Validate) annotation; Class[] validClasses = validator.value(); ValidSet validSet = new ValidSet(validClasses); String msg = "Argument " + i + " must be of a type in:" + validSet; if (null == arg) { // handled by NotNull } else if (arg instanceof Collection) { Collection coll = (Collection) arg; for (Object object : coll) { if (object == null) { continue; // ticket:2513. Perhaps should throw AUE } if (!validSet.isValid(object.getClass())) { throw new ApiUsageException(msg); } } } else { if (!validSet.isValid(arg.getClass())) { throw new ApiUsageException(msg); } } } } } for (int i = 0; i < validated.length; i++) { /* warn if someone's forgotten to annotate a method */ if (!paramTypes[i].equals(Object.class) && args[i] instanceof Collection && !validated[i]) { throw new ValidationException( mthd + " is missing a required @" + Validate.class.getName() + " annotation. This should be added to one of the " + " implemented interfaces. Refusing to proceed..."); } } } } } class ValidSet { Class[] classes; public ValidSet(Class[] validClasses) { classes = validClasses; } public boolean isValid(Class target) { if (classes == null) { return false; } for (int i = 0; i < classes.length; i++) { Class klass = classes[i]; if (klass == null) { continue; } if (klass.isAssignableFrom(target)) { return true; } } return false; } @Override public String toString() { return Arrays.asList(classes).toString(); } }