Search in sources :

Example 21 with APIResponses

use of org.eclipse.microprofile.openapi.annotations.responses.APIResponses in project narayana by jbosstm.

the class RecoveryCoordinator method deleteFailedLRA.

@DELETE
@Path("{LraId}")
@Operation(summary = "Remove the log for a failed LRA")
@APIResponses({ @APIResponse(responseCode = "204", description = "If the LRA log was successfully removed"), @APIResponse(responseCode = "412", description = "If the LRA is not in an end state (in which case the response " + "entity will indicate the current state at the time of the request)"), @APIResponse(responseCode = "412", description = "If the input LRA does not correspond to a valid URI (in which case the " + "response entity will contain the error message)"), @APIResponse(responseCode = "500", description = "If the attempt to remove the LRA log failed. This return code does not " + "discriminate between a failure at the log storage level or if the log did not exist)") })
public Response deleteFailedLRA(@Parameter(name = "LraId", description = "The unique identifier of the LRA", required = true) @PathParam("LraId") String lraId) throws NotFoundException {
    URI lra;
    try {
        lra = new URI(lraId);
        // verify that the LRA is not still being processed
        // will throw NotFoundException if it's unknown (to be caught and processed in the catch block)
        LRAData lraData = lraService.getLRA(lra);
        LRAStatus status = lraData.getStatus();
        // 412 the LRA is not in an end state (return 412 and the actual status of the LRA)
        if (status == LRAStatus.FailedToCancel || status == LRAStatus.FailedToClose) {
            return removeLog(lraId);
        }
        return Response.status(PRECONDITION_FAILED).entity(lraData.getStatus().name()).build();
    } catch (NotFoundException e) {
        // the LRA has finished and, if it corresponds to a failure record, it is safe to delete it
        return removeLog(lraId);
    } catch (URISyntaxException e) {
        // 412 the user provided URI was invalid
        if (LRALogger.logger.isDebugEnabled()) {
            LRALogger.logger.debugf("%s#deleteLRA: %s: %s", getClass().getCanonicalName(), lraId, e.getMessage());
        }
        return Response.status(PRECONDITION_FAILED).entity(String.format("%s: %s", lraId, e.getMessage())).build();
    }
}
Also used : LRAStatus(org.eclipse.microprofile.lra.annotation.LRAStatus) NotFoundException(javax.ws.rs.NotFoundException) URISyntaxException(java.net.URISyntaxException) URI(java.net.URI) LRAData(io.narayana.lra.LRAData) Path(javax.ws.rs.Path) DELETE(javax.ws.rs.DELETE) APIResponses(org.eclipse.microprofile.openapi.annotations.responses.APIResponses) Operation(org.eclipse.microprofile.openapi.annotations.Operation)

Example 22 with APIResponses

use of org.eclipse.microprofile.openapi.annotations.responses.APIResponses in project narayana by jbosstm.

the class Coordinator method startLRA.

/**
 * Performing a POST on {@value LRAConstants#COORDINATOR_PATH_NAME}/start?ClientID=<ClientID>
 * will start a new lra with a default timeout and return an LRA URL
 * of the form <coordinator url>/{@value LRAConstants#COORDINATOR_PATH_NAME}/<LraId>.
 * Adding a query parameter, {@value LRAConstants#TIMELIMIT_PARAM_NAME}=<timeout>, will start a new lra with the specified timeout.
 * If the lra is terminated because of a timeout, the lra URL is deleted and all further invocations on the URL will return 404.
 * The invoker can assume this was equivalent to a compensate operation.
 */
