Search in sources :

Example 1 with GenericLRAException

use of io.narayana.lra.client.GenericLRAException in project narayana by jbosstm.

the class RecoveryCoordinator method replaceCompensator.

// Performing a PUT on the recovery URL will overwrite the old <compensor URL> with the new one supplied
// and return the old url
@PUT
@Path("{LRAId}/{RecCoordId}")
@Produces(MediaType.APPLICATION_JSON)
@ApiOperation(value = "Update the endpoint that a participant is prepared to accept requests on.", notes = "Performing a PUT on the recovery URL will overwrite the old <compensor URL> with the new one supplied" + " and return the old url. The old value is returned." + "The full URL was returned when the participant first joined the LRA.", response = String.class)
@ApiResponses({ @ApiResponse(code = 404, message = "The coordinator has no knowledge of this participant"), @ApiResponse(code = 200, message = "The coordinator has replaced the old participant with the new one ") })
public String replaceCompensator(@ApiParam(value = "Identifies the LRAId that the participant joined", required = true) @PathParam("LRAId") String lraId, @ApiParam(value = "An identifier that was returned by the coordinator when a participant joined the LRA", required = true) @PathParam("RecCoordId") String rcvCoordId, String newCompensatorUrl) throws NotFoundException {
    String compensatorUrl = lraService.getParticipant(rcvCoordId);
    if (compensatorUrl != null) {
        URL lra = null;
        try {
            lra = new URL(lraId);
        } catch (MalformedURLException e) {
            LRALogger.i18NLogger.error_invalidFormatOfLraIdReplacingCompensator(lraId, compensatorUrl, e);
            throw new GenericLRAException(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e.getMessage(), e.getCause());
        }
        lraService.updateRecoveryURL(lra, newCompensatorUrl, rcvCoordId, true);
        try {
            return context.getRequestUri().toURL().toExternalForm();
        } catch (MalformedURLException e) {
            // cannot happen
            LRALogger.i18NLogger.error_invalidFormatOfRequestUri(context.getRequestUri(), lraId, compensatorUrl, e);
            throw new GenericLRAException(lra, Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e.getMessage(), e.getCause());
        }
    }
    LRALogger.i18NLogger.error_cannotFoundCompensatorUrl(compensatorUrl, lraId);
    throw new NotFoundException(rcvCoordId);
}
Also used : MalformedURLException(java.net.MalformedURLException) NotFoundException(javax.ws.rs.NotFoundException) GenericLRAException(io.narayana.lra.client.GenericLRAException) URL(java.net.URL) Path(javax.ws.rs.Path) Produces(javax.ws.rs.Produces) ApiOperation(io.swagger.annotations.ApiOperation) PUT(javax.ws.rs.PUT) ApiResponses(io.swagger.annotations.ApiResponses)

Example 2 with GenericLRAException

use of io.narayana.lra.client.GenericLRAException in project narayana by jbosstm.

the class ServerLRAFilter method filter.

