/*
* JBoss, Home of Professional Open Source.
* Copyright 2011, Red Hat, Inc., and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This 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 software 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 software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jboss.as.pojo.service;
import org.jboss.as.pojo.logging.PojoLogger;
import org.jboss.as.pojo.descriptor.ValueConfig;
import org.jboss.as.server.deployment.reflect.ClassReflectionIndex;
import org.jboss.as.server.deployment.reflect.DeploymentReflectionIndex;
import org.jboss.common.beans.property.PropertiesValueResolver;
import java.beans.PropertyEditor;
import java.beans.PropertyEditorManager;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Arrays;
import java.util.Collection;
/**
* Configuration util.
*
* @author <a href="mailto:ales.justin@jboss.org">Ales Justin</a>
*/
public class Configurator {
/**
* No parameter types
*/
public static final String[] NO_PARAMS_TYPES = new String[0];
/**
* Turn type into class.
*
* @param type the type
* @return class
*/
public static Class<?> toClass(Type type) {
if (type instanceof Class) {
return (Class) type;
} else if (type instanceof ParameterizedType) {
ParameterizedType pt = (ParameterizedType) type;
return toClass(pt.getRawType());
} else {
throw PojoLogger.ROOT_LOGGER.unknownType(type);
}
}
/**
* Convert a value
*
* @param clazz the class
* @param value the value
* @param replaceProperties whether to replace system properties
* @param trim whether to trim string value
* @return the value or null if there is no editor
* @throws Throwable for any error
*/
@SuppressWarnings("unchecked")
public static Object convertValue(Class<?> clazz, Object value, boolean replaceProperties, boolean trim) throws Throwable {
if (clazz == null)
return value;
if (value == null)
return null;
Class<?> valueClass = value.getClass();
// If we have a string, trim and replace any system properties when requested
if (valueClass == String.class) {
String string = (String) value;
if (trim)
string = string.trim();
if (replaceProperties)
value = PropertiesValueResolver.replaceProperties(string);
}
if (clazz.isAssignableFrom(valueClass))
return value;
// First see if this is an Enum
if (clazz.isEnum()) {
Class<? extends Enum> eclazz = clazz.asSubclass(Enum.class);
return Enum.valueOf(eclazz, value.toString());
}
// Next look for a property editor
if (valueClass == String.class) {
PropertyEditor editor = PropertyEditorManager.findEditor(clazz);
if (editor != null) {
editor.setAsText((String) value);
return editor.getValue();
}
}
// Try a static clazz.valueOf(value)
try {
Method method = clazz.getMethod("valueOf", valueClass);
int modifiers = method.getModifiers();
if (Modifier.isPublic(modifiers) && Modifier.isStatic(modifiers)
&& clazz.isAssignableFrom(method.getReturnType()))
return method.invoke(null, value);
} catch (Exception ignored) {
}
if (valueClass == String.class) {
try {
Constructor constructor = clazz.getConstructor(valueClass);
if (Modifier.isPublic(constructor.getModifiers()))
return constructor.newInstance(value);
} catch (Exception ignored) {
}
}
return value;
}
/**
* Get types from values.
*
* @param values the values
* @return the values' types
*/
public static String[] getTypes(ValueConfig[] values) {
if (values == null || values.length == 0)
return NO_PARAMS_TYPES;
String[] types = new String[values.length];
for (int i =0; i < types.length; i++)
types[i] = values[i].getType();
return types;
}
/**
* Find method info
*
* @param index the deployment reflection index
* @param classInfo the class info
* @param name the method name
* @param paramTypes the parameter types
* @param isStatic must the method be static
* @param isPublic must the method be public
* @param strict is strict about method modifiers
* @return the method info
* @throws IllegalArgumentException when no such method
*/
@SuppressWarnings("unchecked")
public static Method findMethod(DeploymentReflectionIndex index, Class classInfo, String name, String[] paramTypes, boolean isStatic, boolean isPublic, boolean strict) throws IllegalArgumentException {
if (name == null)
throw PojoLogger.ROOT_LOGGER.nullName();
if (classInfo == null)
throw PojoLogger.ROOT_LOGGER.nullClassInfo();
if (paramTypes == null)
paramTypes = NO_PARAMS_TYPES;
Class current = classInfo;
while (current != null) {
ClassReflectionIndex cri = index.getClassIndex(classInfo);
Method result = locateMethod(cri, name, paramTypes, isStatic, isPublic, strict);
if (result != null)
return result;
current = current.getSuperclass();
}
throw PojoLogger.ROOT_LOGGER.methodNotFound(name, Arrays.toString(paramTypes), classInfo.getName());
}
/**
* Find method info
*
* @param classInfo the class info
* @param name the method name
* @param paramTypes the parameter types
* @param isStatic must the method be static
* @param isPublic must the method be public
* @param strict is strict about method modifiers
* @return the method info or null if not found
*/
@SuppressWarnings("unchecked")
private static Method locateMethod(ClassReflectionIndex classInfo, String name, String[] paramTypes, boolean isStatic, boolean isPublic, boolean strict) {
Collection<Method> methods = classInfo.getMethods();
if (methods != null) {
for (Method method : methods) {
if (name.equals(method.getName()) &&
equals(paramTypes, method.getParameterTypes()) &&
(strict == false || (Modifier.isStatic(method.getModifiers()) == isStatic && Modifier.isPublic(method.getModifiers()) == isPublic)))
return method;
}
}
return null;
}
/**
* Test whether type names are equal to type infos
*
* @param typeNames the type names
* @param typeInfos the type infos
* @return true when they are equal
*/
public static boolean equals(String[] typeNames, Class<?>[] typeInfos) {
if (simpleCheck(typeNames, typeInfos) == false)
return false;
for (int i = 0; i < typeNames.length; ++i) {
if (typeNames[i] != null && typeNames[i].equals(typeInfos[i].getName()) == false)
return false;
}
return true;
}
/**
* A simple null and length check.
*
* @param typeNames the type names
* @param typeInfos the type infos
* @return false if either argument is null or lengths differ, else true
*/
protected static boolean simpleCheck(String[] typeNames, Class<?>[] typeInfos) {
return typeNames != null && typeInfos != null && typeNames.length == typeInfos.length;
}
}