Search in sources :

Example 1 with Transaction

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();
}
Also used : RecoveringTransaction(org.jboss.jbossts.star.resource.RecoveringTransaction) Transaction(org.jboss.jbossts.star.resource.Transaction)

Example 2 with Transaction

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();
}
Also used : RecoveringTransaction(org.jboss.jbossts.star.resource.RecoveringTransaction) Transaction(org.jboss.jbossts.star.resource.Transaction) UriBuilder(javax.ws.rs.core.UriBuilder)

Example 3 with Transaction

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();
}
Also used : RecoveringTransaction(org.jboss.jbossts.star.resource.RecoveringTransaction) Transaction(org.jboss.jbossts.star.resource.Transaction)

Example 4 with Transaction

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();
}
Also used : RecoveringTransaction(org.jboss.jbossts.star.resource.RecoveringTransaction) Transaction(org.jboss.jbossts.star.resource.Transaction)

Example 5 with Transaction

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();
}
Also used : RecoveringTransaction(org.jboss.jbossts.star.resource.RecoveringTransaction) Transaction(org.jboss.jbossts.star.resource.Transaction) URI(java.net.URI)

Aggregations

RecoveringTransaction (org.jboss.jbossts.star.resource.RecoveringTransaction)8 Transaction (org.jboss.jbossts.star.resource.Transaction)8 URI (java.net.URI)2 Response (javax.ws.rs.core.Response)2 UriBuilder (javax.ws.rs.core.UriBuilder)1 ResourceNotFoundException (org.jboss.jbossts.star.provider.ResourceNotFoundException)1 TransactionStatusException (org.jboss.jbossts.star.provider.TransactionStatusException)1