blob: 57da500b6c63fd48c8e6906d113dd150a3f9db31 [file] [log] [blame]
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.pulsar.config.validation;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
/**
* The class that does the validation of all the members of a given object.
*/
public class ConfigValidation {
private static final Class DEFAULT_ANNOTATION_CLASS = ConfigValidationAnnotations.class;
/**
* Validate the config object with annotations from annotationClass
* @param config config object
* @param annotationClass class with annotations to use
*/
public static void validateConfig(Object config, Class annotationClass) {
for (Field field : config.getClass().getDeclaredFields()) {
Object value = null;
field.setAccessible(true);
try {
value = field.get(config);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
validateField(field, value, annotationClass);
}
validateClass(config, annotationClass);
}
/**
* Validate the config object with default annotation class
* @param config config object
*/
public static void validateConfig(Object config) {
validateConfig(config, DEFAULT_ANNOTATION_CLASS);
}
private static void validateClass(Object config, Class annotationClass) {
processAnnotations(config.getClass().getAnnotations(), config.getClass().getName(), config, annotationClass);
}
private static void validateField(Field field, Object value, Class annotationClass) {
processAnnotations(field.getAnnotations(), field.getName(), value, annotationClass);
}
private static void processAnnotations(Annotation[] annotations, String fieldName, Object value, Class annotationClass) {
try {
for (Annotation annotation : annotations) {
String type = annotation.annotationType().getName();
Class<?> validatorClass = null;
Class<?>[] classes = annotationClass.getDeclaredClasses();
//check if annotation is one of our
for (Class<?> clazz : classes) {
if (clazz.getName().equals(type)) {
validatorClass = clazz;
break;
}
}
if (validatorClass != null) {
Object v = validatorClass.cast(annotation);
@SuppressWarnings("unchecked")
Class<Validator> clazz = (Class<Validator>) validatorClass
.getMethod(ConfigValidationAnnotations.ValidatorParams.VALIDATOR_CLASS).invoke(v);
Validator o = null;
Map<String, Object> params = getParamsFromAnnotation(validatorClass, v);
//two constructor signatures used to initialize validators.
//One constructor takes input a Map of arguments, the other doesn't take any
//arguments (default constructor)
//If validator has a constructor that takes a Map as an argument call that constructor
if (hasConstructor(clazz, Map.class)) {
o = clazz.getConstructor(Map.class).newInstance(params);
} else { //If not call default constructor
o = clazz.newInstance();
}
o.validateField(fieldName, value);
}
}
} catch (NoSuchMethodException | IllegalAccessException
| InstantiationException | InvocationTargetException e) {
throw new RuntimeException(e);
}
}
private static Map<String, Object> getParamsFromAnnotation(Class<?> validatorClass, Object v)
throws InvocationTargetException, IllegalAccessException {
Map<String, Object> params = new HashMap<String, Object>();
for (Method method : validatorClass.getDeclaredMethods()) {
Object value = null;
try {
value = (Object) method.invoke(v);
} catch (IllegalArgumentException ex) {
value = null;
}
if (value != null) {
params.put(method.getName(), value);
}
}
return params;
}
public static boolean hasConstructor(Class<?> clazz, Class<?> paramClass) {
Class<?>[] classes = { paramClass };
try {
clazz.getConstructor(classes);
} catch (NoSuchMethodException e) {
return false;
}
return true;
}
}