/*
* 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.util.journal.queue.XaQueueTxJournalEntry;
import org.mule.runtime.core.util.journal.queue.XaTxQueueTransactionJournal;
import org.mule.runtime.core.util.xa.ResourceManagerException;
import java.io.Serializable;
import java.util.Collection;
import java.util.concurrent.atomic.AtomicInteger;
import javax.transaction.xa.Xid;
import org.apache.commons.collections.Closure;
import org.apache.commons.collections.CollectionUtils;
/**
* Implementation of {@link org.mule.runtime.core.util.queue.XaQueueTransactionContext} for persistent queues using XA
* transactions
*/
public class PersistentXaTransactionContext implements XaQueueTransactionContext {
private final XaTxQueueTransactionJournal transactionJournal;
private final QueueProvider queueProvider;
private Xid xid;
public PersistentXaTransactionContext(XaTxQueueTransactionJournal simpleTxQueueTransactionJournal, QueueProvider queueProvider,
Xid xid) {
this.transactionJournal = simpleTxQueueTransactionJournal;
this.queueProvider = queueProvider;
this.xid = xid;
}
public boolean offer(QueueStore queue, Serializable item, long offerTimeout) throws InterruptedException {
this.transactionJournal.logAdd(xid, queue, item);
return true;
}
public void untake(QueueStore queue, Serializable item) throws InterruptedException {
this.transactionJournal.logAddFirst(xid, queue, item);
}
public void clear(QueueStore queue) throws InterruptedException {
synchronized (queue) {
while (poll(queue, 100) != null);
}
}
public Serializable poll(QueueStore queue, long pollTimeout) throws InterruptedException {
synchronized (queue) {
Serializable value = queue.peek();
if (value == null) {
return null;
}
this.transactionJournal.logRemove(xid, queue, value);
return queue.poll(pollTimeout);
}
}
public Serializable peek(QueueStore queue) throws InterruptedException {
return queue.peek();
}
public int size(QueueStore queue) {
final AtomicInteger addSize = new AtomicInteger(0);
CollectionUtils.forAllDo(this.transactionJournal.getLogEntriesForTx(xid), new Closure() {
@Override
public void execute(Object value) {
if (((XaQueueTxJournalEntry) value).isAdd() || ((XaQueueTxJournalEntry) value).isAddFirst()) {
addSize.incrementAndGet();
}
}
});
return queue.getSize() + addSize.get();
}
@Override
public void doCommit() throws ResourceManagerException {
try {
Collection<XaQueueTxJournalEntry> logEntries = this.transactionJournal.getLogEntriesForTx(xid);
for (XaQueueTxJournalEntry entry : logEntries) {
if (entry.isAdd()) {
queueProvider.getQueue(entry.getQueueName()).putNow(entry.getValue());
} else if (entry.isAddFirst()) {
queueProvider.getQueue(entry.getQueueName()).untake(entry.getValue());
}
}
this.transactionJournal.logCommit(xid);
} catch (Exception e) {
throw new ResourceManagerException(e);
}
}
@Override
public void doRollback() throws ResourceManagerException {
Collection<XaQueueTxJournalEntry> logEntries = this.transactionJournal.getLogEntriesForTx(xid);
for (XaQueueTxJournalEntry entry : logEntries) {
if (entry.isRemove()) {
try {
queueProvider.getQueue(entry.getQueueName()).putNow(entry.getValue());
} catch (InterruptedException e) {
throw new ResourceManagerException(e);
}
}
}
this.transactionJournal.logRollback(xid);
}
@Override
public void doPrepare() throws ResourceManagerException {
this.transactionJournal.logPrepare(xid);
}
}