package com.activequant.domainmodel; import java.lang.reflect.Array; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.MappedSuperclass; import com.activequant.domainmodel.annotations.Property; @Entity @MappedSuperclass public abstract class PersistentEntity { @Column private String className; @Column private long creationTime = System.currentTimeMillis(); @Column private long deletionTime = 0L; @Column private long snapshotTime = 0L; private Map<String, Object> underlyingMap = new HashMap<String, Object>(); public PersistentEntity() { } protected void clearMap() { underlyingMap.clear(); } public PersistentEntity(String className) { this.className = className; } @Property public String getClassName() { return className; } @Property public long getCreationTime() { return creationTime; } @Property public long getDeletionTime() { return deletionTime; } public abstract String getId(); /** * * @return when this value was stored, in ordinary milliseconds. */ @Property public long getSnapshotTime() { return snapshotTime; } /** * very underdeveloped converter. * * @param targetType * @param input * @return */ public Object convertValueToType(Class<?> targetType, Object input) { if(input.getClass().isAssignableFrom(targetType)) return input; else if(targetType.isAssignableFrom(double.class) || targetType.isAssignableFrom(Double.class)){ if(input.getClass().isAssignableFrom(String.class)) return Double.parseDouble(input.toString()); } else if(targetType.isAssignableFrom(long.class) || targetType.isAssignableFrom(Long.class)){ if(input.getClass().isAssignableFrom(String.class)) return Long.parseLong(input.toString()); } else if(targetType.isAssignableFrom(int.class) || targetType.isAssignableFrom(Integer.class)){ if(input.getClass().isAssignableFrom(String.class)) return Integer.parseInt(input.toString()); if(input.getClass().isAssignableFrom(Long.class)){ return ((Long)input).intValue(); } } else if(targetType.isAssignableFrom(TimeStamp.class)){ return new TimeStamp((Long)input); } return input; } /** * * @param inMap * the incoming map will be cloned. */ public void initFromMap(Map<String, Object> inMap) { // clones the incoming map. underlyingMap = new HashMap<String, Object>(inMap); Method[] methods = this.getClass().getMethods(); Map<String, Method> methodMap = new HashMap<String, Method>(); for (Method m : methods) { if (m.getName().startsWith("get") && m.isAnnotationPresent(Property.class)) { String propertyName = m.getName().substring(3).toUpperCase(); if (underlyingMap.containsKey(propertyName)) { @SuppressWarnings("rawtypes") Class returnType = m.getReturnType(); // if(returnType.isArray())continue; Object value = underlyingMap.get(propertyName); try { Method setter = this.getClass().getMethod("set" + m.getName().substring(3), returnType); // only use values if they are not null and are thus, // present. if (value != null){ // Object convertedType = convertValueToType(returnType, value); // setter.invoke(this, convertedType); } } catch (Exception ex) { // drop the value. // log.warn("Could not set " + m.getName().substring(3) + " for value :" + value); } } } else if (m.getName().startsWith("set")) { String propertyName = m.getName().substring(3).toUpperCase(); methodMap.put(propertyName, m); } } // now iterate over the inMap to check for arrays. Iterator<Entry<String, Object>> entries = inMap.entrySet().iterator(); Map<String, Object[]> arrayMap = new HashMap<String, Object[]>(); while (entries.hasNext()) { Entry<String, Object> entry = entries.next(); if (entry.getKey().startsWith("[")) { String[] s = entry.getKey().split(";"); String key = s[0].substring(1); int position = Integer.valueOf(s[1]); int totalAmount = Integer.valueOf(s[2]); if (!arrayMap.containsKey(key)) { // have to finish this ...... Method setter = methodMap.get(key); @SuppressWarnings("rawtypes") Class[] params = setter.getParameterTypes(); if (params != null && params.length == 1) { // generate an array of this type. Object array = Array.newInstance(params[0].getComponentType(), totalAmount); // Object[] array = // params[0].getClass().newInstance()[totalAmount]; arrayMap.put(key, (Object[]) array); } } if (arrayMap.containsKey(key)) { Object[] array = arrayMap.get(key); array[position] = entry.getValue(); } } } // OK, all arrays initialized and temporarily stored. Iterator<Entry<String, Object[]>> arrayIter = arrayMap.entrySet().iterator(); while (arrayIter.hasNext()) { Entry<String, Object[]> entry = arrayIter.next(); // Method m = methodMap.get(entry.getKey()); if (m != null) { try { Object[] obj = entry.getValue(); m.invoke(this, new Object[] { obj }); } catch (Exception ex) { // drop the value. // log.warn("Could not set " + m.getName().substring(3) + " for value :" + entry.getValue()); ex.printStackTrace(); } } } // weeding out load time artifacts. Iterator<Entry<String, Object>> it = underlyingMap.entrySet().iterator(); List<String> weedOutKeys = new ArrayList<String>(); while(it.hasNext()){ Entry<String, Object> entry = it.next(); if(entry.getKey().startsWith("[")) weedOutKeys.add(entry.getKey()); } for(String s : weedOutKeys) underlyingMap.remove(s); } public String nullSafe(Object val) { if (val == null) return "<NA>"; String valString = val.toString(); // valString.replaceAll(" ", "_"); return valString; } public String nullSafeNoSpace(Object val) { if (val == null) return "<NA>"; String valString = val.toString(); valString.replaceAll(" ", "_"); return valString; } /** * recreates the entire property map and stores it in the underlying map. * use getUnderlyingMap() for consecutive calls. * * @return the underlying map */ public Map<String, Object> propertyMap() { // Method[] methods = this.getClass().getMethods(); for (Method m : methods) { if (m.getName().startsWith("get") && m.isAnnotationPresent(Property.class)) { try { String propertyName = m.getName().substring(3).toUpperCase(); Object value = m.invoke(this); underlyingMap.put(propertyName, value); } catch (Exception ex) { ex.printStackTrace(); } } } Map<String, Object> ret = new HashMap<String, Object>(underlyingMap); return ret; } public void setClassName(String className) { this.className = className; } public void setCreationTime(long creationTime) { this.creationTime = creationTime; } public void setDeletionTime(long deletionTime) { this.deletionTime = deletionTime; } public void setSnapshotTime(long snapshotTime) { this.snapshotTime = snapshotTime; } /** * Use this if you have called property map before and no properties changed in between. * * @return a map with all properties */ public Map<String, Object> getUnderlyingMap() { return underlyingMap; } }