package com.activequant.dao.mybatis; import java.lang.reflect.Array; 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 org.apache.ibatis.session.ExecutorType; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.log4j.Logger; import com.activequant.dao.mybatis.mapper.GenericRowMapper; import com.activequant.domainmodel.GenericRow; import com.activequant.domainmodel.PersistentEntity; import com.activequant.domainmodel.TimeStamp; import com.activequant.domainmodel.exceptions.DaoException; /** * * @author ustaudinger * * @param <T> */ public class GenericMapperDao<T extends PersistentEntity> { private Logger log = Logger.getLogger(GenericMapperDao.class); protected GenericRowMapper mapper; private String tableName; private Class<? extends PersistentEntity> clazz; private SqlSessionFactory sqlSessionFactory; public GenericMapperDao(SqlSessionFactory sqlSessionFactory, GenericRowMapper mapper, Class<? extends PersistentEntity> clazz, String table) { log.info("Initializing GenericDao for table " + table); this.tableName = table; this.sqlSessionFactory = sqlSessionFactory; this.mapper = mapper; this.clazz = clazz; // don't know how to check with ibatis if a table exists - at least not // in an easy w. // this one is easier, dirty and safe. // SqlSession sqlSession = sqlSessionFactory.openSession(); // sqlSession.select("SHOW INDEX FROM " + table, new ResultHandler(){ // @Override // public void handleResult(ResultContext arg0) { // System.out.println(arg0); // }}); // sqlSession.close(); try { mapper.init(table); mapper.genIndex1(table); mapper.genIndex2(table); mapper.genIndex3(table); mapper.genIndex4(table); mapper.genIndex5(table); mapper.genIndex6(table); mapper.genIndex7(table); mapper.genIndex8(table); mapper.genKey9(table); } catch (Exception ex) { log.debug("Error creating table, possibly it exists already. " + ex.getStackTrace()[0]); } } public Map<String, Object> loadRaw(String primaryKey) { List<GenericRow> rows = mapper.load(tableName, primaryKey); // to be offloaded to a generic class. Map<String, Object> map = new HashMap<String, Object>(); for (GenericRow row : rows) { String fieldName = row.getFieldName(); if (row.getDoubleVal() != null) map.put(fieldName, row.getDoubleVal()); else if (row.getLongVal() != null) map.put(fieldName, row.getLongVal()); else if (row.getStringVal() != null) map.put(fieldName, row.getStringVal()); } return map; } /** * * @param rawMap */ public void storeRaw(String id, Map<String, Object> rawMap){ List<GenericRow> rows = new ArrayList<GenericRow>(); Iterator<Entry<String, Object>> iterator = rawMap.entrySet().iterator(); long created = System.currentTimeMillis(); while(iterator.hasNext()){ Entry<String, Object> entry = iterator.next(); GenericRow gr = genRow(created, id, entry.getKey(), entry.getValue()); // rows.add(gr); } SqlSession sqlSession = sqlSessionFactory .openSession(ExecutorType.BATCH); try { mapper.delete(tableName, id); for (GenericRow row : rows) { mapper.insert(tableName, row); } sqlSession.commit(); } finally { sqlSession.close(); } } // @SuppressWarnings("unchecked") public T load(String primaryKey) { List<GenericRow> rows = mapper.load(tableName, primaryKey); // to be offloaded to a generic class. Map<String, Object> map = new HashMap<String, Object>(); for (GenericRow row : rows) { String fieldName = row.getFieldName(); if (row.getDoubleVal() != null) map.put(fieldName, row.getDoubleVal()); else if (row.getLongVal() != null) map.put(fieldName, row.getLongVal()); else if (row.getStringVal() != null) map.put(fieldName, row.getStringVal()); } String className = (String) map.get("ClassName".toUpperCase()); if (className == null) // no valid entry. return null; T ret = null; try { @SuppressWarnings({ "rawtypes" }) Class clazz = Class.forName(className); ret = (T) clazz.newInstance(); ret.initFromMap(map); } catch (Exception e) { e.printStackTrace(); } return ret; } /** * First sentence: Use with care. This will load ALL object instances from * DB, which could possibly become a very large table. * * TODO: find another way to load things, this is too slow. * * @return array of ALL instances in persistence layer. */ @SuppressWarnings("unchecked") public T[] loadAll() { List<String> iids = mapper.loadKeyList(tableName); T[] ret = (T[]) Array.newInstance(clazz, iids.size()); for (int i = 0; i < iids.size(); i++) { ret[i] = load(iids.get(i)); } return ret; } public synchronized void delete(T t) { mapper.delete(tableName, t.getId()); } public synchronized void deleteById(String id) { mapper.delete(tableName, id); } public synchronized void update(T t) { this.delete(t); this.create(t); } public String[] findIDsWhereCreationDateBetween(TimeStamp startTs, TimeStamp endTs) { List<String> ids = mapper.findIDsBetween(tableName, startTs.getMilliseconds(), endTs.getMilliseconds()); return ids.toArray(new String[] {}); } /** * Use this function to load all IDs * * @return a list of all Key-IDs in this set. * */ public String[] loadIDs() { List<String> iids = mapper.loadKeyList(tableName); return iids.toArray(new String[] {}); } public String[] findIdsLike(String pattern) throws DaoException { List<String> ret = mapper.findIdsLike(tableName, pattern, Integer.MAX_VALUE); return ret.toArray(new String[] {}); } private GenericRow genRow(long createdTimeStamp, String id, String key, Object value) { GenericRow gr = null; if (value instanceof Double) { gr = new GenericRow(createdTimeStamp, id, key, null, (Double) value, null); } else if (value instanceof String) { gr = new GenericRow(createdTimeStamp, id, key, null, null, (String) value); } else if (value instanceof Integer) { gr = new GenericRow(createdTimeStamp, id, key, ((Integer) value).longValue(), null, null); } else if (value instanceof Long) { gr = new GenericRow(createdTimeStamp, id, key, (Long) value, null, null); } return gr; } private List<GenericRow> createGenRows(T t) { List<GenericRow> ret = new ArrayList<GenericRow>(); // TODO Auto-generated method stub Map<String, Object> map = t.propertyMap(); Iterator<String> it = map.keySet().iterator(); while (it.hasNext()) { boolean added = false; String key = it.next(); Object value = map.get(key); if (value == null) continue; GenericRow gr = null; long createdTimeStamp = t.getCreationTime(); if (value instanceof Object[]) { // generate individual generic rows for all entries of this // array. Object[] array = (Object[]) value; int totalLength = array.length; for (int i = 0; i < totalLength; i++) { String fieldName = "[" + key + ";" + i + ";" + totalLength; GenericRow temp = genRow(createdTimeStamp, t.getId(), fieldName, array[i]); ret.add(temp); added = true; } } else gr = genRow(createdTimeStamp, t.getId(), key, value); if (gr != null) ret.add(gr); else if (!added) log.warn("NO VALUE CONVERTER FOR VALUE: " + key + "/ " + value); } return ret; } public void create(T t) { SqlSession sqlSession = sqlSessionFactory .openSession(ExecutorType.BATCH); try { List<GenericRow> rows = createGenRows(t); for (GenericRow row : rows) { mapper.insert(tableName, row); } sqlSession.commit(); } finally { sqlSession.close(); } } public String[] findIDs(String key, String sValue) { List<String> ret = mapper.findByString(tableName, key, sValue); return ret.toArray(new String[] {}); } public String[] findIDsWhereLongValGreater(String fieldName, long sValue) { List<String> ret = mapper.findIDsWhereLongValGreater(tableName, fieldName, sValue); return ret.toArray(new String[] {}); } public String[] findIDsWhereLongValBetween(String fieldName, long minValue, long maxValue) { List<String> ret = mapper.findIDsWhereLongValBetween(tableName, fieldName, minValue, maxValue); return ret.toArray(new String[] {}); } public String[] findIDs(String key, Double dValue) { List<String> ret = mapper.findByDouble(tableName, key, dValue); return ret.toArray(new String[] {}); } public String[] findIDs(String key, Long lValue) { List<String> ret = mapper.findByLong(tableName, key, lValue); return ret.toArray(new String[] {}); } public String[] findIDs(int startIndex, int endIndex) { List<String> ret = mapper.findIDs(tableName, startIndex, endIndex); return ret.toArray(new String[] {}); } public String[] findIDsLike(String idsLikeString, int resultAmount) { List<String> ret = mapper.findIdsLike(tableName, idsLikeString, resultAmount); return ret.toArray(new String[] {}); } public int count() { return mapper.count(tableName); } public int countForAttributeValue(String key, String value) { return mapper.countForStringValue(tableName, key, value); } public int countForAttributeValue(String key, Double value) { return mapper.countForDoubleValue(tableName, key, value); } public int countForAttributeValue(String key, Long value) { return mapper.countForLongValue(tableName, key, value); } public String[] selectDistinctStringVal(String val) { List<String> ret = mapper.selectDistinctStringVal(tableName, val); return ret.toArray(new String[] {}); } public Long[] selectDistinctLongVal(String val) { List<Long> ret = mapper.selectDistinctLongVal(tableName, val); return ret.toArray(new Long[] {}); } public Double[] selectDistinctDoubleVal(String val) { List<Double> ret = mapper.selectDistinctDoubleVal(tableName, val); return ret.toArray(new Double[] {}); } public List<String> findIDsBetweenCreationTime(String parameter, String value, Long fromTimeStampInMs, Long toMs) { List<String> ids = mapper.findIDsBetweenCreationTime(tableName, parameter, value, fromTimeStampInMs, toMs); return ids; } public String findLastIdBeforeCreationTime(String parameter, String value, Long timeStampInMs) { return mapper.findLastIdBeforeCreationTime(tableName, parameter, value, timeStampInMs); } }