/*
* JEF - Copyright 2009-2010 Jiyi (mr.jiyi@gmail.com)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package jef.database.jpa;
import java.sql.SQLException;
import java.sql.Savepoint;
import java.util.List;
import java.util.Map;
import javax.persistence.EntityGraph;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.FlushModeType;
import javax.persistence.LockModeType;
import javax.persistence.PersistenceException;
import javax.persistence.Query;
import javax.persistence.StoredProcedureQuery;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaDelete;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.CriteriaUpdate;
import javax.persistence.metamodel.Metamodel;
import jef.common.log.LogUtil;
import jef.database.DbClient;
import jef.database.DbUtils;
import jef.database.Field;
import jef.database.IQueryableEntity;
import jef.database.PojoWrapper;
import jef.database.Session;
import jef.database.TransactionalSession;
import jef.database.meta.ITableMetadata;
import jef.database.meta.MetaHolder;
import jef.database.support.SavepointNotSupportedException;
import jef.database.support.TransactionTimedOutException;
import jef.tools.reflect.BeanUtils;
/**
* JPA接口 EntityManager 的JEF实现类
*
* @author Administrator
*
*/
@SuppressWarnings("rawtypes")
public class JefEntityManager implements EntityManager {
private boolean close;
JefEntityManagerFactory parent;
JefEntityTransaction tx;
private Map properties;
private FlushModeType mode = FlushModeType.AUTO;
/**
* 构造
*
* @param parent
* @param properties
*/
public JefEntityManager(EntityManagerFactory parent, Map properties) {
this.parent = (JefEntityManagerFactory) parent;
this.properties = properties;
}
public JefEntityManager(EntityManagerFactory parent, Map properties, TransactionalSession session) {
this.parent = (JefEntityManagerFactory) parent;
this.properties = properties;
this.tx = new JefEntityTransaction(this, session);
}
public void persist(Object entity) {
if (entity instanceof IQueryableEntity) {
doMerge((IQueryableEntity) entity, false);
} else {
ITableMetadata meta = MetaHolder.getMeta(entity.getClass());
PojoWrapper wrapper = meta.transfer(entity, false);
doMerge(wrapper, false);
}
}
@SuppressWarnings("unchecked")
public <T> T merge(T entity) {
if (entity instanceof IQueryableEntity) {
return (T) doMerge((IQueryableEntity) entity, false);
} else {
ITableMetadata meta = MetaHolder.getMeta(entity.getClass());
PojoWrapper wrapper = meta.transfer(entity, false);
wrapper = doMerge(wrapper, false);
return (T) wrapper.get();
}
}
@SuppressWarnings("unchecked")
public <T> T mergeCascade(T entity) {
if (entity instanceof IQueryableEntity) {
return (T) doMerge((IQueryableEntity) entity, true);
} else {
ITableMetadata meta = MetaHolder.getMeta(entity.getClass());
PojoWrapper wrapper = meta.transfer(entity, false);
wrapper = doMerge(wrapper, true);
return (T) wrapper.get();
}
}
public void remove(Object entity) {
try {
if (entity instanceof IQueryableEntity) {
IQueryableEntity data = (IQueryableEntity) entity;
getSession().deleteCascade(data);
} else {
ITableMetadata meta = MetaHolder.getMeta(entity.getClass());
PojoWrapper wrapper = meta.transfer(entity, true);
getSession().deleteCascade(wrapper);
}
} catch (SQLException e) {
throw new PersistenceException(e.getMessage() + " " + e.getSQLState(), e);
}
}
@SuppressWarnings("unchecked")
public <T> T find(Class<T> entityClass, Object primaryKey) {
if (primaryKey == null)
return null;
try {
Object obj = entityClass.newInstance();
if (obj instanceof IQueryableEntity) {
IQueryableEntity data = (IQueryableEntity) obj;
DbUtils.setPrimaryKeyValue(data, primaryKey);
return (T) getSession().load(data,true);
} else {
ITableMetadata meta = MetaHolder.getMeta(entityClass);
PojoWrapper data = meta.transfer(obj, false);
DbUtils.setPrimaryKeyValue(data, primaryKey);
data = getSession().load(data,true);
return data == null ? null : (T) data.get();
}
} catch (SQLException e) {
throw new PersistenceException(e.getMessage() + " " + e.getSQLState(), e);
} catch (InstantiationException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
/**
* 根据主键和其他属性查找
*/
@SuppressWarnings("unchecked")
public <T> T find(Class<T> entityClass, Object primaryKey, Map<String, Object> properties) {
try {
IQueryableEntity data = (IQueryableEntity) entityClass.newInstance();
if (primaryKey != null) {
DbUtils.setPrimaryKeyValue(data, primaryKey);
} else if (properties != null && properties.size() > 0) {
for (String s : properties.keySet()) {
Field f = MetaHolder.getMeta(data).getField(s);
if (f == null) {
LogUtil.error("No Field named " + s + " in bean " + data.getClass().getName());
continue;
}
data.getQuery().addCondition(f, properties.get(s));
}
} else {
data.getQuery().setAllRecordsCondition();
}
return (T) getSession().load(data,true);
} catch (SQLException e) {
throw new PersistenceException(e.getMessage() + " " + e.getSQLState(), e);
} catch (InstantiationException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
public <T> T find(Class<T> entityClass, Object primaryKey, LockModeType lockMode) {
return find(entityClass, primaryKey);
}
/**
* 根据主键和其他属性查找
*/
public <T> T find(Class<T> entityClass, Object primaryKey, LockModeType lockMode, Map<String, Object> properties) {
return find(entityClass, primaryKey, properties);
}
@SuppressWarnings("unchecked")
public <T> T getReference(Class<T> entityClass, Object primaryKey) {
try {
IQueryableEntity data = (IQueryableEntity) entityClass.newInstance();
DbUtils.setPrimaryKeyValue(data, primaryKey);
List<IQueryableEntity> list = getSession().select(data);
if (list.isEmpty())
return null;
return (T) list.get(0);
} catch (SQLException e) {
throw new PersistenceException(e.getMessage() + " " + e.getSQLState(), e);
} catch (InstantiationException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
public void flush() {
}
public void setFlushMode(FlushModeType flushMode) {
this.mode = flushMode;
}
public FlushModeType getFlushMode() {
return mode;
}
public void lock(Object entity, LockModeType lockMode) {
}
public void lock(Object entity, LockModeType lockMode, Map<String, Object> properties) {
}
public void refresh(Object entity) {
if (entity instanceof IQueryableEntity) {
try {
IQueryableEntity newObj = this.getSession().load((IQueryableEntity) entity,true);
newObj.stopUpdate();
BeanUtils.copyProperties(newObj, entity);
} catch (SQLException e) {
throw new PersistenceException(e);
}
}
}
public void refresh(Object entity, Map<String, Object> properties) {
if (entity instanceof IQueryableEntity) {
try {
IQueryableEntity newObj = this.getSession().load((IQueryableEntity) entity,true);
newObj.stopUpdate();
BeanUtils.copyProperties(newObj, entity);
} catch (SQLException e) {
throw new PersistenceException(e);
}
}
}
public void refresh(Object entity, LockModeType lockMode) {
refresh(entity);
}
public void refresh(Object entity, LockModeType lockMode, Map<String, Object> properties) {
refresh(entity);
}
public void clear() {
getSession().evictAll();
}
public void detach(Object entity) {
getSession().evict((IQueryableEntity) entity);
}
public boolean contains(Object entity) {
if (entity instanceof IQueryableEntity) {
try {
IQueryableEntity newObj = this.getSession().load((IQueryableEntity) entity,true);
return newObj != null;
} catch (SQLException e) {
throw new PersistenceException(e);
}
}
return false;
}
public LockModeType getLockMode(Object entity) {
return LockModeType.NONE;
}
@SuppressWarnings("unchecked")
public void setProperty(String propertyName, Object value) {
properties.put(propertyName, value);
}
@SuppressWarnings("unchecked")
public Map<String, Object> getProperties() {
return properties;
}
public Query createQuery(String qlString) {
return getSession().createQuery(qlString);
}
public <T> TypedQuery<T> createQuery(CriteriaQuery<T> criteriaQuery) {
throw new UnsupportedOperationException();
}
public <T> TypedQuery<T> createQuery(String qlString, Class<T> resultClass) {
return getSession().createQuery(qlString, resultClass);
}
public Query createNamedQuery(String name) {
return getSession().createNamedQuery(name);
}
public <T> TypedQuery<T> createNamedQuery(String name, Class<T> resultClass) {
return getSession().createNamedQuery(name, resultClass);
}
public Query createNativeQuery(String sqlString) {
return getSession().createNativeQuery(sqlString);
}
@SuppressWarnings("unchecked")
public Query createNativeQuery(String sqlString, Class resultClass) {
return getSession().createNativeQuery(sqlString, resultClass);
}
/*
*/
public Query createNativeQuery(String sqlString, String resultSetMapping) {
throw new UnsupportedOperationException();
}
/*
*/
public void joinTransaction() {
if (tx == null || !tx.isActive()) {
throw new TransactionTimedOutException("No transaction to join.");
}
}
@SuppressWarnings("unchecked")
public <T> T unwrap(Class<T> cls) {
return (T) getSession();
}
public Object getDelegate() {
return this;
}
public void close() {
if (tx != null && tx.isActive()) {
throw new TransactionTimedOutException("Tx was not closed while em closing");
}
tx = null;
close = true;
parent = null;
}
public boolean isOpen() {
return !close;
}
public EntityManagerFactory getEntityManagerFactory() {
return parent;
}
public CriteriaBuilder getCriteriaBuilder() {
return parent.getCriteriaBuilder();
}
/*
* (non-Javadoc)
*
* @see javax.persistence.EntityManager#getMetamodel()
*/
public Metamodel getMetamodel() {
throw new UnsupportedOperationException();
}
/*
* JPA标准接口(non-Javadoc)
*
* @see javax.persistence.EntityManager#getTransaction()
*/
public JefEntityTransaction getTransaction() {
if (tx == null) {
tx = new JefEntityTransaction(this);
}
return tx;
}
/**
* 设置保存点
*
* @param savepointName
* @throws SavepointNotSupportedException
*/
public Savepoint setSavepoint(String savepointName) throws SavepointNotSupportedException {
if (tx != null) {
try {
return tx.get().setSavepoint(savepointName);
} catch (SQLException e) {
throw new PersistenceException(e.getMessage() + " " + e.getSQLState(), e);
}
}
return null;
}
/**
* 回滚到保存点
*
* @param savepoint
* @throws SavepointNotSupportedException
*/
public void rollbackToSavepoint(Savepoint savepoint) throws SavepointNotSupportedException {
if (tx != null) {
try {
tx.get().rollbackToSavepoint(savepoint);
} catch (SQLException e) {
throw new PersistenceException(e.getMessage() + " " + e.getSQLState(), e);
}
}
}
/**
* 释放保存点
*
* @param savepoint
*/
public void releaseSavepoint(Savepoint savepoint) {
if (tx != null) {
try {
tx.get().releaseSavepoint(savepoint);
} catch (SQLException e) {
throw DbUtils.toRuntimeException(e);
}
}
}
private <T extends IQueryableEntity> T doMerge(T entity, boolean flag) {
try {
if (flag) {
return getSession().mergeCascade(entity);
} else {
return getSession().merge(entity);
}
} catch (SQLException e) {
throw DbUtils.toRuntimeException(e);
}
}
/**
* get the current databa sesession.
*
* @return
*/
public Session getSession() {
if (close)
throw new RuntimeException("the " + this.toString() + " has been closed!");
if (tx != null && tx.isActive()) {
return (Session) tx.get();
} else {
return parent.getDefault();
}
}
@Override
public Query createQuery(CriteriaUpdate updateQuery) {
throw new UnsupportedOperationException();
}
@Override
public Query createQuery(CriteriaDelete deleteQuery) {
throw new UnsupportedOperationException();
}
@Override
public StoredProcedureQuery createNamedStoredProcedureQuery(String name) {
throw new UnsupportedOperationException();
}
@Override
public StoredProcedureQuery createStoredProcedureQuery(String procedureName) {
throw new UnsupportedOperationException();
}
@Override
public StoredProcedureQuery createStoredProcedureQuery(String procedureName, Class... resultClasses) {
throw new UnsupportedOperationException();
}
@Override
public StoredProcedureQuery createStoredProcedureQuery(String procedureName, String... resultSetMappings) {
throw new UnsupportedOperationException();
}
@Override
public boolean isJoinedToTransaction() {
return false;
}
@Override
public <T> EntityGraph<T> createEntityGraph(Class<T> rootType) {
throw new UnsupportedOperationException();
}
@Override
public EntityGraph<?> createEntityGraph(String graphName) {
throw new UnsupportedOperationException();
}
@Override
public EntityGraph<?> getEntityGraph(String graphName) {
throw new UnsupportedOperationException();
}
@Override
public <T> List<EntityGraph<? super T>> getEntityGraphs(Class<T> entityClass) {
throw new UnsupportedOperationException();
}
public MetaProvider getMetadataModel(){
return parent;
}
public DbClient getDbClient(){
if (close)
throw new RuntimeException("the " + this.toString() + " has been closed!");
return parent.getDefault();
}
}