@POST
@Path("start")
@Produces(MediaType.TEXT_PLAIN)
@Bulkhead
@Operation(summary = "Start a new LRA", description = "The LRA model uses a presumed nothing protocol: the coordinator must communicate " + "with Compensators in order to inform them of the LRA activity. Every time a " + "Compensator is enrolled with an LRA, the coordinator must make information about " + "it durable so that the Compensator can be contacted when the LRA terminates, " + "even in the event of subsequent failures. Compensators, clients and coordinators " + "cannot make any presumption about the state of the global transaction without " + "consulting the coordinator and all compensators, respectively.")
@APIResponses({ @APIResponse(responseCode = "201", description = "The request was successful and the response body contains the id of the new LRA", content = @Content(schema = @Schema(description = "An URI of the new LRA", implementation = String.class)), headers = { @Header(ref = LRAConstants.NARAYANA_LRA_API_VERSION_HEADER_NAME) }), @APIResponse(responseCode = "404", description = "Parent LRA id cannot be joint to the started LRA", content = @Content(schema = @Schema(description = "Message containing problematic LRA id", implementation = String.class))), @APIResponse(responseCode = "417", description = "The requested version provided in HTTP Header is not supported by this end point", content = @Content(schema = @Schema(implementation = String.class))), @APIResponse(responseCode = "500", description = "A new LRA could not be started. Coordinator internal error.", content = @Content(schema = @Schema(implementation = String.class))) })
public Response startLRA(@Parameter(name = CLIENT_ID_PARAM_NAME, description = "Each client is expected to have a unique identity (which can be a URL).", required = true) @QueryParam(CLIENT_ID_PARAM_NAME) @DefaultValue("") String clientId, @Parameter(name = TIMELIMIT_PARAM_NAME, description = "Specifies the maximum time in milli seconds that the LRA will exist for.\n" + "If the LRA is terminated because of a timeout, the LRA URL is deleted.\n" + "All further invocations on the URL will return 404.\n" + "The invoker can assume this was equivalent to a compensate operation.") @QueryParam(TIMELIMIT_PARAM_NAME) @DefaultValue("0") Long timelimit, @Parameter(name = PARENT_LRA_PARAM_NAME, description = "The enclosing LRA if this new LRA is nested") @QueryParam(PARENT_LRA_PARAM_NAME) @DefaultValue("") String parentLRA, @Parameter(ref = LRAConstants.NARAYANA_LRA_API_VERSION_HEADER_NAME) @HeaderParam(LRAConstants.NARAYANA_LRA_API_VERSION_HEADER_NAME) @DefaultValue(CURRENT_API_VERSION_STRING) String version) throws WebApplicationException {
    URI parentId = (parentLRA == null || parentLRA.trim().isEmpty()) ? null : toURI(parentLRA);
    String coordinatorUrl = String.format("%s%s", context.getBaseUri(), COORDINATOR_PATH_NAME);
    LongRunningAction lra = lraService.startLRA(coordinatorUrl, parentId, clientId, timelimit);
    URI lraId = lra.getId();
    if (parentId != null) {
        // the startLRA call will have imported the parent LRA
        String compensatorUrl = String.format("%s/nested/%s", coordinatorUrl, LRAConstants.getLRAUid(lraId));
        if (!lraService.hasTransaction(parentId)) {
            Client client = null;
            Response response = null;
            try {
                client = ClientBuilder.newClient();
                response = client.target(parentId).request().header(NARAYANA_LRA_API_VERSION_HEADER_NAME, CURRENT_API_VERSION_STRING).async().put(Entity.text(compensatorUrl)).get(PARTICIPANT_TIMEOUT, TimeUnit.SECONDS);
                if (response.getStatus() != Response.Status.OK.getStatusCode()) {
                    String errMessage = String.format("The coordinator at %s returned an unexpected response: %d" + "when the LRA '%s' tried to join the parent LRA '%s'", parentId, response.getStatus(), lraId, parentLRA);
                    return Response.status(response.getStatus()).entity(errMessage).build();
                }
            } catch (Exception e) {
                String errorMsg = String.format("Cannot contact the LRA Coordinator at '%s' for LRA '%s' joining parent LRA '%s'", parentId, lraId, parentLRA);
                LRALogger.logger.debugf(errorMsg);
                throw new WebApplicationException(errorMsg, e, Response.status(INTERNAL_SERVER_ERROR).header(NARAYANA_LRA_API_VERSION_HEADER_NAME, version).entity(errorMsg).build());
            } finally {
                if (client != null) {
                    client.close();
                }
            }
        }
    }
    Current.push(lraId);
    return Response.created(lraId).entity(lraId).header(LRA_HTTP_CONTEXT_HEADER, Current.getContexts()).header(NARAYANA_LRA_API_VERSION_HEADER_NAME, version).build();
}
Also used : APIResponse(org.eclipse.microprofile.openapi.annotations.responses.APIResponse) Response(javax.ws.rs.core.Response) WebApplicationException(javax.ws.rs.WebApplicationException) Client(javax.ws.rs.client.Client) URI(java.net.URI) URISyntaxException(java.net.URISyntaxException) NotFoundException(javax.ws.rs.NotFoundException) WebApplicationException(javax.ws.rs.WebApplicationException) MalformedURLException(java.net.MalformedURLException) LongRunningAction(io.narayana.lra.coordinator.domain.model.LongRunningAction) Path(javax.ws.rs.Path) Bulkhead(org.eclipse.microprofile.faulttolerance.Bulkhead) POST(javax.ws.rs.POST) Produces(javax.ws.rs.Produces) APIResponses(org.eclipse.microprofile.openapi.annotations.responses.APIResponses) Operation(org.eclipse.microprofile.openapi.annotations.Operation)

Example 23 with APIResponses