// // TODO figure out how to disable the filters for the coordinator since they are required
// private boolean isCoordinator() {
// return resourceInfo.getResourceClass().getName().equals("io.narayana.lra.coordinator.api.Coordinator")
// }
@Override
public void filter(ContainerRequestContext containerRequestContext) throws IOException {
    Method method = resourceInfo.getResourceMethod();
    MultivaluedMap<String, String> headers = containerRequestContext.getHeaders();
    LRA.Type type = null;
    Annotation transactional = method.getDeclaredAnnotation(LRA.class);
    URL lraId;
    URL newLRA = null;
    URL suspendedLRA = null;
    URL incommingLRA = null;
    String recoveryUrl = null;
    boolean nested;
    boolean isLongRunning = false;
    boolean enlist;
    if (transactional == null)
        transactional = method.getDeclaringClass().getDeclaredAnnotation(LRA.class);
    if (transactional != null) {
        type = ((LRA) transactional).value();
        isLongRunning = ((LRA) transactional).delayClose();
        Response.Status.Family[] cancel0nFamily = ((LRA) transactional).cancelOnFamily();
        Response.Status[] cancel0n = ((LRA) transactional).cancelOn();
        if (((LRA) transactional).terminal())
            containerRequestContext.setProperty(TERMINAL_LRA_PROP, Boolean.TRUE);
        if (cancel0nFamily.length != 0)
            containerRequestContext.setProperty(CANCEL_ON_FAMILY_PROP, cancel0nFamily);
        if (cancel0n.length != 0)
            containerRequestContext.setProperty(CANCEL_ON_PROP, cancel0n);
    }
    boolean endAnnotation = method.isAnnotationPresent(Complete.class) || method.isAnnotationPresent(Compensate.class) || method.isAnnotationPresent(Leave.class) || method.isAnnotationPresent(Status.class) || method.isAnnotationPresent(Forget.class);
    if (type == null) {
        if (!endAnnotation)
            Current.clearContext(headers);
        // not transactional
        return;
    }
    if (headers.containsKey(LRA_HTTP_HEADER))
        // TODO filters for asynchronous JAX-RS motheods should not throw exceptions
        incommingLRA = new URL(headers.getFirst(LRA_HTTP_HEADER));
    if (endAnnotation && incommingLRA == null)
        return;
    enlist = ((LRA) transactional).join();
    nested = resourceInfo.getResourceMethod().isAnnotationPresent(NestedLRA.class);
    switch(type) {
        case // a txn must be present
        MANDATORY:
            checkForTx(type, incommingLRA, true);
            if (nested) {
                // a new LRA is nested under the incomming LRA
                suspendedLRA = incommingLRA;
                lraTrace(containerRequestContext, suspendedLRA, "ServerLRAFilter before: MANDATORY start new LRA");
                newLRA = lraId = startLRA(incommingLRA, method, getTimeOut(method));
            } else {
                lraId = incommingLRA;
                // txId is not null
                resumeTransaction(incommingLRA);
            }
            break;
        case // a txn must not be present
        NEVER:
            checkForTx(type, incommingLRA, false);
            if (nested) {
                // nested does not make sense
                throw new GenericLRAException(Response.Status.PRECONDITION_FAILED.getStatusCode(), type.name() + " but found Nested annnotation");
            }
            enlist = false;
            lraId = null;
            break;
        case NOT_SUPPORTED:
            if (nested) {
                // nested does not make sense
                throw new GenericLRAException(Response.Status.PRECONDITION_FAILED.getStatusCode(), type.name() + " but found Nested annnotation");
            }
            enlist = false;
            suspendedLRA = incommingLRA;
            lraId = null;
            break;
        case REQUIRED:
            if (incommingLRA != null) {
                if (nested) {
                    // if there is an LRA present nest a new LRA under it
                    suspendedLRA = incommingLRA;
                    lraTrace(containerRequestContext, suspendedLRA, "ServerLRAFilter before: REQUIRED start new LRA");
                    newLRA = lraId = startLRA(incommingLRA, method, getTimeOut(method));
                } else {
                    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 (nested) {
                // if there is an LRA present a new LRA is nested under it otherwise a new top level LRA is begun
                if (incommingLRA != null)
                    suspendedLRA = incommingLRA;
                lraTrace(containerRequestContext, incommingLRA, "ServerLRAFilter before: SUPPORTS start new LRA");
                newLRA = lraId = startLRA(incommingLRA, method, getTimeOut(method));
            } else if (incommingLRA != null) {
                resumeTransaction(incommingLRA);
            }
            break;
        default:
            lraId = incommingLRA;
    }
    if (lraId == null) {
        lraTrace(containerRequestContext, null, "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");
        if (lraId.toExternalForm().contains("recovery-coordi"))
            lraWarn(containerRequestContext, lraId, "wrong lra id");
    }
    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) {
        if (suspendedLRA != null)
            Current.putState("suspendedLRA", suspendedLRA);
        Current.putState("newLRA", newLRA);
    }
    lraTrace(containerRequestContext, lraId, "ServerLRAFilter before: making LRA available to injected LRAClient");
    // make the current LRA available to the called method
    lraClient.setCurrentLRA(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 = NarayanaLRAClient.getTerminationUris(resourceInfo.getResourceClass(), baseUri);
        String timeLimitStr = terminateURIs.get(NarayanaLRAClient.TIMELIMIT_PARAM_NAME);
        long timeLimit = timeLimitStr == null ? NarayanaLRAClient.DEFAULT_TIMEOUT_MILLIS : Long.valueOf(timeLimitStr);
        if (terminateURIs.containsKey("Link")) {
            try {
                recoveryUrl = lraClient.joinLRA(lraId, timeLimit, toURL(terminateURIs.get(COMPENSATE)), toURL(terminateURIs.get(COMPLETE)), toURL(terminateURIs.get(FORGET)), toURL(terminateURIs.get(LEAVE)), toURL(terminateURIs.get(STATUS)), null);
            } catch (IllegalLRAStateException 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 GenericLRAException(lraId, e.getResponse().getStatus(), e.getMessage(), e);
            }
            headers.putSingle(LRA_HTTP_RECOVERY_HEADER, recoveryUrl);
        } else {
            lraTrace(containerRequestContext, lraId, "ServerLRAFilter: skipping resource " + method.getDeclaringClass().getName() + " - no participant annotations");
        }
    }
    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 participant know which lra he left by leaving the header intact
    }
    lraTrace(containerRequestContext, lraId, "ServerLRAFilter before: making LRA available as a thread local");
}
Also used : Status(io.narayana.lra.annotation.Status) WebApplicationException(javax.ws.rs.WebApplicationException) Leave(io.narayana.lra.annotation.Leave) Forget(io.narayana.lra.annotation.Forget) NestedLRA(io.narayana.lra.annotation.NestedLRA) IllegalLRAStateException(io.narayana.lra.client.IllegalLRAStateException) Method(java.lang.reflect.Method) URI(java.net.URI) Annotation(java.lang.annotation.Annotation) URL(java.net.URL) Response(javax.ws.rs.core.Response) LRA(io.narayana.lra.annotation.LRA) NestedLRA(io.narayana.lra.annotation.NestedLRA) GenericLRAException(io.narayana.lra.client.GenericLRAException)

