/* * To change this template, choose Tools | Templates * and open the template in the editor. */ package kr.co.kihyun.spring; import java.io.IOException; import java.io.InputStream; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Properties; import java.util.Set; import java.util.logging.Level; import javax.jdo.PersistenceManagerFactory; import kr.co.kihyun.beans.entity.AssignType; import kr.co.kihyun.beans.entity.MoumiEntity; import kr.co.kihyun.beans.entity.TotDoc; import kr.co.kihyun.beans.entity.util.PMF; import kr.co.kihyun.moumi.MoumiConfig; import org.datanucleus.ClassLoaderResolver; import org.datanucleus.OMFContext; import org.datanucleus.jdo.JDOPersistenceManagerFactory; import org.datanucleus.metadata.AbstractClassMetaData; import org.datanucleus.metadata.AbstractMemberMetaData; import org.datanucleus.metadata.MetaDataManager; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.jdbc.core.simple.ParameterizedRowMapper; import org.springframework.jdbc.core.support.JdbcDaoSupport; /** * * @author bhs */ public class MoumiJdbcDao extends JdbcDaoSupport implements MoumiDao { private static Logger LOG = LoggerFactory.getLogger(MoumiJdbcDao.class); private AbstractClassMetaData metaData; private Set dirtyFields = new HashSet(2); private MetaDataManager metaDataManager; private ClassLoaderResolver classLoaderResolver; public AbstractClassMetaData getMetaData() { return metaData; } public Set getDirtyFields() { return Collections.unmodifiableSet(dirtyFields); } public void addDirtyField(String field) { this.dirtyFields.add(field); } private Properties getPmfProperties() { Properties result = new Properties(); InputStream stream = MoumiConfig.class.getResourceAsStream("/moumi-pmf.properties"); try { result.load(stream); return result; } catch (IOException e) { throw new RuntimeException("unable to read moumi-pmf.properties file."); } } private void init(Class c, PersistenceManagerFactory pmf) { OMFContext omfContext = new JDOPersistenceManagerFactory(pmf.getProperties()).getOMFContext(); this.metaDataManager = omfContext.getMetaDataManager(); this.classLoaderResolver = omfContext.getClassLoaderResolver(null); this.metaData = metaDataManager.getMetaDataForClass((Class) c, classLoaderResolver); } private class MoumiRowMapper implements ParameterizedRowMapper { private Class clazz; public > MoumiRowMapper(Class c) { this.clazz = c; } public T mapRow(ResultSet rs, int rownum) throws SQLException { T pc = null; try { pc = (T) clazz.newInstance(); } catch (Exception ex) { throw new RuntimeException("Could not instantiate class " + clazz.getSimpleName()); } int skipCount = 0; pc.setId(rs.getObject(1)); for (AbstractMemberMetaData member : MoumiJdbcDao.this.metaData.getManagedMembers()) { Field field = null; Object fieldValue = null; try { if (member.isRelationOwner(classLoaderResolver)) { field = clazz.getDeclaredField(member.getMemberRepresented().getName()); field.setAccessible(true); fieldValue = rs.getObject(member.getAbsoluteFieldNumber() - skipCount); if (field.getType().isEnum()) { int ordinal = ((Integer) fieldValue).intValue(); Object[] values = (Object[]) field.getType().getMethod("values").invoke(fieldValue); field.set(pc, field.getType().cast(values[ordinal])); } else if (MoumiEntity.class.isInstance(field.getType().newInstance())) { MoumiEntity e = (MoumiEntity) field.getType().newInstance(); e.setId((Long) fieldValue); TotDoc doc = (TotDoc) field.getType().cast(e); field.set(pc, field.getType().cast(e)); } else { field.set(pc, field.getType().cast(fieldValue)); } } else { skipCount++; } } catch (IllegalArgumentException ex) { throw new IllegalArgumentException(this.clazz.getSimpleName() + " is incompatible type or unwrapping conversion fails." + " field: " + member.getMemberRepresented().getName() + " field number: " + member.getAbsoluteFieldNumber() + " field value: " + fieldValue); } catch (IllegalAccessException ex) { throw new RuntimeException(member.getMemberRepresented().getName() + " field is set to be acceessable but could not access to this field.", ex); } catch (NoSuchFieldException ex) { throw new RuntimeException(member.getMemberRepresented().getName() + " is present at metadata but could not be found at class." + " It seems to be not enhanced.", ex); } catch (ClassCastException cce) { // throw new ClassCastException(cce.getMessage() + ": field '" + field.getName() + "'"); LOG.warn("{}: field '{}'", cce.getMessage(), field.getName()); } catch (Exception ex) { // throw new RuntimeException("Could not map row for field " // + member.getMemberRepresented().getName(), ex); LOG.warn("Could not map row for field '{}'", member.getMemberRepresented().getName()); } } return pc; } } public MoumiJdbcDao(Class c) { Properties props = getPmfProperties(); init(c, new JDOPersistenceManagerFactory(props)); } public MoumiJdbcDao(Class c, PersistenceManagerFactory pmf) { init(c, pmf); } public T load(Class c, Long id) { // TODO Apply fetch plan. return (T) this.getJdbcTemplate().queryForObject("select * from " + this.metaData.getTable() + " where id = ?", // return (T) this.getJdbcTemplate().queryForObject("select id from " + this.metaData.getTable() + " where id = ?", new Object[]{id}, new MoumiRowMapper(c)); } public void store(Class c, T pc) { if (dirtyFields.isEmpty()) return; List params = new ArrayList(); StringBuilder sql = new StringBuilder(100); sql.append("update ").append(this.metaData.getTable()).append(" set "); int i = 0; for (Iterator iter = dirtyFields.iterator(); iter.hasNext(); i++) { String dirtyField = iter.next(); if (this.metaData.getMetaDataForMember(dirtyField).getColumnMetaData()[0].getName() != null) { sql.append(this.metaData.getMetaDataForMember(dirtyField).getColumnMetaData()[0].getName()); } else { sql.append(dirtyField); } sql.append(" = ?"); try { Field field = c.getDeclaredField(dirtyField); field.setAccessible(true); if (field.get(pc) instanceof Enum) { params.add(((Enum) field.get(pc)).ordinal()); } else { params.add(field.get(pc)); } } catch (IllegalArgumentException ex) { throw new IllegalArgumentException(ex); } catch (IllegalAccessException ex) { throw new RuntimeException(ex); } catch (NoSuchFieldException ex) { throw new RuntimeException("Field " + dirtyField + " does not exists in class " + c.getSimpleName() + ". " + "Check addDirtyField(String field) method invocations."); } catch (SecurityException ex) { throw new SecurityException(ex); } if (i != dirtyFields.size() - 1) { sql.append(", "); } } sql.append(" where id = ?"); params.add(pc.getId()); LOG.debug(sql.toString().replaceAll("\\?", "{}"), params.toArray(new Object[params.size()])); this.getJdbcTemplate().update(sql.toString(), params.toArray(new Object[params.size()])); } }