use of org.eclipse.microprofile.openapi.annotations.responses.APIResponses 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)
@Operation(summary = "Update the endpoint that a participant is prepared to accept requests on.", description = "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.")
@APIResponses({ @APIResponse(responseCode = "404", description = "The coordinator has no knowledge of this participant"), @APIResponse(responseCode = "200", description = "The coordinator has replaced the old participant with the new one") })
public String replaceCompensator(@Parameter(name = "LRAId", description = "Identifies the LRAId that the participant joined", required = true) @PathParam("LRAId") String lraId, @Parameter(name = "RecCoordId", description = "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) {
        URI lra = null;
        try {
            lra = new URI(lraId);
        } catch (URISyntaxException e) {
            LRALogger.i18nLogger.error_invalidFormatOfLraIdReplacingCompensatorURI(lraId, compensatorUrl, e);
            String errMsg = String.format("%s: %s", lraId, e.getMessage());
            throw new WebApplicationException(errMsg, e, Response.status(INTERNAL_SERVER_ERROR.getStatusCode()).entity(errMsg).build());
        }
        lraService.updateRecoveryURI(lra, newCompensatorUrl, rcvCoordId, true);
        return context.getRequestUri().toASCIIString();
    }
    String errorMsg = LRALogger.i18nLogger.warn_cannotFoundCompensatorUrl(rcvCoordId, lraId);
    LRALogger.logger.warn(errorMsg);
    throw new NotFoundException(errorMsg, Response.status(NOT_FOUND).entity(errorMsg).build());
}
Also used : WebApplicationException(javax.ws.rs.WebApplicationException) NotFoundException(javax.ws.rs.NotFoundException) URISyntaxException(java.net.URISyntaxException) URI(java.net.URI) Path(javax.ws.rs.Path) Produces(javax.ws.rs.Produces) APIResponses(org.eclipse.microprofile.openapi.annotations.responses.APIResponses) Operation(org.eclipse.microprofile.openapi.annotations.Operation) PUT(javax.ws.rs.PUT)

Example 24 with APIResponses

use of org.eclipse.microprofile.openapi.annotations.responses.APIResponses in project automatiko-engine by automatiko-io.

the class $Type$Resource method add_tag_$name$.

@APIResponses(value = { @APIResponse(responseCode = "500", description = "In case of processing errors", content = @Content(mediaType = "application/json")), @APIResponse(responseCode = "404", description = "In case of instance with given id was not found", content = @Content(mediaType = "application/json")), @APIResponse(responseCode = "403", description = "In case of instance with given id is not accessible to the caller", content = @Content(mediaType = "application/json")), @APIResponse(responseCode = "200", description = "Successfully added TagInstance to the instance", content = @Content(mediaType = "application/json", schema = @Schema(implementation = TagInstance.class, type = SchemaType.ARRAY))) })
@Operation(summary = "Adds new TagInstance to $name$ instance with given id")
@POST()
@Path("/{id}/tags")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public Collection<? extends Tag> add_tag_$name$(@PathParam("id") @Parameter(description = "Unique identifier of the instance", required = true) String id, @Parameter(description = "User identifier as alternative autroization info", required = false, hidden = true) @QueryParam("user") final String user, @Parameter(description = "Groups as alternative autroization info", required = false, hidden = true) @QueryParam("group") final List<String> groups, @Parameter(description = "TagInstance content that should be associated with the $name$ instance", required = true) TagInstance resource) {
    identitySupplier.buildIdentityProvider(user, groups);
    return io.automatiko.engine.services.uow.UnitOfWorkExecutor.executeInUnitOfWork(application.unitOfWorkManager(), () -> {
        ProcessInstance<$Type$> pi = process.instances().findById(id).orElseThrow(() -> new ProcessInstanceNotFoundException(id));
        tracing(pi);
        pi.tags().add(resource.getValue());
        return pi.tags().get();
    });
}
Also used : ProcessInstanceNotFoundException(io.automatiko.engine.api.workflow.ProcessInstanceNotFoundException) Path(javax.ws.rs.Path) POST(javax.ws.rs.POST) Consumes(javax.ws.rs.Consumes) Produces(javax.ws.rs.Produces) APIResponses(org.eclipse.microprofile.openapi.annotations.responses.APIResponses) Operation(org.eclipse.microprofile.openapi.annotations.Operation)

Example 25 with APIResponses

use of org.eclipse.microprofile.openapi.annotations.responses.APIResponses in project automatiko-engine by automatiko-io.

the class UserTaskManagementResource method get.

