use of org.jboss.jbossts.star.resource.Transaction in project narayana by jbosstm.
the class Coordinator method terminateTransaction.
/**
* The client can control the outcome of the transaction by by PUTing to the terminator
* URL returned as a response to the original transaction create request.
* Upon termination, the resource and all associated resources are implicitly deleted.
* For any subsequent invocation then an implementation MAY return 410 if the implementation
* records information about transactions that have completed, otherwise it should return 404
* (not necessary for presumed rollback semantics) but at a minimum MUST return 401.
* The invoker can assume this was a rollback. In order for an interested party to know for
* sure the outcome of a transaction then it MUST be registered as a participant with the
* transaction coordinator.
*
* @param txId URL template component containing the transaction identifier
* @param fault mechanism for injecting faults TODO use byteman instead
* @param content body of the request indicating a commit or abort request
* @see TxStatus#TransactionCommitted etc
* @return http response code
*/
@PUT
@Path(TxSupport.TX_SEGMENT + "{TxId}/" + TxLinkNames.TERMINATOR)
public Response terminateTransaction(@PathParam("TxId") String txId, @QueryParam("fault") @DefaultValue("") String fault, String content) {
log.tracef("coordinator: commit: transaction-manager/%s/terminator : content: %s", txId, content);
Transaction tx = getTransaction(txId);
String how = TxSupport.getStringValue(content, TxStatusMediaType.STATUS_PROPERTY);
TxStatus currentStatus = tx.getTxStatus();
String status;
int scRes;
/*
* 275If the transaction no longer exists then an implementation MAY return 410 if the implementation
* 276records information about transactions that have rolled back, (not necessary for presumed
* 277rollback semantics) but at a minimum MUST return 404.
*/
if (!currentStatus.isRunning() && !currentStatus.isRollbackOnly())
return Response.status(HttpURLConnection.HTTP_PRECON_FAILED).build();
/*
ABORT_ONLY is not in the spec for the same reasons as it's not in the WS-TX and WS-CAF where
it is assumed that only the txn originator can end the tx:
- simply register a synchronization in the transaction that prevented a commit from happening;
and I haven't implemented synchronisations yet.
It is unclear why allowing similar functionality via synchronisations doesn't open up a similar
security hole.
*/
TxStatus txStatus = TxStatus.fromStatus(how);
tx.setFault(fault);
AtomicAction.resume(tx);
switch(txStatus) {
case TransactionCommitted:
prepared.incrementAndGet();
status = tx.getStatus(tx.commit(true));
break;
case TransactionRolledBack:
prepared.incrementAndGet();
status = tx.getStatus(tx.abort());
break;
case TransactionRollbackOnly:
tx.preventCommit();
status = tx.getStatus();
break;
default:
AtomicAction.suspend();
return Response.status(HttpURLConnection.HTTP_BAD_REQUEST).build();
}
AtomicAction.suspend();
log.tracef("terminate result: %s", status);
/* if (tx.isRunning())
throw new TransactionStatusException("Transaction failed to terminate");*/
// Cleanup is done as part of the org.jboss.jbossts.star.resource.Transaction.afterCompletion()
scRes = status.length() == 0 ? HttpURLConnection.HTTP_INTERNAL_ERROR : HttpURLConnection.HTTP_OK;
return Response.status(scRes).entity(TxSupport.toStatusContent(status)).build();
}
use of org.jboss.jbossts.star.resource.Transaction in project narayana by jbosstm.
the class Coordinator method enlistParticipant.
/**
* Register a participant in a tx
* @param linkHeader link header
* @param info URI info
* @param txId id of transaction
* @param content body of request containing URI for driving the participant through completion
* (the URI should be unique within the scope of txId)
* @return unique resource ref for the participant
*/
@POST
@Path(TxSupport.TX_SEGMENT + "{TxId}")
public Response enlistParticipant(@HeaderParam("Link") String linkHeader, @Context UriInfo info, @PathParam("TxId") String txId, String content) {
log.tracef("enlistParticipant request uri %s txid: %s Link: %s content: %s", info.getRequestUri(), txId, linkHeader != null ? linkHeader : "null", content != null ? content : "null");
Transaction tx = getTransaction(txId);
/*
* If the transaction is not TransactionActive then the implementation MUST return a 412 status
* code
*/
if (!tx.isRunning())
return Response.status(HttpURLConnection.HTTP_PRECON_FAILED).build();
Map<String, String> links = TxSupport.decodeLinkHeader(linkHeader);
if (links.containsKey(TxLinkNames.VOLATILE_PARTICIPANT))
tx.addVolatileParticipant(links.get(TxLinkNames.VOLATILE_PARTICIPANT));
String participantURI = links.get(TxLinkNames.PARTICIPANT_RESOURCE);
String terminatorURI = links.get(TxLinkNames.PARTICIPANT_TERMINATOR);
if (participantURI == null)
return Response.status(HttpURLConnection.HTTP_BAD_REQUEST).entity("Missing Enlistment Link Header").build();
String txURI = TxSupport.buildURI(info.getBaseUriBuilder(), info.getPathSegments().get(0).getPath(), info.getPathSegments().get(1).getPath());
UriBuilder builder = info.getBaseUriBuilder();
String recoveryUrlBase = builder.path(info.getPathSegments().get(0).getPath()).path(RC_SEGMENT).build().toString() + '/';
String coordinatorId;
if (tx.isEnlisted(participantURI))
return Response.status(HttpURLConnection.HTTP_BAD_REQUEST).entity("participant is already enlisted").build();
if (terminatorURI == null) {
String commitURI = links.get(TxLinkNames.PARTICIPANT_COMMIT);
String prepareURI = links.get(TxLinkNames.PARTICIPANT_PREPARE);
String rollbackURI = links.get(TxLinkNames.PARTICIPANT_ROLLBACK);
String commitOnePhaseURI = links.get(TxLinkNames.PARTICIPANT_COMMIT_ONE_PHASE);
if (commitURI == null || prepareURI == null || rollbackURI == null)
return Response.status(HttpURLConnection.HTTP_BAD_REQUEST).entity("Missing TwoPhaseUnawareLink Header").build();
coordinatorId = tx.enlistParticipant(txURI, participantURI, recoveryUrlBase, commitURI, prepareURI, rollbackURI, commitOnePhaseURI);
} else {
coordinatorId = tx.enlistParticipant(txURI, participantURI, recoveryUrlBase, terminatorURI);
}
if (// the request was rejected (2PC processing must have started)
coordinatorId == null)
return Response.status(HttpURLConnection.HTTP_FORBIDDEN).entity("2PC has started").build();
links.put(TxLinkNames.PARTICIPANT_RECOVERY, tx.getRecoveryUrl());
links.put(TxLinkNames.TRANSACTION, txId);
participants.put(coordinatorId, new HashMap<String, String>(links));
log.debug("enlisted participant: content=" + content + " in tx " + txId + " Coordinator url base: " + recoveryUrlBase);
return Response.created(URI.create(tx.getRecoveryUrl())).build();
}
use of org.jboss.jbossts.star.resource.Transaction in project narayana by jbosstm.
the class Coordinator method replaceParticipant.
/**
* PUT /recovery-coordinator/_RecCoordId_/_new participant URL_ -
* overwrite the old participant URL with new participant URL
* (as with JTS, this will also trigger off a recovery attempt on the associated transaction)
* A participant may use this url to notifiy the coordinator that he has moved to a new location.
*
* @param linkHeader link header containing participant links
* @param txId transaction id that this recovery url belongs to
* @param enlistmentId id by the participant is known
* @return http status code
*/
@PUT
@Path(RC_SEGMENT + "/{TxId}/{RecCoordId}")
public Response replaceParticipant(@HeaderParam("Link") String linkHeader, @PathParam("TxId") String txId, @PathParam("RecCoordId") String enlistmentId) {
Map<String, String> links = TxSupport.decodeLinkHeader(linkHeader);
String terminatorUrl = links.get(TxLinkNames.PARTICIPANT_TERMINATOR);
String participantUrl = links.get(TxLinkNames.PARTICIPANT_RESOURCE);
if (participantUrl == null)
return Response.status(HttpURLConnection.HTTP_BAD_REQUEST).entity("Missing Link Header").build();
log.tracef("coordinator: replace: recovery-coordinator/%s?URL=%s", enlistmentId, terminatorUrl);
// check whether the transaction or log still exists
// throws not found exception if the txn has finished
Transaction tx = getTransaction(txId);
links.put(TxLinkNames.TRANSACTION, txId);
links.put(TxLinkNames.PARTICIPANT_RECOVERY, tx.getRecoveryUrl());
participants.put(enlistmentId, new HashMap<String, String>(links));
return Response.status(HttpURLConnection.HTTP_OK).build();
}
use of org.jboss.jbossts.star.resource.Transaction in project narayana by jbosstm.
the class Coordinator method enlistVolatileParticipant.
/**
* Register a volatile participant in a tx
*
* @param linkHeader link header
* @param info URI info
* @param txId id of transaction
* @return HTTP status code
*/
@PUT
@Path(TxSupport.TX_SEGMENT + "{TxId}/" + TxLinkNames.VOLATILE_PARTICIPANT)
public Response enlistVolatileParticipant(@HeaderParam("Link") String linkHeader, @Context UriInfo info, @PathParam("TxId") String txId) {
log.tracef("enlistParticipant request uri %s txid: %s", info.getRequestUri(), txId);
Transaction tx = getTransaction(txId);
if (tx.isFinishing())
return Response.status(HttpURLConnection.HTTP_PRECON_FAILED).build();
Map<String, String> links = TxSupport.decodeLinkHeader(linkHeader);
String vparticipantURI = links.get(TxLinkNames.VOLATILE_PARTICIPANT);
if (vparticipantURI == null)
return Response.status(HttpURLConnection.HTTP_BAD_REQUEST).entity("Missing Enlistment Link Header").build();
tx.addVolatileParticipant(vparticipantURI);
return Response.ok().build();
}
use of org.jboss.jbossts.star.resource.Transaction in project narayana by jbosstm.
the class Coordinator method getTransactionExtStatus.
/**
* Performing a GET on the transaction URL with media type application/txstatusext+xml
* returns extended information about the transaction, such as its status,
* number of participants, and their individual URIs.
*
* @param info Request context
* @param id URL template parameter for the id of the transaction
* @return HTTP response representing extended transaction status information
*/
@GET
@Path(TxSupport.TX_SEGMENT + "{id}")
@Produces(TxMediaType.TX_STATUS_EXT_MEDIA_TYPE)
public Response getTransactionExtStatus(@Context UriInfo info, @PathParam("id") String id) {
log.tracef("coordinator: status: transaction-coordinator/%s", id);
Transaction txn = getTransaction(id);
String terminator = TxLinkNames.TERMINATOR;
Collection<String> enlistmentIds = new ArrayList<String>();
CoordinatorElement coordinatorElement = txn.toXML();
String txnURI = TxSupport.getUri(info, info.getPathSegments().size()).toASCIIString();
URI terminateURI = TxSupport.getUri(info, info.getPathSegments().size(), terminator);
URI volatileURI = TxSupport.getUri(info, info.getPathSegments().size(), TxLinkNames.VOLATILE_PARTICIPANT);
coordinatorElement.setTxnURI(txnURI);
coordinatorElement.setTerminateURI(terminateURI.toASCIIString());
coordinatorElement.setDurableParticipantEnlistmentURI(txnURI);
coordinatorElement.setVolatileParticipantEnlistmentURI(volatileURI.toASCIIString());
txn.getParticipants(enlistmentIds);
for (String enlistmentId : enlistmentIds) {
Map<String, String> participantInfo = participants.get(enlistmentId);
String terminatorURI = participantInfo.get(TxLinkNames.PARTICIPANT_TERMINATOR);
String participantURI = participantInfo.get(TxLinkNames.PARTICIPANT_RESOURCE);
String recoveryURI = participantInfo.get(TxLinkNames.PARTICIPANT_RECOVERY);
TwoPhaseAwareParticipantElement participantElement = new TwoPhaseAwareParticipantElement();
participantElement.setTerminatorURI(terminatorURI);
participantElement.setRecoveryURI(recoveryURI);
participantElement.setResourceURI(participantURI);
txn.getStatus(participantElement, participantURI);
coordinatorElement.addTwoPhaseAware(participantElement);
}
return addTransactionHeaders(Response.ok(coordinatorElement), info, txn, false).build();
}
Aggregations