/*******************************************************************************
* Copyright (c) 2013 hangum.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Lesser Public License v2.1
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
* Contributors:
* hangum - initial API and implementation
******************************************************************************/
package com.hangum.tadpole.engine.manager;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Timestamp;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import javax.sql.DataSource;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import com.hangum.tadpole.commons.exception.TadpoleSQLManagerException;
import com.hangum.tadpole.commons.libs.core.define.PublicTadpoleDefine;
import com.hangum.tadpole.commons.util.LoadConfigFile;
import com.hangum.tadpole.engine.define.DBDefine;
import com.hangum.tadpole.engine.define.DBGroupDefine;
import com.hangum.tadpole.engine.manager.transaction.DBCPConnectionManager;
import com.hangum.tadpole.engine.manager.transaction.TransactionDAO;
import com.hangum.tadpole.engine.query.dao.system.UserDBDAO;
/**
* Tadpole SQL Transaction manager
*
* @author hangum
*
*/
public class TadpoleSQLTransactionManager extends AbstractTadpoleManager {
/**
* Logger for this class
*/
private static final Logger logger = Logger.getLogger(TadpoleSQLTransactionManager.class);
private static Map<String, TransactionDAO> dbManager = null;
private static TadpoleSQLTransactionManager transactionManager = null;
private static boolean isGatewayConnection = false;
private static boolean isGateWayIDCheck = false;
private TadpoleSQLTransactionManager() {
}
static {
if (transactionManager == null) {
transactionManager = new TadpoleSQLTransactionManager();
dbManager = new HashMap<String, TransactionDAO>();
isGatewayConnection = LoadConfigFile.isEngineGateway();
isGateWayIDCheck = LoadConfigFile.isGateWayIDCheck();
}
}
/**
* java.sql.connection을 생성하고 관리합니다.
*
* @param userId
* @param userDB
*
* @return
* @throws Exception
*/
public static Connection getInstance(final String userId, final UserDBDAO userDB) throws Exception {
final String searchKey = getKey(userId, userDB);
if (logger.isDebugEnabled()) logger.debug("[userId]" + searchKey);
Connection _conn = null;;
TransactionDAO transactionDAO = dbManager.get(searchKey);
if (transactionDAO == null) {
try {
DataSource ds = null;
// gate way 서버에 연결하려는 디비 정보가 있는지
if(isGatewayConnection && userDB.getDBDefine() != DBDefine.TADPOLE_SYSTEM_MYSQL_DEFAULT) {
final UserDBDAO gatawayUserDB = (UserDBDAO)userDB.clone();
TDBGatewayManager.makeGatewayServer(gatawayUserDB, isGateWayIDCheck);
ds = DBCPConnectionManager.getInstance().makeDataSource(searchKey, gatawayUserDB);
} else {
ds = DBCPConnectionManager.getInstance().makeDataSource(searchKey, userDB);
}
_conn = ds.getConnection();
_conn.setAutoCommit(false);
// 캐릭터 셋을 맞추어준다.
setConnectionInitialize(userDB, _conn);
final TransactionDAO _transactionDAO = new TransactionDAO();
_transactionDAO.setConn(_conn);
_transactionDAO.setUserId(userId);
_transactionDAO.setUserDB(userDB);
_transactionDAO.setStartTransaction(new Timestamp(System.currentTimeMillis()));
_transactionDAO.setKey(searchKey);
dbManager.put(searchKey, _transactionDAO);
} catch (Exception e) {
logger.error("transaction connection", e);
removeInstance(userId, searchKey);
throw e;
}
} else {
_conn = transactionDAO.getConn();
}
// 변경시 마다 커넥션을 수정한다.
return changeSchema(userId, searchKey, userDB, _conn);
}
/**
* 사용자 커넥션을 얻는다.
*
* @param searchKey
* @param userDB
* @param javaConn
* @return
* @throws TadpoleSQLManagerException
* @throws SQLException
*/
private static Connection changeSchema(final String userId, final String searchKey, final UserDBDAO userDB, Connection javaConn) throws TadpoleSQLManagerException, SQLException {
String strSQL = "";
if(userDB.getDBGroup() == DBGroupDefine.MYSQL_GROUP) {
strSQL = String.format("use `%s`", userDB.getSchema());
} else if(userDB.getDBGroup() == DBGroupDefine.ORACLE_GROUP) {
strSQL = String.format("ALTER SESSION SET CURRENT_SCHEMA = %s", userDB.getSchema());
} else if(userDB.getDBGroup() == DBGroupDefine.POSTGRE_GROUP) {
strSQL = String.format("set schema '%s'", userDB.getSchema());
} else {
strSQL = userDB.getDBDefine().getValidateQuery(false);
}
Statement statement = null;
try {
statement = javaConn.createStatement();
statement.executeUpdate(strSQL);
} catch(Exception e) {
logger.error("Transaction Connection disconnected. and now connect of newone. user id is " + userId);
// Display display = PlatformUI.getWorkbench().getDisplay();
// if(MessageDialog.openConfirm(display.getActiveShell(), "error", "디비연결시 오류가 발생했습니다. 기존 연결을 지우고 새롭게 연결하시겠습니까?")) {
removeInstance(userId, searchKey);
try {
javaConn = getInstance(userId, userDB);
} catch (Exception e1) {
logger.error("user connection disconnect" + e1);
}
// } else {
// throw new SQLException(e);
// }
} finally {
if(statement != null) statement.close();
}
return javaConn;
}
/**
* transaction commit
*
* @param userId
* @param userDB
*/
public static void commit(final String userId, final UserDBDAO userDB) {
final String searchKey = getKey(userId, userDB);
if (logger.isDebugEnabled()) {
logger.debug("=============================================================================");
logger.debug("\t rollback [userId]" + searchKey);
logger.debug("=============================================================================");
}
TransactionDAO transactionDAO = dbManager.get(searchKey);
if (transactionDAO != null) {
Connection conn = transactionDAO.getConn();
try {
conn.commit();
} catch (Exception e) {
logger.error("commit exception", e);
} finally {
try { if(conn != null) conn.close();} catch (Exception e) {}
removeInstance(userId, searchKey);
}
}
}
/**
* connection rollback
*
* @param userId
* @param userDB
*/
public static void rollback(final String userId, final UserDBDAO userDB) {
final String searchKey = getKey(userId, userDB);
if (logger.isDebugEnabled()) {
logger.debug("=============================================================================");
logger.debug("\t rollback [userId]" + searchKey);
logger.debug("=============================================================================");
}
TransactionDAO transactionDAO = dbManager.get(searchKey);
if (transactionDAO != null) {
Connection conn = transactionDAO.getConn();
try {
if (logger.isDebugEnabled()) logger.debug("\tIs auto commit " + conn.getAutoCommit());
conn.rollback();
} catch (Exception e) {
logger.error("rollback exception", e);
} finally {
try { if(conn != null) conn.close(); } catch (Exception e) {}
removeInstance(userId, searchKey);
}
}
}
/**
* 사용자가 로그 아웃등으로 나갈때 transaction rollback합니다.
*
* @param userId
*/
public static void executeAllRollback(final String userId) {
Iterator iteratorEntrySet = dbManager.entrySet().iterator();
while(iteratorEntrySet.hasNext()) {
Map.Entry mapObject = (Map.Entry)iteratorEntrySet.next();
String searchKey = (String)mapObject.getKey();
try {
if (StringUtils.startsWith(searchKey, userId + PublicTadpoleDefine.DELIMITER)) {
if (logger.isDebugEnabled()) logger.debug(String.format("== logout executeRollback start== [%s]", searchKey));
TransactionDAO transactionDAO = (TransactionDAO)mapObject.getValue();
if (transactionDAO != null) {
Connection conn = transactionDAO.getConn();
try {
conn.rollback();
} catch (Exception e) {
logger.error("logout transaction commit", e);
} finally {
try { if (conn != null) conn.close(); } catch (Exception e) {}
}
} // end trsansaction dao
// 기존 object와 커넥션 풀을 삭제한다.
iteratorEntrySet.remove();
transactionDAO =null;
DBCPConnectionManager.getInstance().releaseConnectionPool(searchKey);
}
} catch(Exception e) {
logger.error("********************** Release connection pool exception", e);
}
}
}
/**
* remove map instance
*
* @param userId
* @param userDB
*/
private static void removeInstance(final String userId, final String searchKey) {
if (logger.isDebugEnabled()) logger.debug("\t #### [TadpoleSQLTransactionManager] remove Instance: " + searchKey);
try {
TransactionDAO transactionDAO = dbManager.remove(searchKey);
transactionDAO =null;
DBCPConnectionManager.getInstance().releaseConnectionPool(searchKey);
} catch (Exception e) {
logger.error("remove connection", e);
}
}
public static Map<String, TransactionDAO> getDbManager() {
return dbManager;
}
public static boolean isInstance(final String userId, final UserDBDAO userDB) {
return getDbManager().containsKey(getKey(userId, userDB));
}
/**
* map의 카를 가져옵니다.
*
* @param userDB
* @return
*/
private static String getKey(final String userId, final UserDBDAO userDB) {
return userId + PublicTadpoleDefine.DELIMITER +
userDB.getDisplay_name() + PublicTadpoleDefine.DELIMITER +
userDB.getDbms_type() + PublicTadpoleDefine.DELIMITER +
userDB.getSeq() + PublicTadpoleDefine.DELIMITER +
userDB.getUsers() + PublicTadpoleDefine.DELIMITER;
}
}