Skip to content

Commit

Permalink
issue35 Do not define JAX-RS annotations on @compensate methods
Browse files Browse the repository at this point in the history
resolves #35

Signed-off-by: xstefank <[email protected]>
  • Loading branch information
xstefank committed May 10, 2019
1 parent e71efb0 commit 430e04e
Show file tree
Hide file tree
Showing 14 changed files with 837 additions and 56 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,24 @@
* will be chosen). The spec makes no guarantees about when it will be invoked,
* just that is will eventually be called.
*
* The id of the currently running LRA can be obtained by inspecting the incoming
* JAX-RS headers. If this LRA is nested then the parent LRA MUST be present
* in the header with the name
* If the annotated method is a JAX-RS resource method the id of the currently
* running LRA can be obtained by inspecting the incoming JAX-RS headers. If
* this LRA is nested then the parent LRA MUST be present in the header with the name
* {@link org.eclipse.microprofile.lra.annotation.ws.rs.LRA#LRA_HTTP_PARENT_CONTEXT_HEADER}.
*
* If the annotated method is not a JAX-RS resource method the id of the currently
* running LRA can be obtained by adhering to a predefined method signature as
* defined in the LRA specification document. Similarly the method may determine
* whether or not it runs with a nested LRA by providing a parameter to hold the parent id.
* For example,
* <pre>
* <code>
* &#64;Compensate
* public void compensate(URI lraId, URI parentId) { ...}
* </code>
* </pre>
* would be a valid compensation method declaration.
*
* Note that, according to the state model {@link LRAStatus} once an LRA has been
* asked to cancel it is no longer possible to join with it as a participant.
* Therefore combining this annotation with an `@LRA` annotation that does not
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,25 @@
* If the annotation is present on more than one method then an arbitrary one
* will be chosen.
*
* The id of the currently running LRA can be obtained by inspecting the incoming
* JAX-RS headers. If this LRA is nested then the parent LRA MUST be present
* in the header with the name
* If the annotated method is a JAX-RS resource method the id of the currently
* running LRA can be obtained by inspecting the incoming JAX-RS headers. If
* this LRA is nested then the parent LRA MUST be present in the header with the name
* {@link org.eclipse.microprofile.lra.annotation.ws.rs.LRA#LRA_HTTP_PARENT_CONTEXT_HEADER}.
*
* If the annotated method is not a JAX-RS resource method the id of the currently
* running LRA can be obtained by adhering to a predefined method signature as
* defined in the LRA specification document. Similarly the method may determine
* whether or not it runs with a nested LRA by providing a parameter to hold the parent id.
* For example,
* <pre>
* <code>
* &#64;Complete
* public void complete(URI lraId, URI parentId) { ...}
* </code>
* </pre>
* would be a valid completion method declaration.
*
*
* Note that, according to the state model {@link LRAStatus} once an LRA has been
* asked to close it is no longer possible to join with it as a participant.
* Therefore combining this annotation with an `@LRA` annotation that does not
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,21 +33,33 @@
* in progress) or because of a failure (ie will never be able to finish)
* then it must remember the fact (by reporting it when asked for its'
* {@link Status})) until explicitly told that it can clean
* up using this <em>@Forget</em> annotation. The annotated method
* must be a standard JAX-RS endpoint annotated with the JAX-RS
* <em>@DELETE</em> annotation.
* up using this <em>@Forget</em> annotation.
*
* A similar remark applies if the participant was enlisted in a
* nested LRA {@link LRA#value()}. Actions performed in the context
* of a nested LRA must remain compensatable until the participant
* is explicitly told it can clean up using this <em>@Forget</em>
* annotation.
*
* The id of the currently running LRA can be obtained by inspecting the
* incoming JAX-RS headers. If this LRA is nested then the parent LRA
* MUST be present in the header with the name
* If the annotated method is a JAX-RS resource method the id of the currently
* running LRA can be obtained by inspecting the incoming JAX-RS headers. If
* this LRA is nested then the parent LRA MUST be present in the header with the name
* {@link org.eclipse.microprofile.lra.annotation.ws.rs.LRA#LRA_HTTP_PARENT_CONTEXT_HEADER}.
*
* If the annotated method is not a JAX-RS resource method the id of the currently
* running LRA can be obtained by adhering to a predefined method signature as
* defined in the LRA specification document. Similarly the method may determine
* whether or not it runs with a nested LRA by providing a parameter to hold the parent id.
* For example,
* <pre>
* <code>
* &#64;Forget
* public void forget(URI lraId, URI parentId) { ...}
* </code>
* </pre>
* would be a valid forget method declaration.
*
*
* Since the participant generally needs to know the id of the LRA in order
* to clean up there is generally no benefit to combining this annotation
* with the `@LRA` annotation (though it is not prohibited).
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,18 +36,33 @@
* or compensation notification but if the participant (the class that
* contains the Compensate and Complete annotations) does not
* support idempotency then it must be able to report its' status by
* by annotating one of the methods with this <em>@Status</em> annotation
* together with the <em>@GET</em> JAX-RS annotation.
* by annotating one of the methods with this <em>@Status</em>.
* The annotated method should report the status according to one of the
* {@link ParticipantStatus} enum values.
*
* If the annotated method is a JAX-RS resource method the id of the currently
* running LRA can be obtained by inspecting the incoming JAX-RS headers. If
* this LRA is nested then the parent LRA MUST be present in the header with the name
* {@link org.eclipse.microprofile.lra.annotation.ws.rs.LRA#LRA_HTTP_PARENT_CONTEXT_HEADER}.
*
* If the annotated method is not a JAX-RS resource method the id of the currently
* running LRA can be obtained by adhering to a predefined method signature as
* defined in the LRA specification document. Similarly the method may determine
* whether or not it runs with a nested LRA by providing a parameter to hold the parent id.
* For example,
* <pre>
* <code>
* &#64;Status
* public void status(URI lraId, URI parentId) { ...}
* </code>
* </pre>
* would be a valid status method declaration.
*
* If the participant has already responded successfully to an invocation
* of the <em>@Compensate</em> or <em>@Complete</em> method then it may
* report <em>404 Not Found</em> HTTP status code. This enables the
* participant to free up resources.
*
* The id of the currently running LRA can be obtained by inspecting the
* incoming JAX-RS headers.
* report <em>404 Not Found</em> HTTP status code or in case of
* non-JAX-RS method to return <em>null</em>.
* This enables the participant to free up resources.
*
* Since the participant generally needs to know the id of the LRA in order
* to report its status there is generally no benefit to combining this
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
*******************************************************************************
* Copyright (c) 2019 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*******************************************************************************/
package org.eclipse.microprofile.lra.participant;

/**
* Runtime exception thrown when invalid non-JAX-RS LRA signature definition is detected
*/
public class InvalidLRAParticipantDefinitionException extends RuntimeException {

public InvalidLRAParticipantDefinitionException(String message) {
super(message);
}

public InvalidLRAParticipantDefinitionException(String message, Throwable cause) {
super(message, cause);
}

public InvalidLRAParticipantDefinitionException(Throwable cause) {
super(cause);
}
}
175 changes: 146 additions & 29 deletions spec/src/main/asciidoc/microprofile-lra-spec.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -506,9 +506,9 @@ the method finishes and the `end = true` element on the confirmTrip method force
==== Compensating Activities

The application developer indicates which JAX-RS method to use for a compensating
activity by annotating it with both the `@Compensate` and the JAX-RS `@PUT` annotations.
activity by annotating it with the `@Compensate` annotation.
Whenever the associated resource is invoked in the context of
an LRA the endpoint corresponding to the `@Compensate` method MUST be enlisted with
an LRA the method corresponding to the `@Compensate` method MUST be enlisted with
the LRA. If the LRA is subsequently cancelled then the compensation method MUST be invoked.

The specification does not mandate when this method is invoked
Expand All @@ -530,17 +530,17 @@ An example of how to use this annoation is:
}
----

The resource class MAY also contain a method marked with the `@Complete` and the
JAX-RS `@PUT` annotations. If such a method is present then the method MUST
be invoked when the associated LRA is closed. Again, the specification does
not MANDATE when the method is called, just that it will eventually be invoked.
Typically the resource would use this call to perform any clean up actions. The
method is optional since such clean up actions may not be necessary,
for example consider a system that just tracks hotel reservations and has operations
for booking a room or cancelling the reservation (`@Compensate`). Since this system
is passive, once a room is booked, it does not make any difference if the LRA is
completed or not: the room will be unavailable for others. If it receives a call
to `@Compensate` then it will free the room. But it won't do anything on `@complete`.
The resource class MAY also contain a method marked with the `@Complete` annotation.
If such a method is present then the method MUST be invoked when the associated LRA
is closed. Again, the specification does not MANDATE when the method is called,
just that it will eventually be invoked. Typically the resource would use this call
to perform any clean up actions. The method is optional since such clean up actions
may not be necessary, for example consider a system that just tracks hotel reservations
and has operations for booking a room or cancelling the reservation (`@Compensate`).
Since this system is passive, once a room is booked, it does not make any difference
if the LRA is completed or not: the room will be unavailable for others. If it receives
a call to `@Compensate` then it will free the room. But it won't do anything on
`@Complete`.

If the participant successfully compensates or completes then it may forget about
the LRA. Otherwise it should remember that it is still associated with the LRA and
Expand All @@ -555,11 +555,143 @@ of these methods. If it knows it will never be able to compensate or complete th
it MUST remember the fact until explicitly told that it can clean up by providing
a method annotated with `@Forget` (the requirement is marked MUST because message
delivery is not guaranteed in a distributed system).
The forget method MUST be annotated with the JAX-RS `@DELETE` annotation.

If there is no `@Status` then the `@Compensate` or `@Complete` methods will continue
to be invoked until the implementation knows it has the final status.

If the `@Compensate` or `@Complete` annotation is present on multiple methods
then an arbitrary one is chosen.

The javadoc for the <<source-Compensate,Compensate annotation>> provides
more details about this annotation.

Similarly, the javadoc for the <<source-Complete,Complete annotation>>
provides details about the `@Complete` annotation.

==== Participant marker annotations method signatures

The participant marker annotations are annotations that allow users to mark a method
for the execution by the LRA implemenatation according to the <<participant-state-model,
the participant state model>>. These annotations are:

* `@Compensate` -- a method to be executed when the LRA is cancelled
* `@Complete` -- a method to be executed when the LRA is completed
* `@Status` -- a method that allow user to state status of the participant with regards
to a paricular LRA
* `@Forget` -- a method to be executed when the LRA allows participant to
clear all associated information

This specification is generally expected to be associated with the JAX-RS runtime. However,
we acknowledge that the mapping to JAX-RS resources may not always be feasible which is
why we distinguish two types of participant method definitions -- associated with the
JAX-RS resource method or not bound to JAX-RS.

[[jaxrs-participant-methods]]
===== JAX-RS participant methods

The following table presents expectations that are placed on individual participant
annotations when associated with JAX-RS resource methods:

[[jaxrs-response-table]]
|===
| Annotation | HTTP method | Expected status codes | Response

| `@Compensate`
| PUT
| 200, 202, 404, 412
| <<source-ParticipantStatus,ParticipantStatus>>

| `@Complete`
| PUT
| 200, 202, 404, 412
| <<source-ParticipantStatus,ParticipantStatus>>

| `@Status`
| GET
| 200, 202, 404, 412
| <<source-ParticipantStatus,ParticipantStatus>>

| `@Forget`
| DELETE
| 200, 404, 412
| no expectations

|===

If the participant annotation is not accompanied by an associated JAX-RS HTTP method
annotation according to the <<jaxrs-response-table,table above>>, the error SHOULD be reported using a JAX-RS
exception mapper that maps to a `412 Precondition Failed` HTTP status code.

[[non-jaxrs-participant-methods]]
===== Non-JAX-RS participant methods

When the participant annotations are applied to the non-JAX-RS resource methods they
MUST adhere to these predefined signatures:

* *Return type*:
** `void`: successfull execution is mapped to `Compensated` or `Completed` participant statuses,
error execution is handled by exception mapping
*** applicable only for `@Compensate` and `@Complete` participant methods
** <<source-ParticipantStatus,ParticipantStatus>>
** `javax.ws.rs.core.Response`: handled similarly as for
<<jaxrs-participant-methods, JAX-RS participant methods>>
** `java.util.concurrent.CompletionStage`: with the parameter of any of the previously
defined types
* *Arguments*: up to 2 arguments of types in this order:
** `java.net.URI`: representing current LRA context identification
** `java.net.URI`: representing potentional parent LRA context identification

Declaring more than two arguments, different types of arguments or different return type
for any non-JAX-RS method annotatated with the participant marker annotation MUST result
in the deployment time `InvalidLRAParticipantDefinitionException`.
Please note that both arguments are optional but the order is required.

Examples of valid signatures:

[source,java]
----
@Compensate
public void compensate(URI lraId, URI parentId)
@Complete
public Response complete(URI lraId)
@Status
public CompletionStage<ParticipantStatus> status(URI lraId)
----

Examples of invalid signatures:

[source,java]
----
@Compensate
public void compensate(String lraId, String parentId) // invalid types of arguments
@Compensate
public String compensate(URI lraId) // invalid return type
@Forget
public void forget(URI lraId, URI parentId, String additional) // too many arguments
----

If any of the described methods throws an exception, we distinguish two cases depending
on the exception type:

* `WebApplicationException` -- the exception is mapped to the HTTP response it carries
and then handled as defined in the section
<<jaxrs-participant-methods, JAX-RS participant methods>>
* *any other exception* results into `FailedToComplete` or `FailedToCompensate`
participant states


footnote:[issue #15 (Provide an annotation to supply opaque data during
participant registration) allows participants to register opaque data when
joining with an LRA. This data is made available to the completion and
compensation callbacks]

[[eventual-compensations]]
==== Eventual compensations

[[async-compensators]]
If the resource cannot perform a compensation activity
immediately the `@Compensate` method SHOULD do one or more of the following:
Expand All @@ -573,21 +705,6 @@ The `@Status` method, if present, MUST report the progress of the compensation.

Similarly if it cannot perform a completion activity immediately.

If the `@Compensate` or `@Complete` annotation is present on multiple methods
then an arbitrary one is chosen. If the annotation is not accompanied by
a JAX-RS `@PUT` annotation the error SHOULD be reported using a JAX-RS
exception mapper that maps to a `412 Precondition Failed` HTTP status code.

footnote:[issue #15 (Provide an annotation to supply opaque data during
participant registration) allows participants to register opaque data when
joining with an LRA. This data is made available to the completion and
compensation callbacks]

The javadoc for the <<source-Compensate,Compensate annotation>> provides
more details about this annotation.

Similarly, the javadoc for the <<source-Complete,Complete annotation>>
provides details about the `@Complete` annotation.

[[nesting-lras]]
==== Nesting LRAs
Expand Down
Loading

0 comments on commit 430e04e

Please sign in to comment.