/******************************************************************************* * 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 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; import javax.sql.DataSource; import java.sql.Connection; import java.sql.SQLException; import java.util.ArrayList; import java.util.Map.Entry; 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; } }