Search in sources :

Example 1 with SRA

use of io.narayana.sra.annotation.SRA in project narayana by jbosstm.

the class TripController method bookTrip.

/**
 * The quickstart scenario is:
 *
 * start LRA 1
 *   Book hotel
 *   start LRA 2
 *     start LRA 3
 *       Book flight option 1
 *     start LRA 4
 *       Book flight option 2
 *
 * @param hotelName hotel name
 * @param hotelGuests number of beds required
 * @param flightSeats number of people flying
 */
@POST
@Path("/book")
@Produces(MediaType.APPLICATION_JSON)
// delayClose because we want the LRA to be associated with a booking until the user confirms the booking
@SRA(value = SRA.Type.REQUIRED, delayCommit = true)
public Response bookTrip(@HeaderParam(SRA_HTTP_HEADER) String SRAId, @QueryParam(HotelController.HOTEL_NAME_PARAM) @DefaultValue("") String hotelName, @QueryParam(HotelController.HOTEL_BEDS_PARAM) @DefaultValue("1") Integer hotelGuests, @QueryParam(FlightController.FLIGHT_NUMBER_PARAM) @DefaultValue("") String flightNumber, @QueryParam(FlightController.ALT_FLIGHT_NUMBER_PARAM) @DefaultValue("") String altFlightNumber, @QueryParam(FlightController.FLIGHT_SEATS_PARAM) @DefaultValue("1") Integer flightSeats, @QueryParam("mstimeout") @DefaultValue("500") Long timeout) throws BookingException {
    Booking hotelBooking = bookHotel(hotelName, hotelGuests);
    Booking flightBooking1 = bookFlight(flightNumber, flightSeats);
    Booking flightBooking2 = bookFlight(altFlightNumber, flightSeats);
    Booking tripBooking = new Booking(SRAId, "Trip", hotelBooking, flightBooking1, flightBooking2);
    return Response.status(Response.Status.CREATED).entity(tripBooking).build();
}
Also used : Booking(io.narayana.sra.demo.model.Booking) Path(javax.ws.rs.Path) SRA(io.narayana.sra.annotation.SRA) POST(javax.ws.rs.POST) Produces(javax.ws.rs.Produces)

Example 2 with SRA

use of io.narayana.sra.annotation.SRA in project narayana by jbosstm.

the class ServerSRAFilter method filter.

