/*
* Created on 07.03.2005
*
*/
package net.sf.crispy.util;
import java.beans.IntrospectionException;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.security.AccessController;
import java.sql.Time;
import java.sql.Timestamp;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.Date;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Locale;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.TreeMap;
import java.util.Vector;
import java.util.Map.Entry;
import net.sf.crispy.InvocationException;
import net.sf.crispy.impl.ServiceManager;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Convert complex object in a simple form and back to the object.
*
* @author Linke
*
*/
public class Converter {
public final static String HASH_CODE_KEY = "~hashCode~";
public final static int GET_METHOD = 1;
public final static int SET_METHOD = 2;
protected static final Log log = LogFactory.getLog (Converter.class);
protected static final Map isSimpleDataType = new Hashtable();
protected static final ClassPropertiesCache classPropertiesCacheGetter = new ClassPropertiesCache();
protected static final ClassPropertiesCache classPropertiesCacheSetter = new ClassPropertiesCache();
private String nullValue = null;
private boolean withSimpleKeyMapper = false;
public Converter() { }
public Converter(String pvNullValue) {
setNullValue(pvNullValue);
}
public Converter(int pvStartHashCode) {
uniqueIdMap = new Hashtable();
startHashCode = pvStartHashCode;
}
public void setWithSimpleKeyMapper(boolean pvWithSimpleKeyMapper) { withSimpleKeyMapper = pvWithSimpleKeyMapper; }
public boolean getWithSimpleKeyMapper() { return withSimpleKeyMapper; }
public static boolean isValideEdge(Object pvObject) {
if (pvObject == null) { return false; }
if (isSimpleDataType.size() == 0) {
isSimpleDataType.put(String.class, String.class);
isSimpleDataType.put(Boolean.class, Boolean.class);
isSimpleDataType.put(boolean.class, boolean.class);
isSimpleDataType.put(Byte.class, Byte.class);
isSimpleDataType.put(byte.class, byte.class);
isSimpleDataType.put(Short.class, Short.class);
isSimpleDataType.put(short.class, short.class);
isSimpleDataType.put(Integer.class, Integer.class);
isSimpleDataType.put(int.class, int.class);
isSimpleDataType.put(Long.class, Long.class);
isSimpleDataType.put(long.class, long.class);
isSimpleDataType.put(Float.class, Float.class);
isSimpleDataType.put(float.class, float.class);
isSimpleDataType.put(Double.class, Double.class);
isSimpleDataType.put(double.class, double.class);
isSimpleDataType.put(Character.class, Character.class);
isSimpleDataType.put(char.class, char.class);
isSimpleDataType.put(BigDecimal.class, BigDecimal.class);
isSimpleDataType.put(StringBuffer.class, StringBuffer.class);
isSimpleDataType.put(BigInteger.class, BigInteger.class);
isSimpleDataType.put(Class.class, Class.class);
isSimpleDataType.put(java.sql.Date.class, java.sql.Date.class);
isSimpleDataType.put(java.util.Date.class, java.util.Date.class);
isSimpleDataType.put(Time.class, Time.class);
isSimpleDataType.put(Timestamp.class, Timestamp.class);
}
boolean b = isSimpleDataType.containsKey(pvObject.getClass());
// return ! b;
if (b == true) {
return false;
}
else {
return true;
}
}
private Map uniqueIdMap = null;
private Map uniqueIdMap2 = null;
private int hashCode = 0;
private int startHashCode = -1000000000;
// private int startHashCode = 1;
public String getNullValue() { return nullValue; }
public void setNullValue(String pvNullValue) { nullValue = pvNullValue; }
public String findNextFreeId (int pvHashCode) {
String lvHashCodeStr = Integer.toString(pvHashCode);
if (uniqueIdMap.containsKey(lvHashCodeStr)) {
int next = pvHashCode + 1;
lvHashCodeStr = findNextFreeId (next);
}
return lvHashCodeStr;
}
private String getUniqueId(Object pvObject) {
if (pvObject == null) {return null; }
String lvHashCode = (String) uniqueIdMap2.get(pvObject);
if (lvHashCode != null){
return lvHashCode;
}
lvHashCode = Integer.toString(pvObject.hashCode());
Object o = uniqueIdMap.get(lvHashCode);
if (o == null) {
uniqueIdMap.put(lvHashCode, pvObject);
uniqueIdMap2.put(pvObject, lvHashCode);
}
else { //if (!(o.equals(pvObject))) {
lvHashCode = findNextFreeId(hashCode);
uniqueIdMap.put(lvHashCode, pvObject);
uniqueIdMap2.put(pvObject, lvHashCode);
}
return lvHashCode;
}
/**
* Convert complex object in a Hashtable and relations in Vector.
* Cycles are finded and removed.
*
* @param pvObject Complex or simple object.
* @return Simple object structure.
* @throws Exception
*/
public Object makeSimple (Object pvObject) throws Exception {
uniqueIdMap = new Hashtable();
uniqueIdMap2 = new Hashtable();
hashCode = startHashCode;
Object lvReturn = null;
try {
lvReturn = makeSimpleInternal (pvObject, null, new Graph());
}
finally {
uniqueIdMap = null;
uniqueIdMap2 = null;
hashCode = startHashCode;
}
return lvReturn;
}
private Object makeSimpleInternal (Object pvObject, String pvPropName, Graph pvGraph) throws Exception {
Method lvMethod = null;
if (pvObject == null) { return nullValue; }
Class clazz = pvObject.getClass();
// Zugelassene Datentypen
if (clazz.equals(String.class)) { return pvObject; }
else if (clazz.equals(Date.class)) { return pvObject; }
else if (clazz.equals(Integer.class)) { return pvObject; }
else if (clazz.equals(Double.class)) { return pvObject; }
else if (clazz.equals(Boolean.class)) { return pvObject; }
else if ((clazz.isArray()) && (clazz.getComponentType().equals(byte.class))) { return pvObject; }
// Konvertierung von primitiven Typen in zugelassene primitive Typen
else if (clazz.equals(Long.class)) { return Integer.valueOf(pvObject.toString()); }
else if (clazz.equals(Byte.class)) { return Integer.valueOf(pvObject.toString()); }
else if (clazz.equals(Float.class)) { return new Double(pvObject.toString()); }
else if (clazz.equals(Character.class)) { return pvObject.toString(); }
else if (clazz.equals(Short.class)) { return Integer.valueOf(pvObject.toString()); }
else if (clazz.equals(BigDecimal.class)) { return new Double(pvObject.toString()); }
else if (clazz.equals(StringBuffer.class)) { return pvObject.toString(); }
else if (clazz.equals(BigInteger.class)) { return Integer.valueOf(pvObject.toString()); }
else if (clazz.equals(Class.class)) { return ((Class) pvObject).getName(); }
else if (clazz.equals(java.sql.Date.class)) { return new Date(((java.sql.Date) pvObject).getTime()); }
else if (clazz.equals(Time.class)) { return (Date) pvObject; }
else if (clazz.equals(Timestamp.class)) { return (Date) pvObject; }
// Behaelter
else if (pvObject instanceof Collection) {
final Collection coll = (Collection) pvObject;
Iterator it = coll.iterator();
Vector v = new Vector(coll.size());
while (it.hasNext()) {
Object lvValue = it.next();
String lvHashCode = getUniqueId(lvValue);
if (pvGraph.getVertexCount(lvValue) == true) {
v.add(HASH_CODE_KEY + lvHashCode);
} else {
Object o = makeSimpleInternal(lvValue, pvPropName, pvGraph);
if (o != null) { v.add(o); }
}
}
return v;
}
else if (pvObject instanceof Map) {
Map map = (Map) pvObject;
Hashtable lvHashtable = new Hashtable(map.size());
// um Reihenfolge zu merken, ist wichtig,
// wenn Objekte aus der Map geholt werden
int pos = 0;
SimpleKeyMapper lvKeyMapper = new SimpleKeyMapper();
Iterator it = map.entrySet().iterator();
while (it.hasNext()) {
Map.Entry lvMapEntry = (Entry) it.next();
Object lvKey = lvMapEntry.getKey();
pos = ++pos;
if (isValideEdge(lvKey)) { throw new InvocationException("Complex Map-Key datatypes are not supported: " + lvKey.getClass().getName()); }
Object lvValue = lvMapEntry.getValue();
String lvHashCode = getUniqueId(lvValue);
// class before transformatio
Class lvKeyClass = lvKey.getClass();
// transformation from the key to simple object (e.g. from Long to Integer)
lvKey = makeSimpleInternal(lvKey, pvPropName, pvGraph);
// den Schluessel in eine Map verpacken, damit die Reihenfolge NICHT verloren geht
Object key = lvKeyMapper.toSimpleNewKey(lvKey, lvKeyClass, pos, withSimpleKeyMapper);
if (pvGraph.getVertexCount(lvValue) == true) {
lvHashtable.put(key, HASH_CODE_KEY + lvHashCode);
} else {
Object o = makeSimpleInternal(lvValue, pvPropName, pvGraph);
if (o != null) { lvHashtable.put(key, o); }
}
}
return lvHashtable;
}
else if (clazz.isArray()) {
int length = Array.getLength(pvObject);
Vector v = new Vector(length);
for (int i=0;i<length;i++) {
Object lvValue = Array.get (pvObject, i);
String lvHashCode = getUniqueId(lvValue);
if (pvGraph.getVertexCount(lvValue) == true) {
v.add(HASH_CODE_KEY + lvHashCode);
} else {
Object o = makeSimpleInternal(lvValue, pvPropName, pvGraph);
if (o != null) { v.add(o); }
}
}
return v;
}
// Konvertierung von Objekten in eine Hashtable
else {
Hashtable map = new Hashtable();
String lvHashCode = getUniqueId(pvObject);
map.put(HASH_CODE_KEY, lvHashCode);
pvGraph.addVertex(pvObject);
Map lvGetterMap = getAllGetterMethodWithCache(clazz);
Iterator it = lvGetterMap.entrySet().iterator();
while (it.hasNext()) {
Map.Entry lvMapEntry = (Entry) it.next();
String propName = (String) lvMapEntry.getKey();
if (propName.equals("class") == false) {
Object lvValue = null;
try {
lvMethod = (Method)lvMapEntry.getValue();
lvValue = lvMethod.invoke(pvObject, null);
} catch (Exception e) {
if (log.isDebugEnabled()) { log.debug("Problem by invoke method (in makeSimple): " + lvMethod, e); }
if (ServiceManager.DEBUG_MODE_ON) { e.printStackTrace(); }
}
// test of cycles
if (lvValue != null) {
Edge lvEdge = new Edge(pvObject, lvValue);
if (pvGraph.containsKey(lvEdge) == false) {
if (isValideEdge(lvValue) == true) {
pvGraph.put(lvEdge, "");
}
Edge lvKnownEdgeToThisNode = pvGraph.isFromContains(lvValue);
if (lvKnownEdgeToThisNode != null) {
lvEdge.setMethodName(lvMethod.getName());
map.put(propName, HASH_CODE_KEY + getUniqueId(lvValue));
}
else {
Object o = makeSimpleInternal(lvValue, propName, pvGraph);
map.put(propName, o);
}
}
else {
map.put(propName, HASH_CODE_KEY + getUniqueId(lvValue));
}
}
} else {
// fuer das unmarshalling
map.put("class", clazz.getName());
}
}
return map;
}
}
public Object makeComplex (Object pvObject) throws Exception {
return makeComplex(pvObject, null);
}
public Object makeComplex (Object pvObject, Class clazz) throws Exception {
return makeComplex(pvObject, clazz, null);
}
public Object makeComplex (Object pvObject, Class clazz, Class clazzInArray) throws Exception {
return makeComplexInternal(pvObject, clazz, clazzInArray, new Hashtable());
}
private Object makeComplexInternal (final Object pvObject, final Class pvClazz, final Class clazzInArray, final Map pvHashCodeMap) throws Exception {
Method lvMethod = null;
Class clazz = pvClazz;
if (pvObject == null || pvObject.equals(nullValue)) { return null; }
if (pvClazz == null) { clazz = pvObject.getClass(); }
// clazz ist vom Typ Object, pvObject aber NICHT,
// deshalb den typ von pvObject uebernehmen
if ((clazz.equals(Object.class)) && (!(pvObject.getClass().equals(Object.class)))) {
if (log.isDebugEnabled()) {
log.debug("Class: "+ clazz.getName() + " is different from Object: " + pvObject.getClass().getName());
}
clazz = pvObject.getClass();
}
// Zugelassene Datentypen
if (clazz.equals(String.class)) { return pvObject; }
else if (clazz.equals(Integer.class)) { return pvObject; }
else if (clazz.equals(Double.class)) { return pvObject; }
else if (clazz.equals(Boolean.class)) { return pvObject; }
else if (clazz.equals(Date.class)) { return pvObject; }
else if ((clazz.isArray()) && (clazz.getComponentType().equals(byte.class))) { return pvObject; }
// Primitive Datentypen
else if (clazz.equals(boolean.class)) { return pvObject; }
else if (clazz.equals(short.class)) { return new Short(pvObject.toString()); }
else if (clazz.equals(byte.class)) { return new Byte(pvObject.toString()); }
else if (clazz.equals(int.class)) { return pvObject; }
else if (clazz.equals(long.class)) { return new Long(pvObject.toString()); }
else if (clazz.equals(double.class)) { return new Double(pvObject.toString()); }
else if (clazz.equals(float.class)) { return new Float(pvObject.toString()); }
else if (clazz.equals(char.class)) { return new Character(pvObject.toString().charAt(0)); }
// Konvertierung von primitiven Typen in zugelassene primitive Typen
else if (clazz.equals(Byte.class)) { return new Byte(pvObject.toString()); }
else if (clazz.equals(Float.class)) { return new Float(pvObject.toString()); }
else if (clazz.equals(Character.class)) { return new Character(pvObject.toString().charAt(0)); }
else if (clazz.equals(Long.class)) { return new Long(pvObject.toString()); }
else if (clazz.equals(Short.class)) { return new Short(pvObject.toString()); }
else if (clazz.equals(BigDecimal.class)) { return new BigDecimal (((Double) pvObject).doubleValue()); }
else if (clazz.equals(StringBuffer.class)) { return new StringBuffer(pvObject.toString()); }
else if (clazz.equals(BigInteger.class)) { return new BigInteger(pvObject.toString()); }
else if (clazz.equals(Class.class)) { return Class.forName(pvObject.toString()); }
else if (clazz.equals(java.sql.Date.class)) { return new java.sql.Date(((Date) pvObject).getTime()); }
else if (clazz.equals(Time.class)) {
if (pvObject instanceof Time) {
return (Time) pvObject;
}
else if (pvObject instanceof Timestamp) {
Timestamp ts = (Timestamp) pvObject;
return new Time(ts.getTime());
}
else if (pvObject instanceof Date) {
return new Time(((Date) pvObject).getTime());
}
else if (pvObject instanceof Long) {
Long l = (Long) pvObject;
return new Time(l.longValue());
}
else {
throw new InvocationException("Exception by Converter.makeComplex. The datatype: " + pvObject.getClass().getName()
+ " is not compatible to java.sql.Time");
}
}
else if (clazz.equals(Timestamp.class)) {
if (pvObject instanceof Timestamp) {
return (Timestamp) pvObject;
}
else if (pvObject instanceof Time) {
Time t = (Time) pvObject;
return new Timestamp(t.getTime());
}
else if (pvObject instanceof Date) {
return new Timestamp(((Date) pvObject).getTime());
}
else if (pvObject instanceof Long) {
Long l = (Long) pvObject;
return new Timestamp(l.longValue());
}
else {
throw new InvocationException("Exception by Converter.makeComplex. The datatype: " + pvObject.getClass().getName()
+ " is not compatible to java.sql.Timestamp");
}
}
else if (clazz.isArray()) {
// wenn pvObject kein Array ist
if ((!pvObject.getClass().isArray()) && (pvObject instanceof Collection)) {
Collection coll = (Collection) pvObject;
Class lvType = (clazzInArray == null ? getArrayType(pvObject) : clazzInArray);
Object[] lvTempArray = (Object[]) Array.newInstance(lvType, coll.size());
Iterator it = coll.iterator();
int i = 0;
while (it.hasNext()) {
Object objInList = it.next();
String lvHashCode = objInList.toString();
if (lvHashCode.startsWith(HASH_CODE_KEY) == true) {
lvHashCode = lvHashCode.substring(HASH_CODE_KEY.length());
Object value = pvHashCodeMap.get(lvHashCode);
if (value == null) {
throw new InvocationException("Internal Converter-Exception. " +
"For the HashCode: " + lvHashCode + " can not find a object in the Array: " + coll);
} else {
lvTempArray[i] = value;
}
} else {
if (clazzInArray == null) {
lvTempArray[i] = objInList;
}
else {
lvTempArray[i] = makeComplexInternal(objInList, clazzInArray, null, pvHashCodeMap);
}
}
i++;
}
return lvTempArray;
}
// wenn pvObject kein Array ist
if ((!pvObject.getClass().isArray()) && (pvObject instanceof Map)) {
return makeComplexInternal(pvObject, null, null, pvHashCodeMap);
} else {
int length = Array.getLength(pvObject);
Class lvType = (clazzInArray == null ? getArrayType(pvObject) : clazzInArray);
Object[] o = (Object[]) Array.newInstance(lvType, length);
for (int i=0;i<length;i++) {
Object _o = Array.get (pvObject, i);
o[i] = makeComplexInternal(_o, lvType, null, pvHashCodeMap);
}
return o;
}
}
// Behaelter
else if (pvObject instanceof Collection) {
Collection coll = (Collection) pvObject;
Iterator it = coll.iterator();
Collection lvNewColl = new Vector(coll.size());
while (it.hasNext()) {
Object o = it.next();
// null value are ignored
if (o != null) {
String lvHashCode = o.toString();
if (lvHashCode.startsWith(HASH_CODE_KEY) == true) {
lvHashCode = lvHashCode.substring(HASH_CODE_KEY.length());
Object value = pvHashCodeMap.get(lvHashCode);
if (value == null) {
throw new InvocationException("Internal Converter-Exception. " +
"For the HashCode: " + lvHashCode + " can not find a object in the Collection: " + coll);
} else {
lvNewColl.add(value);
}
} else {
Object value = makeComplexInternal(o, o.getClass(), null, pvHashCodeMap);
lvNewColl.add(value);
}
}
}
return lvNewColl;
}
else if (pvObject instanceof Map) {
Map map = (Map) pvObject;
String aClazzStr = (String) map.get("class");
if (aClazzStr == null) {
SimpleKeyMapper lvSimpleKeyMapper = new SimpleKeyMapper();
map = lvSimpleKeyMapper.orderMapByKey(map, withSimpleKeyMapper);
Iterator it = map.entrySet().iterator();
Hashtable lvHashtable = new Hashtable(map.size());
while (it.hasNext()) {
Map.Entry lvMapEntry = (Entry) it.next();
Object lvKey = lvMapEntry.getKey();
Object key = lvSimpleKeyMapper.toComplexNewKey(lvKey, withSimpleKeyMapper);
Object lvValue = lvMapEntry.getValue();
String lvHashCode = extractHashCode(lvValue);
if (lvHashCode != null) {
lvValue = pvHashCodeMap.get(lvHashCode);
if (lvValue == null) {
throw new InvocationException("Internal Converter-Exception. " +
"For the HashCode: " + lvHashCode + " can not find a object in a map: " + map);
} else {
lvHashtable.put(key, lvValue);
}
} else {
lvValue = makeComplexInternal(lvValue, lvValue.getClass(), null, pvHashCodeMap);
lvHashtable.put(key, lvValue);
}
}
return lvHashtable;
} else {
Class aClazz = null;
try {
aClazz = Class.forName(aClazzStr);
} catch (Exception e) {
throw new InvocationException("Can't load class: " + aClazzStr);
}
Object ret = null;
try {
ret = aClazz.newInstance();
} catch (Exception e) {
throw new InvocationException("Can't create object from class: " + aClazzStr + " (No constructor without parameter!)");
}
String lvMapHashCode = (String) map.get(HASH_CODE_KEY);
if (lvMapHashCode != null) { pvHashCodeMap.put(lvMapHashCode, ret); }
try {
Map lvSetterMap = getAllSetterMethodWithCache(aClazz);
Iterator it = lvSetterMap.entrySet().iterator();
while (it.hasNext()) {
Map.Entry lvMapEntry = (Entry) it.next();
String propName = (String) lvMapEntry.getKey();
Object value = map.get(propName);
if (value != null) {
String lvHashCode = extractHashCode(value);
lvMethod = (Method) lvMapEntry.getValue();
Class lvParamType = lvMethod.getParameterTypes()[0];
if (lvHashCode != null) {
value = pvHashCodeMap.get(lvHashCode);
} else {
value = makeComplexInternal(value, lvParamType, lvParamType.getComponentType(), pvHashCodeMap);
}
try {
value = makeAssignable(lvParamType, value);
lvMethod.invoke(ret, new Object [] {value});
} catch (Exception e) {
if (log.isDebugEnabled()) { log.debug("Problem by invoke method (in makeComplex): " + lvMethod, e); }
if (ServiceManager.DEBUG_MODE_ON) {
e.printStackTrace();
}
}
} // value != null
}
} catch (Exception e) {
if (log.isWarnEnabled()) { log.warn("Error in Converter.makeComplex by Method: " + lvMethod, e); }
if (ServiceManager.DEBUG_MODE_ON) { e.printStackTrace(); }
}
return ret;
}
}
else {
if (log.isInfoEnabled()) {
log.info("Invalide Type in makeComplex for Class: " + clazz + " with value: " + pvObject
+ " (Class from Object: " + pvObject.getClass().getName() + ")");
}
return null;
}
}
public static Object makeAssignable(Class pvSourceClass, Object pvValue) {
if (pvSourceClass.equals(Object.class)) {
return pvValue;
}
else if (pvSourceClass.isAssignableFrom(Set.class) && pvValue instanceof Collection) {
return new HashSet((Collection) pvValue);
}
else if (pvSourceClass.isAssignableFrom(Properties.class) && pvValue instanceof Map) {
Map lvMap = (Map) pvValue;
Properties lvProperties = new Properties();
Iterator it = lvMap.entrySet().iterator();
while (it.hasNext()) {
Map.Entry lvMapEntry = (Entry) it.next();
lvProperties.put(lvMapEntry.getKey(), lvMapEntry.getValue());
}
return lvProperties;
}
return pvValue;
}
/**
* Analysed the objects in an Array/Collection. If all Object from the same class type,
* then is the return value this class. If are several class types in the Array,
* then ist the return class from type Object.
* @param pvListObj
* @return Class, that are in the Array or Collection
*/
public static Class getArrayType (Object pvListObj) {
Class lvType = Object.class;
if (pvListObj == null) { return lvType; }
if (pvListObj.getClass().isArray()) {
Object o[] = (Object[]) pvListObj;
if (o.length > 0) {
Class lvClass = o[0].getClass();
// !!!!! Specialfall ?????
if(Map.class.isAssignableFrom(lvClass)) {
return Object.class;
}
for (int i = 0; i < o.length; i++) {
if (!lvClass.equals(o[i].getClass())) {
return lvType;
}
}
return lvClass;
} else {
return o.getClass().getComponentType();
}
}
else if (pvListObj instanceof Collection) {
Collection coll = (Collection) pvListObj;
if (coll.size() > 0) {
Class lvClass = coll.iterator().next().getClass();
Iterator it = coll.iterator();
while (it.hasNext()) {
if (!lvClass.equals(it.next().getClass())) {
return lvType;
}
}
return lvClass;
} else {
return lvType;
}
}
return lvType;
}
public static Object convertClassString2Object (String pvClassName) throws Exception {
if (pvClassName == null) { return null; }
else if (pvClassName.equals(int.class.getName())) { return Integer.valueOf("0"); }
else if (pvClassName.equals(short.class.getName())) { return Short.valueOf("0"); }
else if (pvClassName.equals(byte.class.getName())) { return Byte.valueOf("0"); }
else if (pvClassName.equals(long.class.getName())) { return Long.valueOf("0"); }
else if (pvClassName.equals(double.class.getName())) { return Double.valueOf("0"); }
else if (pvClassName.equals(float.class.getName())) { return Float.valueOf("0"); }
else if (pvClassName.equals(char.class.getName())) { return new Character(' '); }
else if (pvClassName.equals(Character.class.getName())) { return new Character(' '); }
else if (pvClassName.equals(boolean.class.getName())) { return Boolean.TRUE; }
else if (pvClassName.equals(Boolean.class.getName())) { return Boolean.TRUE; }
else if ((pvClassName.startsWith("[L")) && (pvClassName.endsWith(";"))) {
try {
String lvClassName = pvClassName.substring(2, (pvClassName.length() - 1));
lvClassName = lvClassName.replaceAll("/", "\\.");
Class clazz = Class.forName(lvClassName);
Object lvArray = Array.newInstance(clazz, 0);
return lvArray;
} catch (Exception e) {
if (log.isDebugEnabled()) { log.debug("convertClassString2Object: " + pvClassName, e); }
if (ServiceManager.DEBUG_MODE_ON) { e.printStackTrace(); }
return null;
}
}
else {
Object lvReturn = createObjectWithParamConstructor(null, null, pvClassName);
if (lvReturn == null) {
lvReturn = createObjectWithParamConstructor(new Long(0), long.class, pvClassName);
}
if (lvReturn == null) {
lvReturn = createObjectWithParamConstructor("0", String.class, pvClassName);
}
return lvReturn;
}
}
public static Object createObjectWithParamConstructor (Object pvParam, Class pvParamType, String pvClassName) {
try {
Class clazz = Class.forName(pvClassName);
if (pvParam == null) {
return clazz.newInstance();
} else {
Constructor lvConstructor = clazz.getConstructor(new Class[] {pvParamType});
return lvConstructor.newInstance(new Object [] {pvParam});
}
} catch (Exception e) {
if (log.isDebugEnabled()) { log.debug("convertString2ClassString: " + pvClassName, e); }
if (ServiceManager.DEBUG_MODE_ON) { e.printStackTrace(); }
}
return null;
}
/**
* For example String to Integer or String to Date, ...
*
* @param pvStringValue Value in String class.
* @param pvClassName Class name to convert the String value.
* @return The converted String value.
*/
public static Object convertString2Value (String pvStringValue, String pvClassName) throws Exception {
Class clazz = null;
if (pvClassName.equals(int.class.getName())) { clazz = int.class; }
else if (pvClassName.equals(short.class.getName())) { clazz = short.class; }
else if (pvClassName.equals(byte.class.getName())) { clazz = byte.class; }
else if (pvClassName.equals(long.class.getName())) { clazz = long.class; }
else if (pvClassName.equals(double.class.getName())) { clazz = double.class; }
else if (pvClassName.equals(float.class.getName())) { clazz = float.class; }
else if (pvClassName.equals(char.class.getName())) { clazz = char.class; }
else if (pvClassName.equals(boolean.class.getName())) { clazz = boolean.class; }
else {
try {
clazz = Class.forName(pvClassName);
} catch (Exception e) {
if (ServiceManager.DEBUG_MODE_ON) {
e.printStackTrace();
}
}
}
return convertString2Value (pvStringValue, clazz);
}
public static Object convertString2Value (Object pvValue, Class pvClass) {
if (pvValue instanceof String) {
return convertString2Value((String) pvValue, pvClass);
} else {
return pvValue;
}
}
/**
* For example String to Integer or String to Date, ...
*
* @param pvStringValue Value in String class.
* @param pvClass Type to convert the String value.
* @return The converted String value.
*/
public static Object convertString2Value (String pvStringValue, Class pvClass) {
if ((pvClass == null) || (pvStringValue == null)) { return null; }
if ((pvClass.equals(Integer.class)) || (pvClass.equals(int.class))) { return Integer.valueOf(pvStringValue); }
else if ((pvClass.equals(Short.class)) || (pvClass.equals(short.class))) { return Short.valueOf(pvStringValue); }
else if ((pvClass.equals(Byte.class)) || (pvClass.equals(byte.class))) { return Byte.valueOf(pvStringValue); }
else if ((pvClass.equals(Long.class)) || (pvClass.equals(long.class))) { return Long.valueOf(pvStringValue); }
else if ((pvClass.equals(Double.class)) || (pvClass.equals(double.class))) { return Double.valueOf(pvStringValue); }
else if ((pvClass.equals(Float.class)) || (pvClass.equals(float.class))) { return Float.valueOf(pvStringValue); }
else if (pvClass.equals(BigDecimal.class)) { return new BigDecimal (pvStringValue); }
else if ((pvClass.equals(Boolean.class)) || (pvClass.equals(boolean.class))) { return Boolean.valueOf(pvStringValue); }
else if ((pvClass.equals(Character.class)) || (pvClass.equals(char.class))) { return new Character(pvStringValue.charAt(0)); }
else if (pvClass.equals(String.class)) { return pvStringValue; }
else if ((pvClass.equals(Date.class)) || (pvClass.equals(java.sql.Date.class))){ return Converter.string2Date(pvStringValue); }
else {
// ??? throw new IllegalArgumentException("Illegal value: " + pvStringValue + " or type: " + pvClass); ???
log.warn("Illegal value in Converter.convertString2Value: " + pvStringValue + " for class: " + pvClass);
try {
return pvClass.newInstance();
} catch (Exception e) {
if (log.isDebugEnabled()) {
log.debug("Error by convertString2Value by new Instance for class: " + pvClass, e);
if (ServiceManager.DEBUG_MODE_ON) { e.printStackTrace(); }
}
return null;
}
}
}
/**
* Convert String-Parameter (contains in the Vector) in Method-ParameterTypes.
* For example: Vector ["5", "8"] convert to new Integer [] { new Integer(5), new Integer (8) }
*
* @param pvMethod Method with ParameterTypes.
* @param pvParams Vector with Strings.
*
* @return Array with ParameterTypes and ParameterValues.
*/
public static Object[] convertStringParams2MethodParams (Method pvMethod, Vector pvParams) {
if ((pvMethod == null) || (pvParams == null)) {
throw new IllegalArgumentException("The method parameter: " + pvMethod + " or params array: " + pvParams +
" must not null!");
}
Class lvParamTypes[] = pvMethod.getParameterTypes();
if (pvParams.size() != lvParamTypes.length) {
throw new IllegalArgumentException("The parameter size: " + pvParams.size()
+ " is not equal to method parameter: " + lvParamTypes.length);
}
Object lvNewParams[] = new Object[pvParams.size()];
for (int i = 0; i < lvNewParams.length; i++) {
lvNewParams[i] = Converter.convertString2Value(pvParams.get(i), lvParamTypes[i]);
}
return lvNewParams;
}
/**
* Convert a Date-String to a Date. The Converter <b>neglected the Millisecond</b>.
* Example: Thu Aug 11 19:30:57 CEST 2005
*
* @param pvDateString The Date-String (unequal null).
* @return Valid <code>java.util.Date</code>.
*/
public static Date string2Date (String pvDateString) {
if (pvDateString == null) { throw new IllegalArgumentException ("The Date-String was null by string2Date."); }
Date date = null;
// 1. Versuch, Datum wie es bei der toString-Methode zurueck kommt, umzuwandeln
DateFormat df = new SimpleDateFormat("EEE MMM dd HH:mm:ss 'CEST' yyyy", Locale.ENGLISH);
try {
date = df.parse(pvDateString);
return date;
} catch (ParseException e) {
log.debug("Error by string2Date: " + pvDateString , e);
}
// 2. Versuch, Datum wie es bei der toString-Methode zurueck kommt, umzuwandeln
df = new SimpleDateFormat("EEE MMM dd HH:mm:ss 'CET' yyyy", Locale.ENGLISH);
try {
date = df.parse(pvDateString);
return date;
} catch (ParseException e) {
log.debug("Error by string2Date: " + pvDateString , e);
}
// 3. Verusch, Medium Datum umzuwandeln
df = DateFormat.getDateInstance(DateFormat.MEDIUM);
try {
date = df.parse(pvDateString);
return date;
} catch (ParseException e) {
log.debug("Error by string2Date: " + pvDateString , e);
}
throw new IllegalStateException ("The String: \"" + pvDateString + "\" is not valid date.");
}
/**
* Extract from package + class name, the class name.
* Example (<code>pvToLowerCase = false)</code>): Input: <code>net.sf.crispy.ServiceManager</code> -> Output: <code>ServiceManger</code>.
* Example (<code>pvToLowerCase = true)</code>): Input: <code>net.sf.crispy.ServiceManager</code> -> Output: <code>servicemanger</code>.
*
* @param pvClassWitchPackage
* @param pvToLowerCase
* @return The class without package.
*/
public static String getClassWithoutPackage(String pvClassWitchPackage, boolean pvToLowerCase) {
if (pvClassWitchPackage == null) { return null; }
int lvIndex = pvClassWitchPackage.lastIndexOf('.') + 1;
String lvClassName = pvClassWitchPackage.substring(lvIndex);
if (pvToLowerCase == true) { lvClassName = lvClassName.toLowerCase(); }
return lvClassName;
}
/**
* If pvObject.toString - method start with <code>Converter.HASH_CODE_KEY</code>, then extract
* the hash code.
* Example: make from <code>~hashCode~24306761</code> to <code>24306761</code>.
*
* @param pvObject
* @return The hash code.
*/
public static String extractHashCode (Object pvObject) {
if (pvObject == null) { return null; }
String lvHashCode = pvObject.toString();
if (lvHashCode.startsWith(HASH_CODE_KEY) == true) {
lvHashCode = lvHashCode.substring(HASH_CODE_KEY.length());
return lvHashCode;
} else {
return null;
}
}
/**
* Remove all getter-method where no setter-method exist.
*/
public static Map getAllNotEqualsGetterAndSetterAndRemoveThisProperties(Map pvGetterMap, Map pvSetterMap) {
Iterator it = new ArrayList(pvGetterMap.keySet()).iterator();
while (it.hasNext()) {
Object lvGetterProp = it.next();
if (!(pvSetterMap.containsKey(lvGetterProp)) && !(lvGetterProp.equals("class"))) {
if (log.isDebugEnabled()) {
log.debug("For Getter: " + lvGetterProp + " --> no Setter!");
}
pvGetterMap.remove(lvGetterProp);
}
}
return pvGetterMap;
}
/**
* Find all getter-method from a Class and remove all getter-method where no setter-method exist.
* @param pvClass Class to anaylse.
* @return Map from getter-method (key=property name, value=method).
* @throws IntrospectionException
*/
public static Map getAllGetterMethodWithCache(Class pvClass) throws IntrospectionException {
Map lvGetterMap = classPropertiesCacheGetter.getClassPropertiesMapByClass(pvClass);
if (lvGetterMap == null) {
try {
lvGetterMap = Converter.getAllGetterMethod(pvClass);
Map lvSetterMap = getAllSetterMethodWithCache(pvClass);
lvGetterMap = getAllNotEqualsGetterAndSetterAndRemoveThisProperties (lvGetterMap, lvSetterMap);
classPropertiesCacheGetter.addClassPropertiesMap(pvClass, lvGetterMap);
} catch (IntrospectionException e) {
if (ServiceManager.DEBUG_MODE_ON) {
e.printStackTrace();
}
}
}
return lvGetterMap;
}
/**
* Find all setter-method from a Class.
* @param pvClass Class to analyse.
* @return Map all setter-Method (key=property name, value=method).
* @throws IntrospectionException
*/
public static Map getAllSetterMethodWithCache(Class pvClass) throws IntrospectionException {
Map lvMap = classPropertiesCacheSetter.getClassPropertiesMapByClass(pvClass);
if (lvMap == null) {
try {
lvMap = Converter.getAllSetterMethod(pvClass);
classPropertiesCacheSetter.addClassPropertiesMap(pvClass, lvMap);
} catch (IntrospectionException e) {
if (ServiceManager.DEBUG_MODE_ON) {
e.printStackTrace();
}
}
}
return lvMap;
}
/**
* Find all getter-method from a Class.
* @param pvClass Class to analyse.
* @return Map all getter-Method (key=property name, value=method).
* @throws IntrospectionException
*/
public static Map getAllGetterMethod(Class pvClass) throws IntrospectionException {
return getAllGetterAndSetterMethod(pvClass, GET_METHOD);
}
/**
* Find all setter-method from a Class.
* @param pvClass Class to analyse.
* @return Map all setter-Method (key=property name, value=method).
* @throws IntrospectionException
*/
public static Map getAllSetterMethod(Class pvClass) throws IntrospectionException {
return getAllGetterAndSetterMethod(pvClass, SET_METHOD);
}
/**
* Get all set/get methods from a Class. With methods from all super classes.
* @param pvClass Analyse Class.
* @return All finded methods.
*/
public static Method[] getAllMethodsByClass (Class pvClass) {
Collection lvColl = getAllMethodsByClassIntern(pvClass, new Hashtable());
return (Method[]) getAllMethodsByClassIntern(pvClass, new Hashtable()).toArray(new Method [lvColl.size()]);
}
/**
* Recursive search alle method from the Class in the Class Hierarchy to Object.class.
* @param pvClass Search class.
* @param pvMethodsMap Method map (key=property name, value=method).
* @return All finded methods.
*/
private static Collection getAllMethodsByClassIntern (Class pvClass, Map pvMethodsMap) {
putAllMethodsIntern( pvClass.getMethods(), pvMethodsMap) ;
putAllMethodsIntern( pvClass.getDeclaredMethods(), pvMethodsMap);
if (!(pvClass.getSuperclass().equals(Object.class))) {
getAllMethodsByClassIntern(pvClass.getSuperclass(), pvMethodsMap);
}
return pvMethodsMap.values();
}
private static void putAllMethodsIntern (Method pvAllMethods[], Map pvMethodsMap) {
for (int i = 0; i < pvAllMethods.length; i++) {
String lvMethodName = pvAllMethods[i].getName();
if (lvMethodName.startsWith("set") || lvMethodName.startsWith("get")) {
pvMethodsMap.put(pvAllMethods[i], pvAllMethods[i]);
}
}
}
/**
*
* @param pvClass Find all get or set method from a Class.
* @param pvMethodType get or set
* @return Method map (key=property name, value=method).
* @throws IntrospectionException
*/
public static Map getAllGetterAndSetterMethod(Class pvClass, int pvMethodType) throws IntrospectionException {
Method lvAllAmethods[] = getAllMethodsByClass(pvClass);
Map lvGetterOrSetter = new TreeMap();
for (int i = 0; i < lvAllAmethods.length; i++) {
Method lvMethod = null;
String lvPropName = lvAllAmethods[i].getName();
switch (pvMethodType) {
case GET_METHOD:
if (lvPropName.startsWith("get")) {
lvMethod = lvAllAmethods[i];
}
break;
case SET_METHOD:
if (lvPropName.startsWith("set")) {
lvMethod = lvAllAmethods[i];
}
break;
default:
break;
}
if (lvMethod != null) {
AccessController.doPrivileged(new MethodAccessiblePrivilegedAction(lvMethod));
lvPropName = lvPropName.substring(3);
// PropName muss aus set oder get UND einen Namen bestehen
if (lvPropName.length() > 0) {
lvPropName = lvPropName.substring(0, 1).toLowerCase()+ lvPropName.substring(1);
if (lvPropName.equals("class")) {
lvGetterOrSetter.put(lvPropName, pvClass.getName());
} else {
lvGetterOrSetter.put(lvPropName, lvMethod);
}
} else {
throw new InvocationException("Invalid Property-Name: '" + lvAllAmethods[i].getName()
+ "' (Valid Property-Name is: set[name] themed get[name], eg. setYear and getYear).");
}
} // if method != null
} // for
return lvGetterOrSetter;
}
public static Object createDefaultValueForPrimitiveClass(Class pvClass) {
Object lvReturn = null;
if (pvClass.equals(boolean.class)) { lvReturn = Boolean.FALSE; }
else if (pvClass.equals(short.class)) { lvReturn = Short.valueOf("0"); }
else if (pvClass.equals(byte.class)) { lvReturn = Byte.valueOf("0"); }
else if (pvClass.equals(int.class)) { lvReturn = Integer.valueOf("0"); }
else if (pvClass.equals(long.class)) { lvReturn = Long.valueOf("0"); }
else if (pvClass.equals(double.class)) { lvReturn = Double.valueOf("0"); }
else if (pvClass.equals(float.class)) { lvReturn = Float.valueOf("0"); }
else if (pvClass.equals(char.class)) { lvReturn = new Character(' '); }
return lvReturn;
}
private class SimpleKeyMapper implements Comparator {
public static final String DELIMITER = "~_-_~";
private String pos = null;
private Object key = null;
public SimpleKeyMapper() {}
public SimpleKeyMapper(String pvPos, Object pvKey) {
pos = pvPos;
key = pvKey;
}
public int getPos () {
Integer integer = Integer.valueOf(pos);
return integer.intValue();
}
public Object getKey() {
return key;
}
public Object toSimpleNewKey(final Object pvOldKey, final Class pvOldKeyClass, int pvPos, boolean pvWithSimpleKeyMapper) {
if (pvWithSimpleKeyMapper) {
String lvNewKey = null;
int l = pvOldKey.toString().split(DELIMITER).length;
if (l == 3 || l == 2) {
lvNewKey = pvOldKey.toString();
} else {
if (pvOldKeyClass.equals(String.class)) {
lvNewKey = pvPos + DELIMITER + pvOldKey;
} else {
lvNewKey = pvPos + DELIMITER + pvOldKey + DELIMITER + pvOldKeyClass.getName();
}
}
return lvNewKey;
} else {
return pvOldKey;
}
}
public Object toComplexNewKey(Object pvOriginalKey, boolean pvWithSimpleKeyMapper) {
if (pvWithSimpleKeyMapper == false) {
return pvOriginalKey;
} else {
Object lvKey = ((SimpleKeyMapper) pvOriginalKey).getKey();
return lvKey;
}
}
public Map orderMapByKey (final Map pvMap, boolean pvWithSimpleKeyMapper) throws Exception {
if (pvWithSimpleKeyMapper == false) {
return pvMap;
} else {
Iterator it = pvMap.keySet().iterator();
TreeMap lvTreeMap = new TreeMap(new SimpleKeyMapper());
while (it.hasNext()) {
Object o = it.next();
if ( ! (o instanceof String) ) {
throw new IllegalArgumentException("Expected String and object is: " + o + " -> class: " + o.getClass().getName());
}
String lvKeyStr = (String) o;
String lvKeyArray[] = lvKeyStr.split(DELIMITER);
if (lvKeyArray.length < 2) {
throw new IllegalArgumentException("If the property Converter.withSimpleKeyMappe is true, than must the key contains" +
" the delimiter: " + DELIMITER + " - " + lvKeyStr + " (" + lvKeyArray.length + ")");
}
Object lvValue = pvMap.get(lvKeyStr);
String lvPos = lvKeyArray[0];
String lvKeyValue = lvKeyArray[1];
Object lvKey = null;
if (lvKeyArray.length == 3) {
String lvKeyClass = lvKeyArray[2];
lvKey = Converter.convertString2Value(lvKeyValue, lvKeyClass);
} else {
lvKey = lvKeyValue;
}
SimpleKeyMapper skm = new SimpleKeyMapper(lvPos, lvKey);
lvTreeMap.put(skm, lvValue);
}
return lvTreeMap;
}
}
public int compare(Object pvO1, Object pvO2) {
SimpleKeyMapper skm1 = (SimpleKeyMapper) pvO1;
SimpleKeyMapper skm2 = (SimpleKeyMapper) pvO2;
if (skm1.getPos() > skm2.getPos()) {
return 1;
}
else {
return -1;
}
}
}
}
|