use of org.apache.qpid.proton.amqp.transaction.Discharge in project activemq-artemis by apache.
the class ProtonTransactionHandler method onMessage.
@Override
public void onMessage(Delivery delivery) throws ActiveMQAMQPException {
final Receiver receiver;
try {
receiver = ((Receiver) delivery.getLink());
if (!delivery.isReadable()) {
return;
}
ByteBuffer buffer;
MessageImpl msg;
connection.lock();
try {
// transaction declare and discahrge operations.
if (receiver.getCredit() < amqpLowMark) {
receiver.flow(amqpCredit);
}
// the incoming request is to big just use a scratch buffer.
if (delivery.available() > DECODE_BUFFER.capacity()) {
buffer = ByteBuffer.allocate(delivery.available());
} else {
buffer = (ByteBuffer) DECODE_BUFFER.clear();
}
// Update Buffer for the next incoming command.
buffer.limit(receiver.recv(buffer.array(), buffer.arrayOffset(), buffer.capacity()));
receiver.advance();
msg = decodeMessage(buffer);
} finally {
connection.unlock();
}
Object action = ((AmqpValue) msg.getBody()).getValue();
if (action instanceof Declare) {
Binary txID = sessionSPI.newTransaction();
Declared declared = new Declared();
declared.setTxnId(txID);
IOCallback ioAction = new IOCallback() {
@Override
public void done() {
connection.lock();
try {
delivery.settle();
delivery.disposition(declared);
} finally {
connection.unlock();
connection.flush();
}
}
@Override
public void onError(int errorCode, String errorMessage) {
}
};
sessionSPI.afterIO(ioAction);
} else if (action instanceof Discharge) {
Discharge discharge = (Discharge) action;
Binary txID = discharge.getTxnId();
ProtonTransactionImpl tx = (ProtonTransactionImpl) sessionSPI.getTransaction(txID, true);
tx.discharge();
IOCallback ioAction = new IOCallback() {
@Override
public void done() {
connection.lock();
try {
delivery.settle();
delivery.disposition(new Accepted());
} finally {
connection.unlock();
connection.flush();
}
}
@Override
public void onError(int errorCode, String errorMessage) {
}
};
if (discharge.getFail()) {
sessionSPI.withinContext(() -> tx.rollback());
sessionSPI.afterIO(ioAction);
} else {
sessionSPI.withinContext(() -> tx.commit());
sessionSPI.afterIO(ioAction);
}
}
} catch (ActiveMQAMQPException amqpE) {
log.warn(amqpE.getMessage(), amqpE);
connection.lock();
try {
delivery.settle();
delivery.disposition(createRejected(amqpE.getAmqpError(), amqpE.getMessage()));
} finally {
connection.unlock();
}
connection.flush();
} catch (Throwable e) {
log.warn(e.getMessage(), e);
connection.lock();
try {
delivery.settle();
delivery.disposition(createRejected(Symbol.getSymbol("failed"), e.getMessage()));
} finally {
connection.unlock();
}
connection.flush();
}
}
use of org.apache.qpid.proton.amqp.transaction.Discharge in project activemq-artemis by apache.
the class AmqpTransactionCoordinator method discharge.
public void discharge(AmqpTransactionId txId, AsyncResult request, boolean commit) throws Exception {
if (isClosed()) {
Exception failureCause = null;
if (commit) {
failureCause = new TransactionRolledBackException("Transaction inbout: Coordinator remotely closed");
} else {
failureCause = new JMSException("Rollback cannot complete: Coordinator remotely closed");
}
request.onFailure(failureCause);
return;
}
// Store the context of this action in the transaction ID for later completion.
txId.setState(commit ? AmqpTransactionId.COMMIT_MARKER : AmqpTransactionId.ROLLBACK_MARKER);
Message message = Message.Factory.create();
Discharge discharge = new Discharge();
discharge.setFail(!commit);
discharge.setTxnId(txId.getRemoteTxId());
message.setBody(new AmqpValue(discharge));
Delivery pendingDelivery = getEndpoint().delivery(tagGenerator.getNextTag());
pendingDelivery.setContext(txId);
// Store away for completion
pendingDeliveries.add(pendingDelivery);
pendingRequests.put(txId, request);
sendTxCommand(message);
}
Aggregations