use of io.narayana.lra.client.IllegalLRAStateException in project narayana by jbosstm.
the class LRAService method endLRA.
public LRAStatus endLRA(URL lraId, boolean compensate, boolean fromHierarchy) {
lraTrace(lraId, "end LRA");
Transaction transaction = getTransaction(lraId);
if (!transaction.isActive() && !transaction.isRecovering() && transaction.isTopLevel())
throw new IllegalLRAStateException(lraId.toString(), "LRA is closing or closed", "endLRA");
transaction.end(compensate);
if (transaction.currentLRA() != null)
if (LRALogger.logger.isInfoEnabled())
LRALogger.logger.infof("LRAServicve.endLRA LRA %s ended but is still associated with %s%n", lraId, transaction.currentLRA().get_uid().fileStringForm());
finished(transaction, fromHierarchy);
if (transaction.isTopLevel()) {
// forget any nested LRAs
// instruct compensators to clean up
transaction.forgetAllParticipants();
}
return new LRAStatus(transaction);
}
use of io.narayana.lra.client.IllegalLRAStateException 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");
}
use of io.narayana.lra.client.IllegalLRAStateException in project narayana by jbosstm.
the class Coordinator method getNestedLRAStatus.
@GET
@Path("{NestedLraId}/status")
public Response getNestedLRAStatus(@PathParam("NestedLraId") String nestedLraId) {
if (!lraService.hasTransaction(nestedLraId)) {
// it must have compensated TODO maybe it's better to keep nested LRAs in separate collection
return Response.ok(CompensatorStatus.Compensated.name()).build();
}
Transaction lra = lraService.getTransaction(toURL(nestedLraId));
CompensatorStatus status = lra.getLRAStatus();
if (status == null || lra.getLRAStatus() == null) {
LRALogger.i18NLogger.error_cannotGetStatusOfNestedLra(nestedLraId, lra.getId());
throw new IllegalLRAStateException(nestedLraId, "The LRA is still active", "getNestedLRAStatus");
}
return Response.ok(lra.getLRAStatus().name()).build();
}
use of io.narayana.lra.client.IllegalLRAStateException in project narayana by jbosstm.
the class ActivityController method status.
/**
* Performing a GET on the participant URL will return the current status of the participant {@link CompensatorStatus}, or 404 if the participant is no longer present.
*/
@GET
@Path("/status")
@Produces(MediaType.APPLICATION_JSON)
@Status
@LRA(LRA.Type.NOT_SUPPORTED)
public Response status(@PathParam("LraUrl") String lraUrl, @HeaderParam(LRA_HTTP_HEADER) String lraId) throws NotFoundException {
String txId = NarayanaLRAClient.getLRAId(lraId);
Activity activity = activityService.getActivity(txId);
if (activity.status == null)
throw new IllegalLRAStateException(lraId, "LRA is not active", "getStatus");
if (activity.getAndDecrementAcceptCount() <= 0) {
if (activity.status == CompensatorStatus.Completing)
activity.status = CompensatorStatus.Completed;
else if (activity.status == CompensatorStatus.Compensating)
activity.status = CompensatorStatus.Compensated;
}
return Response.ok(activity.status.name()).build();
}
Aggregations