/*
* Copyright (c) MuleSoft, Inc. All rights reserved. http://www.mulesoft.com
* The software in this package is published under the terms of the CPAL v1.0
* license, a copy of which has been included with this distribution in the
* LICENSE.txt file.
*/
package org.mule.runtime.core.util.queue;
import org.mule.runtime.core.api.MuleContext;
import org.mule.runtime.core.util.journal.queue.LocalTxQueueTransactionJournal;
import org.mule.runtime.core.util.xa.AbstractResourceManager;
import org.mule.runtime.core.util.xa.AbstractTransactionContext;
import org.mule.runtime.core.util.xa.ResourceManagerException;
import org.mule.runtime.core.util.xa.XaTransactionRecoverer;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import javax.transaction.xa.XAException;
import javax.transaction.xa.XAResource;
import javax.transaction.xa.Xid;
/**
* A Queue session that is used to manage the transaction context of a Queue.
* <p/>
* This QueueSession can be used for local and xa transactions
*/
public class TransactionalQueueSession extends AbstractQueueSession implements QueueSession {
private final QueueXaResource queueXaResource;
private final AbstractResourceManager resourceManager;
private final LocalTxQueueTransactionJournal localTxTransactionJournal;
private final ReentrantReadWriteLock txContextReadWriteLock;
private LocalQueueTransactionContext singleResourceTxContext;
public TransactionalQueueSession(QueueProvider queueProvider, QueueXaResourceManager xaResourceManager,
AbstractResourceManager resourceManager, XaTransactionRecoverer xaTransactionRecoverer,
LocalTxQueueTransactionJournal localTxTransactionJournal, MuleContext muleContext) {
super(queueProvider, muleContext);
this.localTxTransactionJournal = localTxTransactionJournal;
this.resourceManager = resourceManager;
this.queueXaResource = new QueueXaResource(xaResourceManager, xaTransactionRecoverer, getQueueProvider());
this.txContextReadWriteLock = new ReentrantReadWriteLock();
}
protected QueueTransactionContext getTransactionalContext() {
if (singleResourceTxContext != null) {
return singleResourceTxContext;
} else {
return queueXaResource.getTransactionContext();
}
}
// Local transaction implementation
public void begin() throws ResourceManagerException {
final ReentrantReadWriteLock.WriteLock writeLock = txContextReadWriteLock.writeLock();
writeLock.lock();
try {
if (getTransactionalContext() != null) {
throw new IllegalStateException("Cannot start local transaction. A local transaction already in progress.");
}
singleResourceTxContext =
new LocalTxQueueTransactionContext(localTxTransactionJournal, getQueueProvider(), txContextReadWriteLock.readLock());
resourceManager.beginTransaction((AbstractTransactionContext) singleResourceTxContext);
} finally {
writeLock.unlock();
}
}
public void commit() throws ResourceManagerException {
final ReentrantReadWriteLock.WriteLock writeLock = txContextReadWriteLock.writeLock();
writeLock.lock();
try {
if (singleResourceTxContext == null) {
throw new IllegalStateException("Cannot commit local transaction as no transaction was begun");
}
resourceManager.commitTransaction((AbstractTransactionContext) singleResourceTxContext);
singleResourceTxContext = null;
} finally {
writeLock.unlock();
}
}
public void rollback() throws ResourceManagerException {
final ReentrantReadWriteLock.WriteLock writeLock = txContextReadWriteLock.writeLock();
writeLock.lock();
try {
if (singleResourceTxContext == null) {
throw new IllegalStateException("Cannot commit local transaction as no transaction was begun");
}
resourceManager.rollbackTransaction((AbstractTransactionContext) singleResourceTxContext);
singleResourceTxContext = null;
} finally {
writeLock.unlock();
}
}
// XA transaction delegation to QueueXaResource
@Override
public boolean isSameRM(XAResource xares) throws XAException {
return queueXaResource.isSameRM(xares);
}
@Override
public void start(Xid xid, int flags) throws XAException {
queueXaResource.start(xid, flags);
}
@Override
public void end(Xid xid, int flags) throws XAException {
queueXaResource.end(xid, flags);
}
@Override
public void commit(Xid xid, boolean onePhase) throws XAException {
queueXaResource.commit(xid, onePhase);
}
@Override
public void rollback(Xid xid) throws XAException {
queueXaResource.rollback(xid);
}
@Override
public int prepare(Xid xid) throws XAException {
return queueXaResource.prepare(xid);
}
@Override
public void forget(Xid xid) throws XAException {
queueXaResource.forget(xid);
}
@Override
public int getTransactionTimeout() throws XAException {
return queueXaResource.getTransactionTimeout();
}
@Override
public boolean setTransactionTimeout(int timeout) throws XAException {
return queueXaResource.setTransactionTimeout(timeout);
}
@Override
public Xid[] recover(int i) throws XAException {
return queueXaResource.recover(i);
}
}