package org.ripple.power.collection;
import java.beans.PropertyEditor;
import java.beans.PropertyEditorManager;
import java.lang.reflect.Constructor;
import java.util.HashMap;
import java.util.Map;
import org.ripple.power.ioc.reflect.ConstructorConverter;
import org.ripple.power.ioc.reflect.Converter;
import org.ripple.power.ioc.reflect.PropertyEditorConverter;
import org.ripple.power.ioc.reflect.Reflector;
import org.ripple.power.ioc.reflect.TypeArray;
public class ConverterMap {
public static final BaseTypeMap BaseTypeMap = new BaseTypeMap();
private Map<TypeArray, Converter> converters;
public ConverterMap() {
super();
this.converters = new HashMap<TypeArray, Converter>();
}
public Converter lookup(Class<?> target, Class<? extends Object> input) {
Converter converter = (Converter) converters.get(new TypeArray(
new Class[] { target, input }));
if (converter == null) {
TypeArray[] typearray = (TypeArray[]) converters.keySet().toArray(
new TypeArray[converters.size()]);
for (int i = 0; i < typearray.length; i++) {
if (typearray[i].getParameterTypes()[0].equals(target)
&& typearray[i].getParameterTypes()[1]
.isAssignableFrom(input)) {
converter = (Converter) converters.get(typearray[i]);
TypeArray array = new TypeArray(
new Class[] { target, input });
array.setAliased(true);
converters.put(array, converter);
break;
}
}
}
return converter;
}
public void store(Class<?> targetClass, Converter converter) {
converters.put(
new TypeArray(new Class[] { targetClass,
converter.getInputType() }), converter);
}
public Object[] convertParameters(Class<?>[] targetTypes,
Object[] parameters) {
if (parameters == null) {
return null;
}
Object[] converted = new Object[parameters.length];
for (int i = 0; i < converted.length; i++) {
if (convertAsNull(converted, parameters, i))
continue;
if (convertAsAssignable(targetTypes, converted, parameters, i))
continue;
if (convertAsConvertable(targetTypes, converted, parameters, i))
continue;
if (convertAsPropertyEditor(targetTypes, converted, parameters, i))
continue;
if (convertAsPrimitive(targetTypes, converted, parameters, i))
continue;
if (convertAsConstructor(targetTypes, converted, parameters, i))
continue;
}
return converted;
}
public boolean typeAssignable(Class<?> targetType,
Class<? extends Object> rawClass) {
if (rawClass == null)
return true;
if (targetType.isAssignableFrom(rawClass))
return true;
if (lookup(targetType, rawClass) != null)
return true;
// if (findPropertyEditor(targetType, rawClass) != null)
// return true;
if (isBaseAssignable(targetType, rawClass))
return true;
if (constructorConverter(targetType, rawClass) != null)
return true;
return false;
}
public boolean typesAssignable(Class<?>[] targetTypes, Class<?>[] rawTypes) {
if ((rawTypes == null || rawTypes.length == 0)
&& (targetTypes == null || targetTypes.length == 0)) {
return true;
}
if (rawTypes.length != targetTypes.length) {
return false;
}
for (int i = 0; i < targetTypes.length; i++) {
if (!typeAssignable(targetTypes[i], rawTypes[i])) {
return false;
}
}
return true;
}
private boolean convertAsNull(Object[] converted, Object[] parameters, int i) {
if (parameters[i] == null) {
converted[i] = null;
return true;
}
return false;
}
private boolean convertAsAssignable(Class<?>[] targetTypes,
Object[] converted, Object[] parameters, int i) {
if (targetTypes[i].isAssignableFrom(parameters[i].getClass())) {
converted[i] = parameters[i];
return true;
}
return false;
}
private boolean convertAsPrimitive(Class<?>[] targetTypes,
Object[] converted, Object[] parameters, int i) {
if (isBaseAssignable(targetTypes[i], parameters[i].getClass())) {
converted[i] = parameters[i];
return true;
}
return false;
}
private boolean isBaseAssignable(Class<?> targetType,
Class<?> parameterClass) {
if (targetType.isPrimitive()) {
Class<?> parameterPrimitiveClass = BaseTypeMap
.getBaseClassForWrapper(parameterClass);
if (targetType == parameterPrimitiveClass) {
return true;
}
}
return false;
}
private boolean convertAsPropertyEditor(Class<?>[] targetTypes,
Object[] converted, Object[] parameters, int i) {
Converter pec = findPropertyEditor(targetTypes[i],
parameters[i].getClass());
if (pec != null) {
converted[i] = pec.convert(parameters[i]);
return true;
}
return false;
}
private Converter findPropertyEditor(Class<?> targetType,
Class<?> parameterClass) {
Converter pec = null;
if (String.class.equals(parameterClass)) {
PropertyEditor pe = PropertyEditorManager.findEditor(targetType);
if (pe != null) {
pec = new PropertyEditorConverter(pe);
store(targetType, pec);
}
}
return pec;
}
private boolean convertAsConvertable(Class<?>[] targetTypes,
Object[] converted, Object[] parameters, int i) {
Converter converter = lookup(targetTypes[i], parameters[i].getClass());
if (converter != null) {
converted[i] = converter.convert(parameters[i]);
return true;
}
return false;
}
private boolean convertAsConstructor(Class<?>[] targetTypes,
Object[] converted, Object[] parameters, int i) {
Converter cc = constructorConverter(targetTypes[i],
parameters[i].getClass());
if (cc != null) {
converted[i] = cc.convert(parameters[i]);
return true;
}
return false;
}
private Converter constructorConverter(Class<?> targetType,
Class<?> parameterClass) {
Converter cc = null;
Constructor<?> c = Reflector.getReflector(targetType)
.lookupConstructor(new Class[] { parameterClass }, this, false);
if (c != null) {
cc = new ConstructorConverter(parameterClass, c);
store(targetType, cc);
}
return cc;
}
public static class BaseTypeMap {
private BaseTypeMap() {
super();
}
private final Class<?>[] wrapperClasses = new Class[] { Boolean.class,
Byte.class, Character.class, Short.class, Integer.class,
Long.class, Float.class, Double.class };
private final Class<?>[] baseClasses = new Class[] { Boolean.TYPE,
Byte.TYPE, Character.TYPE, Short.TYPE, Integer.TYPE, Long.TYPE,
Float.TYPE, Double.TYPE };
public Class<?> getBaseClassForWrapper(Class<?> wrapperClass) {
for (int i = 0; i < wrapperClasses.length; i++) {
if (wrapperClasses[i] == wrapperClass) {
return baseClasses[i];
}
}
return null;
}
public Class<?> getWrapperClassForBase(Class<?> BaseClass) {
for (int i = 0; i < baseClasses.length; i++) {
if (baseClasses[i] == BaseClass) {
return wrapperClasses[i];
}
}
return null;
}
public Class<?> getBaseClassForName(String name) {
for (int i = 0; i < baseClasses.length; i++) {
if (baseClasses[i].getName().equals(name)) {
return baseClasses[i];
}
}
return null;
}
}
}