@APIResponses(value = { @APIResponse(responseCode = "404", description = "In case of instance with given id was not found", content = @Content(mediaType = "text/html")), @APIResponse(responseCode = "200", description = "List of available processes", content = @Content(mediaType = "text/html")) })
@Operation(summary = "Retrives user task form for given user task", operationId = "getUserTaskForm")
@SuppressWarnings("unchecked")
@GET
@Path("{processId}/{pInstanceId}/{taskId}")
@Produces(MediaType.TEXT_HTML)
public TemplateInstance get(@Context UriInfo uriInfo, @Parameter(description = "Unique identifier of the process", required = true) @PathParam("processId") String processId, @Parameter(description = "Unique identifier of the instance", required = true) @PathParam("pInstanceId") String pInstanceId, @Parameter(description = "Unique identifier of the task", required = true) @PathParam("taskId") String taskId, @Parameter(description = "User identifier as alternative autroization info", required = false, hidden = true) @QueryParam("user") final String user, @Parameter(description = "Groups as alternative autroization info", required = false, hidden = true) @QueryParam("group") final List<String> groups) {
    IdentityProvider identityProvider = identitySupplier.buildIdentityProvider(user, groups);
    try {
        Process<?> process = processData.get(processId);
        if (process == null) {
            return getTemplate("process-not-found", PROCESS_INSTANCE_NOT_FOUND).instance().data("instanceId", pInstanceId);
        }
        Optional<ProcessInstance<?>> instance = (Optional<ProcessInstance<?>>) process.instances().findById(pInstanceId, ProcessInstanceReadMode.READ_ONLY);
        if (instance.isEmpty()) {
            return getTemplate("process-instance-not-found", PROCESS_INSTANCE_NOT_FOUND).instance().data("instanceId", pInstanceId);
        }
        ProcessInstance<?> pi = instance.get();
        WorkItem task = pi.workItem(taskId, SecurityPolicy.of(identityProvider));
        Template template = getTemplate(process.id(), task);
        if (template == null) {
            template = engine.getTemplate(DEFAULT_TEMPLATE);
        }
        String link = task.getReferenceId() + "?redirect=true";
        if (user != null && !user.isEmpty()) {
            link += "&user=" + user;
        }
        if (groups != null && !groups.isEmpty()) {
            for (String group : groups) {
                link += "&group=" + group;
            }
        }
        TemplateInstance templateInstance = template.data("task", task).data("url", new RawString(link));
        templateInstance.data("inputs", process.taskInputs(task.getId(), task.getName(), task.getParameters()));
        Map<String, Object> results = task.getResults();
        task.getParameters().entrySet().stream().forEach(e -> results.putIfAbsent(e.getKey(), e.getValue()));
        templateInstance.data("results", process.taskOutputs(task.getId(), task.getName(), results));
        return templateInstance;
    } catch (WorkItemNotFoundException e) {
        return getTemplate("task-not-found", TASK_INSTANCE_NOT_FOUND).instance().data("taskId", taskId);
    } finally {
        IdentityProvider.set(null);
    }
}
Also used : Optional(java.util.Optional) RawString(io.quarkus.qute.RawString) IdentityProvider(io.automatiko.engine.api.auth.IdentityProvider) RawString(io.quarkus.qute.RawString) WorkItem(io.automatiko.engine.api.workflow.WorkItem) Template(io.quarkus.qute.Template) TemplateInstance(io.quarkus.qute.TemplateInstance) WorkItemNotFoundException(io.automatiko.engine.api.runtime.process.WorkItemNotFoundException) ProcessInstance(io.automatiko.engine.api.workflow.ProcessInstance) Path(javax.ws.rs.Path) Produces(javax.ws.rs.Produces) GET(javax.ws.rs.GET) APIResponses(org.eclipse.microprofile.openapi.annotations.responses.APIResponses) Operation(org.eclipse.microprofile.openapi.annotations.Operation)

Aggregations

APIResponses (org.eclipse.microprofile.openapi.annotations.responses.APIResponses)28 Operation (org.eclipse.microprofile.openapi.annotations.Operation)27 Path (javax.ws.rs.Path)25 Produces (javax.ws.rs.Produces)22 GET (javax.ws.rs.GET)15 ProcessInstanceNotFoundException (io.automatiko.engine.api.workflow.ProcessInstanceNotFoundException)8 POST (javax.ws.rs.POST)8 ProcessInstance (io.automatiko.engine.api.workflow.ProcessInstance)7 APIResponse (org.eclipse.microprofile.openapi.annotations.responses.APIResponse)7 AbstractProcessInstance (io.automatiko.engine.workflow.AbstractProcessInstance)6 Optional (java.util.Optional)6 DELETE (javax.ws.rs.DELETE)6 ResponseBuilder (javax.ws.rs.core.Response.ResponseBuilder)6 LogWith (dk.dbc.log.LogWith)5 JsonExportedProcessInstance (io.automatiko.engine.addons.process.management.model.JsonExportedProcessInstance)5 ArchivedProcessInstance (io.automatiko.engine.api.workflow.ArchivedProcessInstance)5 ProcessImageNotFoundException (io.automatiko.engine.api.workflow.ProcessImageNotFoundException)5 URI (java.net.URI)5 Consumes (javax.ws.rs.Consumes)5 WebApplicationException (javax.ws.rs.WebApplicationException)5