You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
211 lines
7.5 KiB
211 lines
7.5 KiB
/* |
|
* 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<T extends MoumiEntity> extends JdbcDaoSupport implements MoumiDao<T> { |
|
|
|
private static Logger LOG = LoggerFactory.getLogger(MoumiJdbcDao.class); |
|
private AbstractClassMetaData metaData; |
|
private Set<String> dirtyFields = new HashSet<String>(2); |
|
private MetaDataManager metaDataManager; |
|
private ClassLoaderResolver classLoaderResolver; |
|
|
|
public AbstractClassMetaData getMetaData() { |
|
return metaData; |
|
} |
|
|
|
public Set<String> 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<T> c, PersistenceManagerFactory pmf) { |
|
OMFContext omfContext = new JDOPersistenceManagerFactory(pmf.getProperties()).getOMFContext(); |
|
this.metaDataManager = omfContext.getMetaDataManager(); |
|
this.classLoaderResolver = omfContext.getClassLoaderResolver(null); |
|
this.metaData = metaDataManager.getMetaDataForClass((Class<T>) c, classLoaderResolver); |
|
} |
|
|
|
private class MoumiRowMapper implements ParameterizedRowMapper<T> { |
|
|
|
private Class clazz; |
|
|
|
public <T extends MoumiEntity<Object>> MoumiRowMapper(Class<T> 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<T> c) { |
|
Properties props = getPmfProperties(); |
|
init(c, new JDOPersistenceManagerFactory(props)); |
|
} |
|
|
|
public MoumiJdbcDao(Class<T> c, PersistenceManagerFactory pmf) { |
|
init(c, pmf); |
|
} |
|
|
|
public T load(Class<T> 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<T> c, T pc) { |
|
if (dirtyFields.isEmpty()) |
|
return; |
|
|
|
List<Object> params = new ArrayList<Object>(); |
|
StringBuilder sql = new StringBuilder(100); |
|
|
|
sql.append("update ").append(this.metaData.getTable()).append(" set "); |
|
int i = 0; |
|
for (Iterator<String> 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()])); |
|
} |
|
}
|
|
|