Example 3 with GenericLRAException

use of io.narayana.lra.client.GenericLRAException in project narayana by jbosstm.

the class Coordinator method joinLRA.

private Response joinLRA(URL lraId, long timeLimit, String compensatorUrl, String linkHeader, String userData) throws NotFoundException {
    final String recoveryUrlBase = String.format("http://%s/%s/", context.getRequestUri().getAuthority(), NarayanaLRAClient.RECOVERY_COORDINATOR_PATH_NAME);
    StringBuilder recoveryUrl = new StringBuilder();
    int status = lraService.joinLRA(recoveryUrl, lraId, timeLimit, compensatorUrl, linkHeader, recoveryUrlBase, userData);
    try {
        return Response.status(status).entity(recoveryUrl).location(new URI(recoveryUrl.toString())).header(LRA_HTTP_RECOVERY_HEADER, recoveryUrl).build();
    } catch (URISyntaxException e) {
        LRALogger.i18NLogger.error_invalidRecoveryUrlToJoinLRA(recoveryUrl.toString(), lraId);
        throw new GenericLRAException(lraId, Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), "Invalid recovery URL", e);
    }
}
Also used : URISyntaxException(java.net.URISyntaxException) GenericLRAException(io.narayana.lra.client.GenericLRAException) URI(java.net.URI)

Aggregations

GenericLRAException (io.narayana.lra.client.GenericLRAException)3 URI (java.net.URI)2 URL (java.net.URL)2 Forget (io.narayana.lra.annotation.Forget)1 LRA (io.narayana.lra.annotation.LRA)1 Leave (io.narayana.lra.annotation.Leave)1 NestedLRA (io.narayana.lra.annotation.NestedLRA)1 Status (io.narayana.lra.annotation.Status)1 IllegalLRAStateException (io.narayana.lra.client.IllegalLRAStateException)1 ApiOperation (io.swagger.annotations.ApiOperation)1 ApiResponses (io.swagger.annotations.ApiResponses)1 Annotation (java.lang.annotation.Annotation)1 Method (java.lang.reflect.Method)1 MalformedURLException (java.net.MalformedURLException)1 URISyntaxException (java.net.URISyntaxException)1 NotFoundException (javax.ws.rs.NotFoundException)1 PUT (javax.ws.rs.PUT)1 Path (javax.ws.rs.Path)1 Produces (javax.ws.rs.Produces)1 WebApplicationException (javax.ws.rs.WebApplicationException)1