package org.jboss.seam.util;
import java.io.Serializable;
import java.lang.reflect.Array;
import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
@SuppressWarnings("serial")
public class Conversions
{
private static final String EXPRESSION_MARKER = "#{";
private static final char EXPRESSION_ESCAPE_CHAR = '\\';
private static Map<Class, Converter> converters = new HashMap<Class, Converter>() {{
put(String.class, new StringConverter());
put(Boolean.class, new BooleanConverter());
put(boolean.class, new BooleanConverter());
put(Integer.class, new IntegerConverter());
put(int.class, new IntegerConverter());
put(Long.class, new LongConverter());
put(long.class, new LongConverter());
put(Float.class, new FloatConverter());
put(float.class, new FloatConverter());
put(Double.class, new DoubleConverter());
put(double.class, new DoubleConverter());
put(Character.class, new CharacterConverter());
put(char.class, new CharacterConverter());
put(String[].class, new StringArrayConverter());
put(Set.class, new SetConverter());
put(List.class, new ListConverter());
put(Map.class, new MapConverter());
put(Properties.class, new PropertiesConverter());
//put(Date.class, new DateTimeConverter());
//put(Short.class, new ShortConverter());
//put(Byte.class, new ByteConverter());
put(Enum.class, new EnumConverter());
put(BigInteger.class, new BigIntegerConverter());
put(BigDecimal.class, new BigDecimalConverter());
put(Class.class, new ClassConverter());
}};
public static <Y> void putConverter(Class<Y> type, Converter<Y> converter)
{
converters.put(type, converter);
}
public static <Y> Converter<Y> getConverter(Class<Y> clazz)
{
Converter<Y> converter = converters.get(clazz);
if (converter == null && clazz != null && clazz.isEnum())
{
converter = converters.get(Enum.class);
}
if (converter==null)
{
throw new IllegalArgumentException("No converter for type: " + clazz.getName());
}
return converter;
}
public static interface Converter<Z>
{
public Z toObject(PropertyValue value, Type type);
}
public static class BooleanConverter implements Converter<Boolean>
{
public Boolean toObject(PropertyValue value, Type type)
{
return Boolean.valueOf( value.getSingleValue() );
}
}
public static class IntegerConverter implements Converter<Integer>
{
public Integer toObject(PropertyValue value, Type type)
{
return Integer.valueOf( value.getSingleValue() );
}
}
public static class LongConverter implements Converter<Long>
{
public Long toObject(PropertyValue value, Type type)
{
return Long.valueOf( value.getSingleValue() );
}
}
public static class FloatConverter implements Converter<Float>
{
public Float toObject(PropertyValue value, Type type)
{
return Float.valueOf( value.getSingleValue() );
}
}
public static class DoubleConverter implements Converter<Double>
{
public Double toObject(PropertyValue value, Type type)
{
return Double.valueOf( value.getSingleValue() );
}
}
public static class CharacterConverter implements Converter<Character>
{
public Character toObject(PropertyValue value, Type type)
{
return value.getSingleValue().charAt(0);
}
}
public static class StringConverter implements Converter<String>
{
public String toObject(PropertyValue value, Type type)
{
return value.getSingleValue() ;
}
}
public static class BigDecimalConverter implements Converter<BigDecimal>
{
public BigDecimal toObject(PropertyValue value, Type type)
{
return new BigDecimal(value.getSingleValue());
}
}
public static class BigIntegerConverter implements Converter<BigInteger>
{
public BigInteger toObject(PropertyValue value, Type type)
{
return new BigInteger(value.getSingleValue());
}
}
public static class EnumConverter implements Converter<Enum<?>>
{
public Enum<?> toObject(PropertyValue value, Type type)
{
return Enum.valueOf((Class<Enum>) type, value.getSingleValue());
}
}
public static class StringArrayConverter implements Converter<String[]>
{
public String[] toObject(PropertyValue values, Type type)
{
return values.getMultiValues();
}
}
public static class ArrayConverter implements Converter
{
public Object toObject(PropertyValue values, Type type)
{
String[] strings = values.getMultiValues();
Class elementType = ( (Class) type ).getComponentType();
Object objects = Array.newInstance( elementType, strings.length );
Converter elementConverter = converters.get(elementType);
for (int i=0; i<strings.length; i++)
{
Object element = elementConverter.toObject( new FlatPropertyValue(strings[i]), elementType );
Array.set( objects, i, element );
}
return objects;
}
}
public static class SetConverter implements Converter<Set>
{
public Set toObject(PropertyValue values, Type type)
{
String[] strings = values.getMultiValues();
Class elementType = Reflections.getCollectionElementType(type);
Set set = new HashSet(strings.length);
Converter elementConverter = converters.get(elementType);
for (int i=0; i<strings.length; i++)
{
Object element = elementConverter.toObject( new FlatPropertyValue(strings[i]), elementType );
set.add(element);
}
return set;
}
}
public static class ListConverter implements Converter<List>
{
public List toObject(PropertyValue values, Type type)
{
String[] strings = values.getMultiValues();
Class elementType = Reflections.getCollectionElementType(type);
List list = new ArrayList(strings.length);
Converter elementConverter = converters.get(elementType);
for (int i=0; i<strings.length; i++)
{
list.add( getElementValue( elementType, elementConverter, strings[i] ) );
}
return list;
}
}
private static Object getElementValue(Class elementType, Converter elementConverter, String string)
{
PropertyValue propertyValue = new FlatPropertyValue(string);
if ( propertyValue.isExpression() )
{
throw new IllegalArgumentException("No expressions allowed here");
}
if (elementConverter==null)
{
throw new IllegalArgumentException("No converter for element type: " + elementType.getName());
}
return elementConverter.toObject(propertyValue, elementType);
}
public static class MapConverter implements Converter<Map>
{
public Map toObject(PropertyValue values, Type type)
{
Map<String, String> keyedValues = values.getKeyedValues();
Class elementType = Reflections.getCollectionElementType(type);
Map map = new HashMap( keyedValues.size() );
Converter elementConverter = converters.get(elementType);
for ( Map.Entry<String, String> me: keyedValues.entrySet() )
{
map.put( me.getKey(), getElementValue( elementType, elementConverter, me.getValue() ) );
}
return map;
}
}
public static class PropertiesConverter implements Converter<Properties>
{
public Properties toObject(PropertyValue values, Type type)
{
Map<String, String> keyedValues = values.getKeyedValues();
Properties map = new Properties();
Converter elementConverter = converters.get(String.class);
for ( Map.Entry<String, String> me: keyedValues.entrySet() )
{
String key = me.getKey();
Object element = elementConverter.toObject( new FlatPropertyValue( me.getValue() ), String.class );
map.put(key, element);
}
return map;
}
}
public static class ClassConverter implements Converter<Class>
{
public Class toObject(PropertyValue value, Type type)
{
try
{
return Reflections.classForName( value.getSingleValue() );
}
catch (ClassNotFoundException cnfe)
{
throw new IllegalArgumentException(cnfe);
}
}
}
public static interface PropertyValue extends Serializable
{
Map<String, String> getKeyedValues();
String[] getMultiValues();
String getSingleValue();
boolean isExpression();
boolean isMultiValued();
boolean isAssociativeValued();
Class getType();
}
public static class FlatPropertyValue implements PropertyValue
{
private String string;
public FlatPropertyValue(String string)
{
if (string==null)
{
throw new IllegalArgumentException("null value");
}
this.string = string;
}
public String[] getMultiValues()
{
return Strings.split(string, ", \r\n\f\t");
}
public String getSingleValue()
{
return string;
}
public boolean isExpression()
{
boolean containsExpr = false;
int idx = string.indexOf(EXPRESSION_MARKER);
if (idx == 0) {
containsExpr = true;
}
else {
while (idx != -1) {
if (string.charAt(idx - 1) == EXPRESSION_ESCAPE_CHAR) {
idx = string.indexOf(EXPRESSION_MARKER, idx + 2);
}
else {
containsExpr = true;
break;
}
}
}
return containsExpr;
}
public boolean isMultiValued()
{
return false;
}
public boolean isAssociativeValued()
{
return false;
}
public Map<String, String> getKeyedValues()
{
throw new UnsupportedOperationException("not a keyed property value");
}
@Override
public String toString()
{
return string;
}
public Class getType()
{
return null;
}
}
public static class MultiPropertyValue implements PropertyValue
{
private String[] strings;
private Class type;
public MultiPropertyValue(String[] strings, Class type)
{
if (strings==null) throw new IllegalArgumentException();
this.strings = strings;
this.type = type;
}
public String[] getMultiValues()
{
return strings;
}
public String getSingleValue()
{
throw new UnsupportedOperationException("not a flat property value");
}
public Map<String, String> getKeyedValues()
{
throw new UnsupportedOperationException("not a keyed property value");
}
public boolean isMultiValued()
{
return true;
}
public boolean isAssociativeValued()
{
return false;
}
public boolean isExpression()
{
return false;
}
@Override
public String toString()
{
return Strings.toString( ", ", (Object[]) strings );
}
public Class getType()
{
return type;
}
}
public static class AssociativePropertyValue implements PropertyValue
{
private Map<String, String> keyedValues;
private Class type;
public AssociativePropertyValue(Map<String, String> keyedValues, Class type)
{
if (keyedValues==null) throw new IllegalArgumentException();
this.keyedValues = keyedValues;
this.type = type;
}
public String[] getMultiValues()
{
throw new UnsupportedOperationException("not a multi-valued property value");
}
public String getSingleValue()
{
throw new UnsupportedOperationException("not a flat property value");
}
public Map<String, String> getKeyedValues()
{
return keyedValues;
}
public boolean isExpression()
{
return false;
}
public boolean isMultiValued()
{
return false;
}
public boolean isAssociativeValued()
{
return true;
}
@Override
public String toString()
{
return keyedValues.toString();
}
public Class getType()
{
return type;
}
}
}