/*******************************************************************************
* Copyright (c) 2010 Robert "Unlogic" Olofsson (unlogic@unlogic.se).
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Lesser Public License v3
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/lgpl-3.0-standalone.html
******************************************************************************/
package se.unlogic.standardutils.dao;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Map.Entry;
import javax.sql.DataSource;
import se.unlogic.standardutils.dao.querys.ArrayListQuery;
import se.unlogic.standardutils.dao.querys.BooleanQuery;
import se.unlogic.standardutils.dao.querys.HashMapQuery;
import se.unlogic.standardutils.dao.querys.ObjectQuery;
import se.unlogic.standardutils.dao.querys.PreparedStatementQuery;
import se.unlogic.standardutils.dao.querys.UpdateQuery;
import se.unlogic.standardutils.db.DBUtils;
public class TransactionHandler {
private final Connection connection;
private ArrayList<PreparedStatementQuery> queryList;
private boolean aborted;
private boolean commited;
public TransactionHandler(DataSource dataSource) throws SQLException {
super();
this.connection = dataSource.getConnection();
connection.setAutoCommit(false);
}
public TransactionHandler(Connection connection) throws SQLException {
super();
this.connection = connection;
connection.setAutoCommit(false);
}
public UpdateQuery getUpdateQuery(String sqlExpression) throws SQLException {
this.checkStatus();
UpdateQuery query = new UpdateQuery(connection, false, sqlExpression);
checkQueryList();
this.queryList.add(query);
return query;
}
private synchronized void checkQueryList() {
if(queryList == null){
queryList = new ArrayList<PreparedStatementQuery>();
}
}
public BooleanQuery getBooleanQuery(String sql) throws SQLException {
BooleanQuery query = new BooleanQuery(connection, false, sql);
checkQueryList();
this.queryList.add(query);
return query;
}
public <T> ObjectQuery<T> getObjectQuery(String sql, BeanResultSetPopulator<T> populator) throws SQLException {
ObjectQuery<T> query = new ObjectQuery<T>(connection, false, sql, populator);
checkQueryList();
this.queryList.add(query);
return query;
}
public <T> ArrayListQuery<T> getArrayListQuery(String sql, BeanResultSetPopulator<T> populator) throws SQLException {
ArrayListQuery<T> query = new ArrayListQuery<T>(connection, false, sql, populator);
checkQueryList();
this.queryList.add(query);
return query;
}
public <K, V> HashMapQuery<K, V> getHashMapQuery(String sql, BeanResultSetPopulator<? extends Entry<K, V>> populator) throws SQLException {
HashMapQuery<K, V> query = new HashMapQuery<K, V>(connection, false, sql, populator);
checkQueryList();
this.queryList.add(query);
return query;
}
public synchronized void commit() throws SQLException {
this.checkStatus();
try {
connection.commit();
this.commited = true;
} finally {
if (!this.commited) {
this.abort();
} else {
this.closeConnection();
}
}
}
public synchronized int getQueryCount() {
if(queryList == null){
return 0;
}
return this.queryList.size();
}
public synchronized void abort() {
this.checkStatus();
if(queryList != null){
for (PreparedStatementQuery query : queryList) {
query.abort();
}
}
if (connection != null) {
try {
connection.rollback();
} catch (SQLException e) {}
}
this.closeConnection();
this.aborted = true;
}
private void closeConnection() {
DBUtils.closeConnection(connection);
}
private void checkStatus() {
if (aborted) {
throw new TransactionAlreadyAbortedException();
} else if (commited) {
throw new TransactionAlreadyComittedException();
}
}
@Override
protected void finalize() throws Throwable {
if (!commited && !aborted) {
this.abort();
}
super.finalize();
}
public boolean isClosed() {
return commited || aborted;
}
public static void autoClose(TransactionHandler transactionHandler) {
if (transactionHandler != null && !transactionHandler.isClosed()) {
transactionHandler.abort();
}
}
//Workaround for AnnotatedDAO, needs a better solution in the long run
Connection getConnection() {
return connection;
}
public boolean isAborted() {
return aborted;
}
public boolean isCommited() {
return commited;
}
}