// // TODO figure out how to disable the filters for the coordinator (they remove the
// private boolean isCoordinator() {
// return resourceInfo.getResourceClass().getName().equals("org.jboss.narayana.rts.lra.coordinator.io.narayana.sra.demo.api.Coordinator")
// }
@Override
public void filter(ContainerRequestContext containerRequestContext) throws IOException {
    Method method = resourceInfo.getResourceMethod();
    MultivaluedMap<String, String> headers = containerRequestContext.getHeaders();
    SRA.Type type = null;
    Annotation transactional = method.getDeclaredAnnotation(SRA.class);
    URL lraId;
    URL newLRA = null;
    URL suspendedLRA = null;
    URL incommingLRA = null;
    String recoveryUrl = null;
    boolean isLongRunning = false;
    if (transactional == null)
        transactional = method.getDeclaringClass().getDeclaredAnnotation(SRA.class);
    if (transactional != null) {
        type = ((SRA) transactional).value();
        // ((Transactional) transactional).delayClose();
        isLongRunning = false;
        // TODO((Transactional) transactional).cancelOnFamily();
        Response.Status.Family[] cancel0nFamily = { Response.Status.Family.SERVER_ERROR };
        // TODO((Transactional) transactional).cancelOn();
        Response.Status[] cancel0n = {};
        if (cancel0nFamily.length != 0)
            containerRequestContext.setProperty(CANCEL_ON_FAMILY_PROP, cancel0nFamily);
        if (cancel0n.length != 0)
            containerRequestContext.setProperty(CANCEL_ON_PROP, cancel0n);
    }
    if (type == null) {
        Current.clearContext(headers);
        // not transactional
        return;
    }
    boolean enlist = true;
    boolean endAnnotation = method.isAnnotationPresent(Commit.class) || method.isAnnotationPresent(Prepare.class) || method.isAnnotationPresent(OnePhaseCommit.class);
    if (headers.containsKey(SRA_HTTP_HEADER))
        // TODO filters for asynchronous JAX-RS motheods should not throw exceptions
        incommingLRA = new URL(headers.getFirst(SRA_HTTP_HEADER));
    if (endAnnotation && incommingLRA == null) {
        return;
    }
    switch(type) {
        case // a txn must be present
        MANDATORY:
            checkForTx(type, incommingLRA, true);
            lraId = incommingLRA;
            // txId is not null
            resumeTransaction(incommingLRA);
            break;
        case // a txn must not be present
        NEVER:
            checkForTx(type, incommingLRA, false);
            enlist = false;
            lraId = null;
            break;
        case NOT_SUPPORTED:
            // suspend any currently active transaction
            // previous = AtomicAction.suspend();
            enlist = false;
            suspendedLRA = incommingLRA;
            lraId = null;
            break;
        case REQUIRED:
            if (incommingLRA != null) {
                lraId = incommingLRA;
                resumeTransaction(incommingLRA);
            } else {
                lraTrace(containerRequestContext, null, "ServerLRAFilter before: REQUIRED start new LRA");
                newLRA = lraId = startLRA(null, method, getTimeOut(method));
            }
            break;
        case REQUIRES_NEW:
            // previous = AtomicAction.suspend();
            suspendedLRA = incommingLRA;
            lraTrace(containerRequestContext, suspendedLRA, "ServerLRAFilter before: REQUIRES_NEW start new LRA");
            newLRA = lraId = startLRA(incommingLRA, method, getTimeOut(method));
            break;
        case SUPPORTS:
            lraId = incommingLRA;
            if (incommingLRA != null) {
                resumeTransaction(incommingLRA);
            }
            break;
        default:
            lraId = incommingLRA;
    }
    if (lraId == null) {
        lraTrace(containerRequestContext, lraId, "ServerLRAFilter before: removing header");
        // the method call needs to run without a transaction
        Current.clearContext(headers);
        // non transactional
        return;
    } else {
        lraTrace(containerRequestContext, lraId, "ServerLRAFilter before: adding header");
    // headers.putSingle(LRA_HTTP_HEADER, lraId.toString());
    }
    if (isLongRunning)
        newLRA = null;
    // store state with the current thread. TODO for the async version use containerRequestContext.setProperty("lra", Current.peek());
    // make the current LRA available to the called method
    Current.updateLRAContext(lraId, headers);
    if (newLRA != null)
        Current.putState("newLRA", newLRA);
    lraTrace(containerRequestContext, lraId, "ServerLRAFilter before: making LRA available to injected SRAClient");
    // make the current LRA available to the called method
    lraClient.setCurrentSRA(lraId);
    // TODO make sure it is possible to do compensations inside a new LRA
    if (!endAnnotation && enlist) {
        // don't enlist for methods marked with Compensate, Complete or Leave
        URI baseUri = containerRequestContext.getUriInfo().getBaseUri();
        Map<String, String> terminateURIs = lraClient.getTerminationUris(resourceInfo.getResourceClass(), baseUri, true);
        String timeLimitStr = terminateURIs.get(SRAClient.TIMELIMIT_PARAM_NAME);
        long timeLimit = timeLimitStr == null ? SRAClient.DEFAULT_TIMEOUT_MILLIS : Long.valueOf(timeLimitStr);
        try {
            recoveryUrl = lraClient.joinSRAWithLinkHeader(lraId, timeLimit, terminateURIs.get("Link"));
        } catch (IllegalSRAStateException e) {
            lraTrace(containerRequestContext, lraId, "ServerLRAFilter before: aborting with " + e.getMessage());
            throw e;
        } catch (WebApplicationException e) {
            lraTrace(containerRequestContext, lraId, "ServerLRAFilter before: aborting with " + e.getMessage());
            throw new GenericSRAException(lraId, e.getResponse().getStatus(), e.getMessage(), e);
        }
        headers.putSingle(RTS_HTTP_RECOVERY_HEADER, recoveryUrl);
    }
    /*        if (method.isAnnotationPresent(Leave.class)) {
            // leave the LRA
            String compensatorId = getCompensatorId(lraId, containerRequestContext.getUriInfo().getBaseUri());

            lraTrace(containerRequestContext, lraId, "leaving LRA");
            lraClient.leaveLRA(lraId, compensatorId);

            // let the compensator know which lra he left by leaving the header intact
        }*/
    lraTrace(containerRequestContext, lraId, "ServerLRAFilter before: making LRA available as a thread local");
// FilterState.setCurrentLRA(new FilterState(lraId, newLRA, suspendedLRA, recoveryUrl));
}
Also used : Status(io.narayana.sra.annotation.Status) SRA(io.narayana.sra.annotation.SRA) WebApplicationException(javax.ws.rs.WebApplicationException) Method(java.lang.reflect.Method) URI(java.net.URI) Annotation(java.lang.annotation.Annotation) URL(java.net.URL) Response(javax.ws.rs.core.Response) OnePhaseCommit(io.narayana.sra.annotation.OnePhaseCommit)

Aggregations

SRA (io.narayana.sra.annotation.SRA)2 OnePhaseCommit (io.narayana.sra.annotation.OnePhaseCommit)1 Status (io.narayana.sra.annotation.Status)1 Booking (io.narayana.sra.demo.model.Booking)1 Annotation (java.lang.annotation.Annotation)1 Method (java.lang.reflect.Method)1 URI (java.net.URI)1 URL (java.net.URL)1 POST (javax.ws.rs.POST)1 Path (javax.ws.rs.Path)1 Produces (javax.ws.rs.Produces)1 WebApplicationException (javax.ws.rs.WebApplicationException)1 Response (javax.ws.rs.core.Response)1