/**
*
* Copyright 2014 The Darks ORM Project (Liu lihua)
*
* 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 darks.orm.core.session;
import java.io.Serializable;
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Savepoint;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import darks.orm.annotation.Id.FeedBackKeyType;
import darks.orm.annotation.Id.GenerateKeyType;
import darks.orm.app.Page;
import darks.orm.app.SqlSession;
import darks.orm.core.cache.CacheContext;
import darks.orm.core.config.ResultSetConfig;
import darks.orm.core.data.FieldData;
import darks.orm.core.data.PrimaryKeyData;
import darks.orm.core.factory.ClassFactory;
import darks.orm.core.factory.TransformFactory;
import darks.orm.datasource.Transaction;
import darks.orm.datasource.factory.ConnectionFactory;
import darks.orm.datasource.factory.StatementFactory.StatementType;
import darks.orm.datasource.factory.TransactionFactory;
import darks.orm.exceptions.PersistenceException;
import darks.orm.exceptions.SessionException;
import darks.orm.log.Logger;
import darks.orm.log.LoggerFactory;
import darks.orm.util.DataTypeHelper;
import darks.orm.util.JdbcHelper;
import darks.orm.util.ReflectHelper;
/**
*
*
* <p>
* <h1>SessionSupport.java</h1>
* <p>
*
* @author Liu LiHua
* @version 1.0.0 v05/03/2012
* @since JDK1.5
*/
public abstract class SessionSupport implements Serializable, SqlSession
{
private static final Logger logger = LoggerFactory.getLogger(SessionSupport.class);
private static final long serialVersionUID = 9127842587231565250L;
private static ConcurrentMap<String, String> getMap = new ConcurrentHashMap<String, String>();
private static ConcurrentMap<String, String> deleteMap = new ConcurrentHashMap<String, String>();
// �Ƿ��Զ���������
private Transaction tx;
private StatementType stmtType;
private volatile boolean inited = false;
public SessionSupport()
{
}
/**
* Initialize sql session
*/
private void initialize()
{
if (!inited || tx == null)
{
tx = TransactionFactory.getTransaction();
ResultSetConfig cfg = ConnectionFactory.getInstance().getCurrentResultSetConfig();
if (cfg != null)
{
stmtType = cfg.getStatementType();
}
else
{
stmtType = StatementType.Scorllable;
}
inited = true;
}
}
/**
* {@inheritDoc}
*/
public boolean isInited()
{
return inited;
}
/**
* {@inheritDoc}
*/
public Connection getConnection()
{
return tx.getConnection();
}
/**
* {@inheritDoc}
*/
public Connection getConnection(boolean isCreate)
{
return tx.getConnection(isCreate);
}
/**
* {@inheritDoc}
*/
public void setConnection(Connection conn)
{
tx.setConnection(conn);
}
/**
* {@inheritDoc}
*/
public void close()
{
if (tx == null)
return;
tx.close();
}
/**
* {@inheritDoc}
*/
public void shutDown()
{
close();
SessionContext.destroy();
}
/**
* {@inheritDoc}
*/
public boolean isClosed()
{
if (tx == null)
return true;
return tx.isClosed();
}
/**
* {@inheritDoc}
*/
public int executeField(String sql, Object... params)
{
ResultSet rs = executeQuery(sql, params);
int num = 0;
try
{
if (rs.next())
{
num = rs.getInt(1);
}
}
catch (SQLException e)
{
throw new SessionException(e.getMessage(), e);
}
finally
{
JdbcHelper.closeResultSet(rs);
}
return num;
}
/**
* {@inheritDoc}
*/
public ResultSet executeQuery(String sql, Object... param)
{
return executeQuery(sql, param, null);
}
/**
* {@inheritDoc}
*/
public ResultSet executeQuery(String sql, Object param[], StatementType stateType)
throws SessionException
{
sql = sql.toLowerCase();
logger.debug("[SQL]" + sql);
PreparedStatement pstmt = null;
initialize();
try
{
if (stateType != null)
pstmt = tx.getPreparedStatement(sql, stateType);
else
pstmt = tx.getPreparedStatement(sql);
if (param != null)
{
for (int i = 0; i < param.length; i++)
{
pstmt.setObject(i + 1, param[i]);
}
}
return pstmt.executeQuery();
}
catch (SQLException e)
{
throw new SessionException(e);
}
}
/**
* {@inheritDoc}
*/
public CallableStatement prepareCall(String sql)
{
initialize();
return tx.getCallableStatement(sql);
}
/**
* {@inheritDoc}
*/
public <T> List<T> queryList(Class<T> c, String sql, Object... params)
{
initialize();
ResultSet rs = null;
try
{
rs = executeQuery(sql, params);
if (rs == null)
return null;
return TransformFactory.getInstance().ResultToList(c, sql, rs);
}
catch (Exception e)
{
throw new SessionException(e.getMessage(), e);
}
finally
{
JdbcHelper.closeResultSet(rs);
}
}
/**
* {@inheritDoc}
*/
public <T> List<T> queryList(Class<T> c, ResultSet rs, String sql)
{
try
{
initialize();
if (rs == null)
return null;
logger.debug("[SQL]" + sql);
return TransformFactory.getInstance().ResultToList(c, sql, rs);
}
catch (Exception e)
{
throw new SessionException(e.getMessage(), e);
}
}
/**
* {@inheritDoc}
*/
public <T> T queryCascadeObject(Class<T> c, String sql, String[] entityName, String[] alias, Object... param)
{
ResultSet rs = null;
Map<String, String> map = new HashMap<String, String>();
StringBuffer buf = new StringBuffer("[MAP]");
if (entityName != null && alias != null)
{
if (entityName.length != alias.length)
return null;
for (int i = 0; i < entityName.length; i++)
{
map.put(entityName[i], alias[i]);
buf.append(entityName[i]);
buf.append("#");
buf.append(alias[i]);
buf.append("@");
}
}
try
{
initialize();
sql = TransformFactory.getInstance().transformSQLToCascade(sql, c, map, buf);
rs = executeQuery(sql, param);
if (rs == null)
return null;
return TransformFactory.getInstance().cascadeResultToBean(c, sql, rs, map, true);
}
catch (Exception e)
{
throw new SessionException(e.getMessage(), e);
}
finally
{
JdbcHelper.closeResultSet(rs);
}
}
/**
* {@inheritDoc}
*/
public <T> List<T> queryCascadeList(Class<T> c, String sql, String[] entityName, String[] alias, Object... param)
{
ResultSet rs = null;
Map<String, String> map = new HashMap<String, String>();
StringBuffer buf = new StringBuffer("[MAP]");
if (entityName != null && alias != null)
{
if (entityName.length != alias.length)
return null;
for (int i = 0; i < entityName.length; i++)
{
map.put(entityName[i], alias[i]);
buf.append(entityName[i]);
buf.append("#");
buf.append(alias[i]);
buf.append("@");
}
}
try
{
initialize();
sql = TransformFactory.getInstance().transformSQLToCascade(sql, c, map, buf);
rs = executeQuery(sql, param);
if (rs == null)
return null;
return TransformFactory.getInstance().cascadeResultToList(c, sql, rs, map);
}
catch (Exception e)
{
throw new SessionException(e.getMessage(), e);
}
finally
{
JdbcHelper.closeResultSet(rs);
}
}
/**
* {@inheritDoc}
*/
public <T> Page<T> queryCascadePageList(Class<T> c, String sql, int page, int pageSize, String[] entityName,
String[] alias, Object... param)
{
ResultSet rs = null;
Map<String, String> map = new HashMap<String, String>();
StringBuffer buf = new StringBuffer("[MAP]");
if (entityName != null && alias != null)
{
if (entityName.length != alias.length)
return null;
for (int i = 0; i < entityName.length; i++)
{
map.put(entityName[i], alias[i]);
buf.append(entityName[i]);
buf.append("#");
buf.append(alias[i]);
buf.append("@");
}
}
try
{
initialize();
sql = TransformFactory.getInstance().transformSQLToCascade(sql, c, map, buf);
rs = executeQuery(sql, param);
if (rs == null)
return null;
List<T> list = null;
rs.last();
int count = rs.getRow();
rs.beforeFirst();
if (count > 0)
{
list = TransformFactory.getInstance().cascadeResultToPage(c, sql, rs, page, pageSize, map);
}
else
{
list = new ArrayList<T>();
}
return new Page<T>(list, count);
}
catch (Exception e)
{
throw new SessionException(e.getMessage(), e);
}
finally
{
JdbcHelper.closeResultSet(rs);
}
}
/**
* {@inheritDoc}
*/
public <T> T queryById(Class<T> c, int id)
{
String sql = null;
if (getMap.containsKey(c.getName()))
{
sql = getMap.get(c.getName());
}
else
{
try
{
sql = PersistSqlBuilder.buildGetSql(c, id);
}
catch (ClassNotFoundException e)
{
throw new SessionException("SessionSupport::queryById ClassNotFoundException " + e.toString(), e);
}
getMap.put(c.getName(), sql);
}
initialize();
ResultSet rs = executeQuery(sql, id);
if (rs == null)
return null;
try
{
return TransformFactory.getInstance().ResultToBean(c, sql, rs, true);
}
catch (Exception e)
{
throw new SessionException("SessionSupport::queryById " + e.toString(), e);
}
finally
{
JdbcHelper.closeResultSet(rs);
}
}
/**
* {@inheritDoc}
*/
public <T> T queryBySQL(Class<T> c, String sql, Object... param)
{
initialize();
ResultSet rs = executeQuery(sql, param);
if (rs == null)
return null;
try
{
return TransformFactory.getInstance().ResultToBean(c, sql, rs, true);
}
catch (Exception e)
{
throw new SessionException("SessionSupport::queryBySQL " + e.toString(), e);
}
finally
{
JdbcHelper.closeResultSet(rs);
}
}
/**
* {@inheritDoc}
*/
public <T> T queryBySQL(Class<T> c, ResultSet rs, String sql)
{
initialize();
if (rs == null)
return null;
logger.debug("[SQL]" + sql);
try
{
return TransformFactory.getInstance().ResultToBean(c, sql, rs, true);
}
catch (Exception e)
{
throw new SessionException("queryBySQL " + e.toString(), e);
}
}
/**
* {@inheritDoc}
*/
public <T> Page<T> queryPageList(Class<T> c, String sql, int page, int pageSize, Object... param)
{
ResultSet rs = null;
initialize();
try
{
rs = executeQuery(sql, param);
if (rs == null)
return null;
int count = 0;
List<T> list = null;
if (stmtType == StatementType.Scorllable)
{
rs.last();
count = rs.getRow();
rs.beforeFirst();
if (count > 0)
{
list = TransformFactory.getInstance().ResultToPageScroll(c, sql, rs, page, pageSize);
}
else
{
list = new ArrayList<T>();
}
}
else
{
String countsql = TransformFactory.getInstance().transformSqlToCount(sql);
count = executeField(countsql, param);
if (count > 0)
{
list = TransformFactory.getInstance().ResultToPageForward(c, sql, rs, page, pageSize);
}
else
{
list = new ArrayList<T>();
}
}
return new Page<T>(list, count);
}
catch (Exception e)
{
throw new SessionException("SessionSupport::queryPageList " + e.toString(), e);
}
finally
{
JdbcHelper.closeResultSet(rs);
}
}
/**
* {@inheritDoc}
*/
public <T> int save(T entity)
throws SQLException
{
return (Integer)save(entity, false);
}
/**
* {@inheritDoc}
*/
@SuppressWarnings("unchecked")
public <T> Object save(T entity, boolean isReturnPk)
throws SQLException
{
initialize();
Class<T> c = null;
if (entity == null)
{
throw new PersistenceException("the entity saved is null");
}
else
{
c = (Class<T>)entity.getClass();
}
String tn = ClassFactory.getTableName(c);
if (tn == null)
return -1;
FieldData fdata = ClassFactory.getPrimaryKey(c);
PrimaryKeyData pkdata = fdata.getPkData();
Class<?> pkClass = fdata.getFieldClass();
Object pkval = fdata.getValue(entity);
boolean isNull = DataTypeHelper.checkValueIsNull(pkClass, pkval);
if (isNull)
{
if (pkdata.getType() == GenerateKeyType.SELECT)
{
String sql = pkdata.getSelect();
ResultSet rs = executeQuery(sql, null, StatementType.Normal);
if (rs != null && rs.next())
{
pkval = ReflectHelper.getResultSetValue(rs, pkClass, 1);
rs.close();
}
isNull = DataTypeHelper.checkValueIsNull(pkClass, pkval);
}
}
List<Object> list = PersistSqlBuilder.buildSaveSql(c, entity, tn, isNull, pkval);
if (list == null)
return -1;
String sql = (String)list.get(0);
Object[] objs = (Object[])list.get(1);
if (isReturnPk)
{
Object id = pkval;
if (id == null || isNull)
{
if (pkdata.getFeedBackKey() == FeedBackKeyType.SELECT)
{
id = executeUpdateSelectKey(sql, pkdata.getSelect(), fdata.getFieldClass(), objs);
}
else
{
id = executeUpdateGeneratedKey(sql, fdata.getFieldClass(), objs);
}
}
else
{
executeUpdate(sql, objs);
}
if (!id.getClass().equals(pkClass))
{
id = DataTypeHelper.longToOther(id, pkClass);
}
fdata.setValue(entity, id);
list.clear();
list = null;
return id;
}
int ret = executeUpdate(sql, objs);
if (pkval != null && !isNull)
{
fdata.setValue(entity, pkval);
}
list.clear();
list = null;
return ret;
}
/**
* {@inheritDoc}
*/
public <T> void update(T entity)
{
update(entity, false);
}
/**
* {@inheritDoc}
*/
@SuppressWarnings("unchecked")
public <T> void update(T entity, boolean isNullable)
{
initialize();
Class<T> c = null;
if (entity == null)
{
throw new PersistenceException("update entity is null");
}
else
{
c = (Class<T>)entity.getClass();
}
try
{
String tn = ClassFactory.getTableName(c);
if (tn == null)
return;
List<Object> list = PersistSqlBuilder.buildUpdateSql(c, entity, tn, isNullable);
if (list == null)
return;
String sql = (String)list.get(0);
Object[] objs = (Object[])list.get(1);
executeUpdate(sql, objs);
}
catch (Exception e)
{
throw new PersistenceException("update exception " + e.toString());
}
}
/**
* {@inheritDoc}
*/
public <T> void delete(T entity)
{
Class<?> c = null;
if (entity == null)
{
throw new PersistenceException("delete entity is null");
}
else
{
c = entity.getClass();
}
if (c != null)
{
int val = (Integer)ClassFactory.getPrimaryKeyValue(c, entity);
delete(c, val);
}
}
/**
* {@inheritDoc}
*/
public <T> void delete(Class<T> c, int id)
{
initialize();
String sql = deleteMap.get(c.getName());
;
if (sql == null)
{
sql = PersistSqlBuilder.buildDeleteSql(c, id);
if (sql == null)
return;
deleteMap.put(c.getName(), sql);
}
executeUpdate(sql, id);
}
/**
* {@inheritDoc}
*/
public int executeUpdate(String sql, Object... params)
{
initialize();
sql = sql.toLowerCase();
logger.debug("[SQL]" + sql);
int Count = -1;
PreparedStatement pstmt = null;
boolean isAutoCommit = tx.isAutoCommit();
try
{
pstmt = tx.getPreparedStatement(sql, StatementType.Normal);
tx.setAutoCommit(false);
if (params != null)
{
for (int i = 0; i < params.length; i++)
{
JdbcHelper.setObject(pstmt, i + 1, params[i]);
}
}
if (pstmt != null)
{
Count = pstmt.executeUpdate();
if (isAutoCommit)
{
tx.commit();
}
}
}
catch (SQLException ex)
{
if (isAutoCommit)
{
JdbcHelper.rollback(tx);
}
throw new SessionException("SessionSupport::executeUpdate sql exception " + ex.toString(), ex);
}
finally
{
try
{
tx.setAutoCommit(isAutoCommit);
}
catch (SQLException e)
{
e.printStackTrace();
}
JdbcHelper.closeStatement(pstmt);
CacheContext ctx = SessionContext.getCacheContext();
if (SessionContext.isUseCache() && ctx != null)
{
ctx.flushAll();
}
}
return Count;
}
/**
* {@inheritDoc}
*/
public Object executeUpdateGeneratedKey(String sql, Object... params)
{
initialize();
sql = sql.toLowerCase();
logger.debug("[SQL]" + sql);
PreparedStatement pstmt = null;
boolean isAutoCommit = tx.isAutoCommit();
try
{
pstmt = tx.getPreparedStatement(sql, StatementType.GenerateKey);
tx.setAutoCommit(false);
if (params != null)
{
for (int i = 0; i < params.length; i++)
{
JdbcHelper.setObject(pstmt, i + 1, params[i]);
}
}
pstmt.executeUpdate();
if (isAutoCommit)
{
tx.commit();
Object autoIncKeyFromApi = -1;
ResultSet rs = null;
try
{
rs = pstmt.getGeneratedKeys();
if (rs != null && rs.next())
{
autoIncKeyFromApi = rs.getObject(1);
}
}
finally
{
JdbcHelper.closeResultSet(rs);
}
return autoIncKeyFromApi;
}
else
{
return 0;
}
}
catch (SQLException ex)
{
if (isAutoCommit)
{
JdbcHelper.rollback(tx);
}
throw new SessionException("SessionSupport::executeUpdateGeneratedKey sql exception " + ex.toString(), ex);
}
finally
{
try
{
tx.setAutoCommit(isAutoCommit);
}
catch (SQLException e)
{
e.printStackTrace();
}
JdbcHelper.closeStatement(pstmt);
CacheContext ctx = SessionContext.getCacheContext();
if (SessionContext.isUseCache() && ctx != null)
{
ctx.flushAll();
}
}
}
/**
* ִ�и��£��ɷ�������ֵ
*
* @param sql SQL���
* @param param ע���������
* @return ����ֵ
*/
private Object executeUpdateGeneratedKey(String sql, Class<?> keyClass, Object[] params)
throws SessionException
{
initialize();
sql = sql.toLowerCase();
logger.debug("[SQL]" + sql);
PreparedStatement pstmt = null;
boolean isAutoCommit = tx.isAutoCommit();
try
{
pstmt = tx.getPreparedStatement(sql, StatementType.GenerateKey);
tx.setAutoCommit(false);
if (params != null)
{
for (int i = 0; i < params.length; i++)
{
JdbcHelper.setObject(pstmt, i + 1, params[i]);
}
}
pstmt.execute();
Object autoIncKeyFromApi = -1;
ResultSet rs = null;
try
{
rs = pstmt.getGeneratedKeys();
if (rs != null && rs.next())
{
autoIncKeyFromApi = rs.getObject(1);
}
}
finally
{
JdbcHelper.closeResultSet(rs);
}
if (isAutoCommit)
{
tx.commit();
}
return autoIncKeyFromApi;
}
catch (SQLException ex)
{
if (isAutoCommit)
{
JdbcHelper.rollback(tx);
}
throw new SessionException("SessionSupport::executeUpdateGeneratedKey sql exception " + ex.toString(), ex);
}
finally
{
try
{
tx.setAutoCommit(isAutoCommit);
}
catch (SQLException e)
{
e.printStackTrace();
}
JdbcHelper.closeStatement(pstmt);
CacheContext ctx = SessionContext.getCacheContext();
if (SessionContext.isUseCache() && ctx != null)
{
ctx.flushAll();
}
}
}
/**
* ִ�и��£��ɷ�������ֵ
*
* @param sql SQL���
* @param param ע���������
* @return ����ֵ
*/
private Object executeUpdateSelectKey(String sql, String keysql, Class<?> keyClass, Object[] param)
throws SessionException
{
initialize();
sql = sql.toLowerCase();
logger.debug("[SQL]" + sql);
PreparedStatement pstmt = null;
boolean isAutoCommit = tx.isAutoCommit();
try
{
pstmt = tx.getPreparedStatement(sql, StatementType.Normal);
tx.setAutoCommit(false);
if (param != null)
{
for (int i = 0; i < param.length; i++)
{
JdbcHelper.setObject(pstmt, i + 1, param[i]);
}
}
pstmt.execute();
Object autoIncKeyFromApi = null;
if (pstmt.execute(keysql))
{
ResultSet rs = null;
try
{
rs = pstmt.getResultSet();
if (rs != null && rs.next())
{
autoIncKeyFromApi = ReflectHelper.getResultSetValue(rs, keyClass, 1);
}
}
finally
{
JdbcHelper.closeResultSet(rs);
}
}
if (isAutoCommit)
{
tx.commit();
}
return autoIncKeyFromApi;
}
catch (SQLException ex)
{
if (isAutoCommit)
{
JdbcHelper.rollback(tx);
}
throw new SessionException("SessionSupport::executeUpdateSelectKey sql exception " + ex.toString(), ex);
}
finally
{
try
{
tx.setAutoCommit(isAutoCommit);
}
catch (SQLException e)
{
e.printStackTrace();
}
JdbcHelper.closeStatement(pstmt);
CacheContext ctx = SessionContext.getCacheContext();
if (SessionContext.isUseCache() && ctx != null)
{
ctx.flushAll();
}
}
}
/**
* {@inheritDoc}
*/
public boolean isAutoCommit()
{
initialize();
return tx.isAutoCommit();
}
/**
* {@inheritDoc}
*/
public void setAutoCommit(boolean isAutoCommit)
throws SQLException
{
initialize();
tx.setAutoCommit(isAutoCommit);
}
/**
* {@inheritDoc}
*/
public void commit()
throws SQLException
{
initialize();
tx.commit();
CacheContext ctx = SessionContext.getCacheContext();
if (SessionContext.isUseCache() && ctx != null)
{
ctx.flushAll();
}
}
/**
* {@inheritDoc}
*/
public void rollback()
{
initialize();
JdbcHelper.rollback(tx);
CacheContext ctx = SessionContext.getCacheContext();
if (SessionContext.isUseCache() && ctx != null)
{
ctx.flushAll();
}
}
/**
* {@inheritDoc}
*/
public void rollback(Savepoint point)
{
initialize();
JdbcHelper.rollback(tx, point);
CacheContext ctx = SessionContext.getCacheContext();
if (SessionContext.isUseCache() && ctx != null)
{
ctx.flushAll();
}
}
/**
* {@inheritDoc}
*/
public Savepoint setSavepoint()
throws SQLException
{
initialize();
return tx.setSavepoint();
}
/**
* {@inheritDoc}
*/
public Savepoint setSavepoint(String name)
throws SQLException
{
initialize();
return tx.setSavepoint(name);
}
}