/* * The contents of this file are subject to the Open Software License * Version 3.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.rosenlaw.com/OSL3.0.htm * * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See * the License for the specific language governing rights and limitations * under the License. * * This file is an original work developed by Netymon Pty Ltd * (http://www.netymon.com, mailto:mail@netymon.com) under contract to * Topaz Foundation. Portions created under this contract are * Copyright (c) 2007 Topaz Foundation * All Rights Reserved. */ package org.mulgara.resolver; // Java2 packages import java.util.HashSet; import java.util.Set; import javax.transaction.xa.XAResource; import javax.transaction.xa.Xid; // Local packages import org.mulgara.query.MulgaraTransactionException; import org.mulgara.query.QueryException; /** * Manages external transactions. * * @created 2007-11-06 * * @author <a href="mailto:andrae@netymon.com">Andrae Muys</a> * * @company <A href="mailto:mail@netymon.com">Netymon Pty Ltd</A> * * @copyright ©2007 <a href="http://www.topazproject.org/">Topaz Foundation</a> * * @licence Open Software License v3.0</a> */ public class MulgaraExternalTransactionFactory extends MulgaraTransactionFactory { private final Set<MulgaraExternalTransaction> transactions; private final MulgaraXAResourceContext xaResource; private MulgaraExternalTransaction associatedTransaction; private String lastRollbackCause; public MulgaraExternalTransactionFactory(DatabaseSession session, MulgaraTransactionManager manager) { super(session, manager); this.associatedTransaction = null; this.lastRollbackCause = null; this.transactions = new HashSet<MulgaraExternalTransaction>(); this.xaResource = new MulgaraXAResourceContext(this, session); } public MulgaraTransaction getTransaction(boolean write) throws MulgaraTransactionException { acquireMutex(0, MulgaraTransactionException.class); try { if (associatedTransaction == null) { throw new MulgaraTransactionException( "No externally mediated transaction associated with session" + (lastRollbackCause != null ? " - last transaction was rolled back with error: " + lastRollbackCause : "")); } else if (write && associatedTransaction != writeTransaction) { throw new MulgaraTransactionException("RO-transaction associated with session when requesting write operation"); } return associatedTransaction; } finally { releaseMutex(); } } protected MulgaraExternalTransaction createTransaction(Xid xid, boolean write) throws MulgaraTransactionException { acquireMutex(0, MulgaraTransactionException.class); try { if (associatedTransaction != null) { throw new MulgaraTransactionException( "Attempt to initiate transaction with existing transaction active with session"); } if (write && manager.isHoldingWriteLock(session)) { throw new MulgaraTransactionException("Attempt to initiate two write transactions from the same session"); } if (write) { manager.obtainWriteLock(session); MulgaraExternalTransaction xa = null; try { xa = new MulgaraExternalTransaction(this, xid, session.newOperationContext(true)); writeTransaction = xa; associatedTransaction = xa; lastRollbackCause = null; transactions.add(xa); transactionCreated(xa); return xa; } catch (Throwable th) { manager.releaseWriteLock(session); if (xa != null) transactionComplete(xa, th.toString()); throw new MulgaraTransactionException("Error initiating write transaction", th); } } else { try { MulgaraExternalTransaction xa = new MulgaraExternalTransaction(this, xid, session.newOperationContext(false)); associatedTransaction = xa; lastRollbackCause = null; transactions.add(xa); transactionCreated(xa); return xa; } catch (QueryException eq) { throw new MulgaraTransactionException("Error obtaining new read-only operation-context", eq); } } } finally { releaseMutex(); } } protected Set<MulgaraExternalTransaction> getTransactions() { return transactions; } public XAResource getXAResource(boolean writing) { acquireMutex(0, RuntimeException.class); try { return xaResource.getResource(writing); } finally { releaseMutex(); } } public void transactionComplete(MulgaraExternalTransaction xa, String rollbackCause) throws MulgaraTransactionException { acquireMutex(0, MulgaraTransactionException.class); try { super.transactionComplete(xa); if (xa == null) { throw new IllegalArgumentException("Null transaction indicated completion"); } if (xa == writeTransaction) { manager.releaseWriteLock(session); writeTransaction = null; } transactions.remove(xa); if (associatedTransaction == xa) { associatedTransaction = null; lastRollbackCause = rollbackCause; } } finally { releaseMutex(); } } public boolean hasAssociatedTransaction() { acquireMutex(0, RuntimeException.class); try { return associatedTransaction != null; } finally { releaseMutex(); } } public boolean associateTransaction(MulgaraExternalTransaction xa) { acquireMutex(0, RuntimeException.class); try { if (associatedTransaction != null) { return false; } else { associatedTransaction = xa; return true; } } finally { releaseMutex(); } } public MulgaraExternalTransaction getAssociatedTransaction() { acquireMutex(0, RuntimeException.class); try { return associatedTransaction; } finally { releaseMutex(); } } public void disassociateTransaction(MulgaraExternalTransaction xa) throws MulgaraTransactionException { acquireMutex(0, MulgaraTransactionException.class); try { if (associatedTransaction == xa) { associatedTransaction = null; } } finally { releaseMutex(); } } public void closingSession() throws MulgaraTransactionException { acquireMutexWithInterrupt(0, MulgaraTransactionException.class); try { try { super.closingSession(); } finally { transactions.clear(); } } finally { releaseMutex(); } } }