/* ====================================================================
* The LateralNZ Software License, Version 1.0
*
* Copyright (c) 2003 LateralNZ. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by
* LateralNZ (http://www.lateralnz.org/) and other third parties."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "LateralNZ" must not be used to endorse or promote
* products derived from this software without prior written
* permission. For written permission, please
* contact oss@lateralnz.org.
*
* 5. Products derived from this software may not be called "Panther",
* or "Lateral" or "LateralNZ", nor may "PANTHER" or "LATERAL" or
* "LATERALNZ" appear in their name, without prior written
* permission of LateralNZ.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of LateralNZ. For more
* information on Lateral, please see http://www.lateralnz.com/ or
* http://www.lateralnz.org
*
*/
package org.lateralnz.simpletrans;
import java.util.Iterator;
import java.util.HashMap;
import java.util.Map;
import java.sql.SQLException;
import javax.transaction.Status;
import javax.transaction.Synchronization;
import javax.transaction.Transaction;
import javax.transaction.xa.XAResource;
import org.apache.log4j.Logger;
import org.lateralnz.common.util.DAOUtils;
/**
* a 'simple' transaction storing a map of named 'transaction-aware' connections. This class
* partially implements a javax.transaction.Transaction, but adds proprietary (to this package)
* methods for adding TransConnection objects.
* Note also that this isn't a true implementation of a transaction (by any stretch of
* the imagination). If two connections have been enlisted from different databases
* and a commit succeeds on one, then fails on the other, your data will (obviously) end up
* in an inconsistent state.
*
* @see org.lateralnz.panther.trans.TransConnection
*
* @author J R Briggs
*/
public class SimpleTransaction implements Transaction {
private static final Logger log = Logger.getLogger(SimpleTransaction.class.getName());
private Map connMap = new HashMap(); // the map of trans connections
private int status; // the status of this transaction
/**
* create a new transaction and make it active
*/
public SimpleTransaction() {
if (log.isDebugEnabled()) {
log.debug("starting new transaction");
}
status = Status.STATUS_ACTIVE;
}
/**
* commit a transaction, and close any connections that have been flagged for
* closing
*/
public void commit() {
status = Status.STATUS_COMMITTING;
Iterator iter = connMap.values().iterator();
while (iter.hasNext()) {
TransConnection conn = (TransConnection)iter.next();
try {
conn.doCommit();
if (conn.isCloseFlagged()) {
conn.doClose();
iter.remove();
}
}
catch (SQLException se) {
se.printStackTrace();
}
}
status = Status.STATUS_COMMITTED;
}
public boolean delistResource(XAResource xAResource, int param) {
TransConnection conn = (TransConnection)xAResource;
DAOUtils.close(conn);
connMap.remove(conn.getName());
return true;
}
public boolean enlistResource(XAResource xAResource) {
if (!(xAResource instanceof TransConnection)) {
throw new UnsupportedOperationException();
}
try {
TransConnection conn = (TransConnection)xAResource;
conn.setAutoCommit(false);
connMap.put(conn.getName(), conn);
return true;
}
catch (SQLException se) {
se.printStackTrace();
return false;
}
}
/**
* get a resource by name
*/
public Object getResource(String name) {
if (connMap.containsKey(name)) {
return connMap.get(name);
}
else {
return null;
}
}
/**
* get the status of this transaction
*/
public int getStatus() {
return status;
}
/**
* not supported
*/
public void registerSynchronization(Synchronization synchronization) {
throw new UnsupportedOperationException();
}
/**
* rollback the connections in this transaction
*/
public void rollback() {
status = Status.STATUS_ROLLING_BACK;
Iterator iter = connMap.values().iterator();
while (iter.hasNext()) {
TransConnection conn = (TransConnection)iter.next();
try {
if (log.isDebugEnabled()) {
log.debug("rollback connection " + conn);
}
conn.doRollback(null);
if (conn.isCloseFlagged()) {
if (log.isDebugEnabled()) {
log.debug("close flagged, so closing connection");
}
conn.doClose();
iter.remove();
}
}
catch (SQLException se) {
se.printStackTrace();
}
}
status = Status.STATUS_ROLLEDBACK;
}
/**
* flag that a rollback is required
*/
public void setRollbackOnly() {
status = Status.STATUS_MARKED_ROLLBACK;
}
}
|