You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@syncope.apache.org by il...@apache.org on 2018/02/16 15:28:59 UTC

[1/2] syncope git commit: [SYNCOPE-1274] Add documentation for ETag, If-Match

Repository: syncope
Updated Branches:
  refs/heads/2_0_X 66aac6a40 -> 2c7138b2f
  refs/heads/master 64bce59f3 -> b28705818


[SYNCOPE-1274] Add documentation for ETag, If-Match


Project: http://git-wip-us.apache.org/repos/asf/syncope/repo
Commit: http://git-wip-us.apache.org/repos/asf/syncope/commit/b2870581
Tree: http://git-wip-us.apache.org/repos/asf/syncope/tree/b2870581
Diff: http://git-wip-us.apache.org/repos/asf/syncope/diff/b2870581

Branch: refs/heads/master
Commit: b287058182150dd499e1439d03105e975a0e721b
Parents: 64bce59
Author: Francesco Chicchiriccò <il...@apache.org>
Authored: Fri Feb 16 15:36:50 2018 +0100
Committer: Francesco Chicchiriccò <il...@apache.org>
Committed: Fri Feb 16 16:27:00 2018 +0100

----------------------------------------------------------------------
 .../rest/api/service/AnyObjectService.java      | 28 ++++++-
 .../common/rest/api/service/AnyService.java     | 78 ++++++++++++++++++--
 .../common/rest/api/service/GroupService.java   | 28 ++++++-
 .../common/rest/api/service/UserService.java    | 47 ++++++++++--
 4 files changed, 166 insertions(+), 15 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/syncope/blob/b2870581/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/AnyObjectService.java
----------------------------------------------------------------------
diff --git a/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/AnyObjectService.java b/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/AnyObjectService.java
index a694adc..005cb67 100644
--- a/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/AnyObjectService.java
+++ b/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/AnyObjectService.java
@@ -55,6 +55,14 @@ import org.apache.syncope.common.rest.api.beans.AnyQuery;
 @Path("anyObjects")
 public interface AnyObjectService extends AnyService<AnyObjectTO> {
 
+    @ApiResponses(
+            @ApiResponse(responseCode = "200", description =
+                    "Any object matching the provided key; if value looks like a UUID then it is interpreted as key,"
+                    + " otherwise as a name.", headers =
+                    @Header(name = HttpHeaders.ETAG, schema =
+                            @Schema(type = "string"),
+                            description = "Opaque identifier for the latest modification made to the entity returned"
+                            + " by this endpoint")))
     @Override
     AnyObjectTO read(String key);
 
@@ -105,6 +113,11 @@ public interface AnyObjectService extends AnyService<AnyObjectTO> {
             description = "Allows client to specify a preference for the result to be returned from the server",
             allowEmptyValue = true, schema =
             @Schema(defaultValue = "return-content", allowableValues = { "return-content", "return-no-content" }))
+    @Parameter(name = HttpHeaders.IF_MATCH, in = ParameterIn.HEADER,
+            description = "When the provided ETag value does not match the latest modification date of the entity, "
+            + "an error is reported and the requested operation is not performed.",
+            allowEmptyValue = true, schema =
+            @Schema(type = "string"))
     @ApiResponses({
         @ApiResponse(responseCode = "200",
                 description = "Any object successfully updated enriched with propagation status information, as Entity",
@@ -116,7 +129,10 @@ public interface AnyObjectService extends AnyService<AnyObjectTO> {
                 @Header(name = RESTHeaders.PREFERENCE_APPLIED, schema =
                         @Schema(type = "string"),
                         description = "Allows the server to inform the "
-                        + "client about the fact that a specified preference was applied")) })
+                        + "client about the fact that a specified preference was applied"))
+        , @ApiResponse(responseCode = "412",
+                description = "The ETag value provided via the 'If-Match' header does not match the latest modification"
+                + " date of the entity") })
     @PATCH
     @Path("{key}")
     @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
@@ -133,6 +149,11 @@ public interface AnyObjectService extends AnyService<AnyObjectTO> {
             description = "Allows client to specify a preference for the result to be returned from the server",
             allowEmptyValue = true, schema =
             @Schema(defaultValue = "return-content", allowableValues = { "return-content", "return-no-content" }))
+    @Parameter(name = HttpHeaders.IF_MATCH, in = ParameterIn.HEADER,
+            description = "When the provided ETag value does not match the latest modification date of the entity, "
+            + "an error is reported and the requested operation is not performed.",
+            allowEmptyValue = true, schema =
+            @Schema(type = "string"))
     @ApiResponses({
         @ApiResponse(responseCode = "200",
                 description = "Any object successfully updated enriched with propagation status information, as Entity",
@@ -144,7 +165,10 @@ public interface AnyObjectService extends AnyService<AnyObjectTO> {
                 @Header(name = RESTHeaders.PREFERENCE_APPLIED, schema =
                         @Schema(type = "string"),
                         description = "Allows the server to inform the "
-                        + "client about the fact that a specified preference was applied")) })
+                        + "client about the fact that a specified preference was applied"))
+        , @ApiResponse(responseCode = "412",
+                description = "The ETag value provided via the 'If-Match' header does not match the latest modification"
+                + " date of the entity") })
     @PUT
     @Path("{key}")
     @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })

http://git-wip-us.apache.org/repos/asf/syncope/blob/b2870581/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/AnyService.java
----------------------------------------------------------------------
diff --git a/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/AnyService.java b/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/AnyService.java
index 5dcccb1..768b3e6 100644
--- a/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/AnyService.java
+++ b/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/AnyService.java
@@ -36,6 +36,7 @@ import javax.ws.rs.PUT;
 import javax.ws.rs.Path;
 import javax.ws.rs.PathParam;
 import javax.ws.rs.Produces;
+import javax.ws.rs.core.HttpHeaders;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
 import org.apache.syncope.common.lib.patch.AssociationPatch;
@@ -43,6 +44,7 @@ import org.apache.syncope.common.lib.patch.DeassociationPatch;
 import org.apache.syncope.common.lib.to.AnyTO;
 import org.apache.syncope.common.lib.to.AttrTO;
 import org.apache.syncope.common.lib.to.BulkAction;
+import org.apache.syncope.common.lib.to.BulkActionResult;
 import org.apache.syncope.common.lib.to.PagedResult;
 import org.apache.syncope.common.lib.to.ProvisioningResult;
 import org.apache.syncope.common.lib.types.SchemaType;
@@ -88,10 +90,7 @@ public interface AnyService<TO extends AnyTO> extends JAXRSService {
     /**
      * Reads the any object matching the provided key.
      *
-     * Note that for the UserService, GroupService and AnyObjectService subclasses, if the key parameter
-     * looks like a UUID then it is interpreted as as key, otherwise as a (user)name.
-     *
-     * @param key any object key or name
+     * @param key if value looks like a UUID then it is interpreted as key, otherwise as a (user)name
      * @return any object with matching key
      */
     @GET
@@ -152,6 +151,11 @@ public interface AnyService<TO extends AnyTO> extends JAXRSService {
             description = "Allows client to specify a preference for the result to be returned from the server",
             allowEmptyValue = true, schema =
             @Schema(defaultValue = "return-content", allowableValues = { "return-content", "return-no-content" }))
+    @Parameter(name = HttpHeaders.IF_MATCH, in = ParameterIn.HEADER,
+            description = "When the provided ETag value does not match the latest modification date of the entity, "
+            + "an error is reported and the requested operation is not performed.",
+            allowEmptyValue = true, schema =
+            @Schema(type = "string"))
     @ApiResponses({
         @ApiResponse(responseCode = "200",
                 description = "User, Group or Any Object successfully deleted enriched with propagation status "
@@ -163,7 +167,10 @@ public interface AnyService<TO extends AnyTO> extends JAXRSService {
                 @Header(name = RESTHeaders.PREFERENCE_APPLIED, schema =
                         @Schema(type = "string"),
                         description = "Allows the server to inform the "
-                        + "client about the fact that a specified preference was applied")) })
+                        + "client about the fact that a specified preference was applied"))
+        , @ApiResponse(responseCode = "412",
+                description = "The ETag value provided via the 'If-Match' header does not match the latest modification"
+                + " date of the entity") })
     @DELETE
     @Path("{key}")
     @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
@@ -175,6 +182,29 @@ public interface AnyService<TO extends AnyTO> extends JAXRSService {
      * @param patch external resources to be used for propagation-related operations
      * @return Response object featuring BulkActionResult as Entity
      */
+    @Parameter(name = RESTHeaders.PREFER, in = ParameterIn.HEADER,
+            description = "Allows client to specify a preference for the result to be returned from the server",
+            allowEmptyValue = true, schema =
+            @Schema(defaultValue = "return-content", allowableValues = { "return-content", "return-no-content" }))
+    @Parameter(name = HttpHeaders.IF_MATCH, in = ParameterIn.HEADER,
+            description = "When the provided ETag value does not match the latest modification date of the entity, "
+            + "an error is reported and the requested operation is not performed.",
+            allowEmptyValue = true, schema =
+            @Schema(type = "string"))
+    @ApiResponses({
+        @ApiResponse(responseCode = "200",
+                description = "Bulk action result", content =
+                @Content(schema =
+                        @Schema(implementation = BulkActionResult.class)))
+        , @ApiResponse(responseCode = "204",
+                description = "No content if 'Prefer: return-no-content' was specified", headers =
+                @Header(name = RESTHeaders.PREFERENCE_APPLIED, schema =
+                        @Schema(type = "string"),
+                        description = "Allows the server to inform the "
+                        + "client about the fact that a specified preference was applied"))
+        , @ApiResponse(responseCode = "412",
+                description = "The ETag value provided via the 'If-Match' header does not match the latest modification"
+                + " date of the entity") })
     @POST
     @Path("{key}/deassociate/{action}")
     @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
@@ -187,6 +217,29 @@ public interface AnyService<TO extends AnyTO> extends JAXRSService {
      * @param patch external resources to be used for propagation-related operations
      * @return Response object featuring BulkActionResult as Entity
      */
+    @Parameter(name = RESTHeaders.PREFER, in = ParameterIn.HEADER,
+            description = "Allows client to specify a preference for the result to be returned from the server",
+            allowEmptyValue = true, schema =
+            @Schema(defaultValue = "return-content", allowableValues = { "return-content", "return-no-content" }))
+    @Parameter(name = HttpHeaders.IF_MATCH, in = ParameterIn.HEADER,
+            description = "When the provided ETag value does not match the latest modification date of the entity, "
+            + "an error is reported and the requested operation is not performed.",
+            allowEmptyValue = true, schema =
+            @Schema(type = "string"))
+    @ApiResponses({
+        @ApiResponse(responseCode = "200",
+                description = "Bulk action result", content =
+                @Content(schema =
+                        @Schema(implementation = BulkActionResult.class)))
+        , @ApiResponse(responseCode = "204",
+                description = "No content if 'Prefer: return-no-content' was specified", headers =
+                @Header(name = RESTHeaders.PREFERENCE_APPLIED, schema =
+                        @Schema(type = "string"),
+                        description = "Allows the server to inform the "
+                        + "client about the fact that a specified preference was applied"))
+        , @ApiResponse(responseCode = "412",
+                description = "The ETag value provided via the 'If-Match' header does not match the latest modification"
+                + " date of the entity") })
     @POST
     @Path("{key}/associate/{action}")
     @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
@@ -199,6 +252,21 @@ public interface AnyService<TO extends AnyTO> extends JAXRSService {
      * @param bulkAction list of any object ids against which the bulk action will be performed.
      * @return Response object featuring BulkActionResult as Entity
      */
+    @Parameter(name = RESTHeaders.PREFER, in = ParameterIn.HEADER,
+            description = "Allows client to specify a preference for the result to be returned from the server",
+            allowEmptyValue = true, schema =
+            @Schema(defaultValue = "return-content", allowableValues = { "return-content", "return-no-content" }))
+    @ApiResponses({
+        @ApiResponse(responseCode = "200",
+                description = "Bulk action result", content =
+                @Content(schema =
+                        @Schema(implementation = BulkActionResult.class)))
+        , @ApiResponse(responseCode = "204",
+                description = "No content if 'Prefer: return-no-content' was specified", headers =
+                @Header(name = RESTHeaders.PREFERENCE_APPLIED, schema =
+                        @Schema(type = "string"),
+                        description = "Allows the server to inform the "
+                        + "client about the fact that a specified preference was applied")) })
     @POST
     @Path("bulk")
     @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })

http://git-wip-us.apache.org/repos/asf/syncope/blob/b2870581/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/GroupService.java
----------------------------------------------------------------------
diff --git a/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/GroupService.java b/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/GroupService.java
index d999df3..e4eaafa 100644
--- a/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/GroupService.java
+++ b/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/GroupService.java
@@ -60,6 +60,14 @@ import org.apache.syncope.common.rest.api.beans.AnyQuery;
 @Path("groups")
 public interface GroupService extends AnyService<GroupTO> {
 
+    @ApiResponses(
+            @ApiResponse(responseCode = "200", description =
+                    "Group matching the provided key; if value looks like a UUID then it is interpreted as key,"
+                    + " otherwise as a name.", headers =
+                    @Header(name = HttpHeaders.ETAG, schema =
+                            @Schema(type = "string"),
+                            description = "Opaque identifier for the latest modification made to the entity returned"
+                            + " by this endpoint")))
     @Override
     GroupTO read(String key);
 
@@ -109,6 +117,11 @@ public interface GroupService extends AnyService<GroupTO> {
             description = "Allows client to specify a preference for the result to be returned from the server",
             allowEmptyValue = true, schema =
             @Schema(defaultValue = "return-content", allowableValues = { "return-content", "return-no-content" }))
+    @Parameter(name = HttpHeaders.IF_MATCH, in = ParameterIn.HEADER,
+            description = "When the provided ETag value does not match the latest modification date of the entity, "
+            + "an error is reported and the requested operation is not performed.",
+            allowEmptyValue = true, schema =
+            @Schema(type = "string"))
     @ApiResponses({
         @ApiResponse(responseCode = "200",
                 description = "Group successfully updated enriched with propagation status information, as Entity",
@@ -120,7 +133,10 @@ public interface GroupService extends AnyService<GroupTO> {
                 @Header(name = RESTHeaders.PREFERENCE_APPLIED, schema =
                         @Schema(type = "string"),
                         description = "Allows the server to inform the "
-                        + "client about the fact that a specified preference was applied")) })
+                        + "client about the fact that a specified preference was applied"))
+        , @ApiResponse(responseCode = "412",
+                description = "The ETag value provided via the 'If-Match' header does not match the latest modification"
+                + " date of the entity") })
     @PATCH
     @Path("{key}")
     @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
@@ -137,6 +153,11 @@ public interface GroupService extends AnyService<GroupTO> {
             description = "Allows client to specify a preference for the result to be returned from the server",
             allowEmptyValue = true, schema =
             @Schema(defaultValue = "return-content", allowableValues = { "return-content", "return-no-content" }))
+    @Parameter(name = HttpHeaders.IF_MATCH, in = ParameterIn.HEADER,
+            description = "When the provided ETag value does not match the latest modification date of the entity, "
+            + "an error is reported and the requested operation is not performed.",
+            allowEmptyValue = true, schema =
+            @Schema(type = "string"))
     @ApiResponses({
         @ApiResponse(responseCode = "200",
                 description = "Group successfully updated enriched with propagation status information, as Entity",
@@ -148,7 +169,10 @@ public interface GroupService extends AnyService<GroupTO> {
                 @Header(name = RESTHeaders.PREFERENCE_APPLIED, schema =
                         @Schema(type = "string"),
                         description = "Allows the server to inform the "
-                        + "client about the fact that a specified preference was applied")) })
+                        + "client about the fact that a specified preference was applied"))
+        , @ApiResponse(responseCode = "412",
+                description = "The ETag value provided via the 'If-Match' header does not match the latest modification"
+                + " date of the entity") })
     @PUT
     @Path("{key}")
     @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })

http://git-wip-us.apache.org/repos/asf/syncope/blob/b2870581/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/UserService.java
----------------------------------------------------------------------
diff --git a/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/UserService.java b/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/UserService.java
index 82f9a72..6f36494 100644
--- a/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/UserService.java
+++ b/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/UserService.java
@@ -58,6 +58,14 @@ import org.apache.syncope.common.rest.api.beans.AnyQuery;
 @Path("users")
 public interface UserService extends AnyService<UserTO> {
 
+    @ApiResponses(
+            @ApiResponse(responseCode = "200", description =
+                    "User matching the provided key; if value looks like a UUID then it is interpreted as key,"
+                    + " otherwise as a username.", headers =
+                    @Header(name = HttpHeaders.ETAG, schema =
+                            @Schema(type = "string"),
+                            description = "Opaque identifier for the latest modification made to the entity returned"
+                            + " by this endpoint")))
     @Override
     UserTO read(String key);
 
@@ -110,6 +118,11 @@ public interface UserService extends AnyService<UserTO> {
             description = "Allows client to specify a preference for the result to be returned from the server",
             allowEmptyValue = true, schema =
             @Schema(defaultValue = "return-content", allowableValues = { "return-content", "return-no-content" }))
+    @Parameter(name = HttpHeaders.IF_MATCH, in = ParameterIn.HEADER,
+            description = "When the provided ETag value does not match the latest modification date of the entity, "
+            + "an error is reported and the requested operation is not performed.",
+            allowEmptyValue = true, schema =
+            @Schema(type = "string"))
     @ApiResponses({
         @ApiResponse(responseCode = "200",
                 description = "User successfully updated enriched with propagation status information, as Entity",
@@ -121,7 +134,10 @@ public interface UserService extends AnyService<UserTO> {
                 @Header(name = RESTHeaders.PREFERENCE_APPLIED, schema =
                         @Schema(type = "string"),
                         description = "Allows the server to inform the "
-                        + "client about the fact that a specified preference was applied")) })
+                        + "client about the fact that a specified preference was applied"))
+        , @ApiResponse(responseCode = "412",
+                description = "The ETag value provided via the 'If-Match' header does not match the latest modification"
+                + " date of the entity") })
     @PATCH
     @Path("{key}")
     @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
@@ -134,22 +150,32 @@ public interface UserService extends AnyService<UserTO> {
      * @param userTO complete update
      * @return Response object featuring the updated user enriched with propagation status information
      */
-    @Parameter(name = RESTHeaders.PREFER, in = ParameterIn.HEADER,
+    @Parameter(
+            name = RESTHeaders.PREFER, in = ParameterIn.HEADER,
             description = "Allows client to specify a preference for the result to be returned from the server",
             allowEmptyValue = true, schema =
             @Schema(defaultValue = "return-content", allowableValues = { "return-content", "return-no-content" }))
+    @Parameter(name = HttpHeaders.IF_MATCH, in = ParameterIn.HEADER,
+            description = "When the provided ETag value does not match the latest modification date of the entity, "
+            + "an error is reported and the requested operation is not performed.",
+            allowEmptyValue = true, schema =
+            @Schema(type = "string"))
     @ApiResponses({
         @ApiResponse(responseCode = "200",
                 description = "User successfully updated enriched with propagation status information, as Entity",
                 content =
                 @Content(schema =
                         @Schema(implementation = ProvisioningResult.class)))
-        , @ApiResponse(responseCode = "204",
+        ,
+        @ApiResponse(responseCode = "204",
                 description = "No content if 'Prefer: return-no-content' was specified", headers =
                 @Header(name = RESTHeaders.PREFERENCE_APPLIED, schema =
                         @Schema(type = "string"),
                         description = "Allows the server to inform the "
-                        + "client about the fact that a specified preference was applied")) })
+                        + "client about the fact that a specified preference was applied"))
+        , @ApiResponse(responseCode = "412",
+                description = "The ETag value provided via the 'If-Match' header does not match the latest modification"
+                + " date of the entity") })
     @PUT
     @Path("{key}")
     @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
@@ -162,10 +188,16 @@ public interface UserService extends AnyService<UserTO> {
      * @param statusPatch status update details
      * @return Response object featuring the updated user enriched with propagation status information
      */
-    @Parameter(name = RESTHeaders.PREFER, in = ParameterIn.HEADER,
+    @Parameter(
+            name = RESTHeaders.PREFER, in = ParameterIn.HEADER,
             description = "Allows client to specify a preference for the result to be returned from the server",
             allowEmptyValue = true, schema =
             @Schema(defaultValue = "return-content", allowableValues = { "return-content", "return-no-content" }))
+    @Parameter(name = HttpHeaders.IF_MATCH, in = ParameterIn.HEADER,
+            description = "When the provided ETag value does not match the latest modification date of the entity, "
+            + "an error is reported and the requested operation is not performed.",
+            allowEmptyValue = true, schema =
+            @Schema(type = "string"))
     @ApiResponses({
         @ApiResponse(responseCode = "200",
                 description = "User successfully updated enriched with propagation status information, as Entity",
@@ -177,7 +209,10 @@ public interface UserService extends AnyService<UserTO> {
                 @Header(name = RESTHeaders.PREFERENCE_APPLIED, schema =
                         @Schema(type = "string"),
                         description = "Allows the server to inform the "
-                        + "client about the fact that a specified preference was applied")) })
+                        + "client about the fact that a specified preference was applied"))
+        , @ApiResponse(responseCode = "412",
+                description = "The ETag value provided via the 'If-Match' header does not match the latest modification"
+                + " date of the entity") })
     @POST
     @Path("{key}/status")
     @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })


[2/2] syncope git commit: [SYNCOPE-1274] Add documentation for ETag, If-Match

Posted by il...@apache.org.
[SYNCOPE-1274] Add documentation for ETag, If-Match


Project: http://git-wip-us.apache.org/repos/asf/syncope/repo
Commit: http://git-wip-us.apache.org/repos/asf/syncope/commit/2c7138b2
Tree: http://git-wip-us.apache.org/repos/asf/syncope/tree/2c7138b2
Diff: http://git-wip-us.apache.org/repos/asf/syncope/diff/2c7138b2

Branch: refs/heads/2_0_X
Commit: 2c7138b2f9c6e1314112f618f083f0672136ac27
Parents: 66aac6a
Author: Francesco Chicchiriccò <il...@apache.org>
Authored: Fri Feb 16 15:36:50 2018 +0100
Committer: Francesco Chicchiriccò <il...@apache.org>
Committed: Fri Feb 16 16:28:52 2018 +0100

----------------------------------------------------------------------
 .../rest/api/service/AnyObjectService.java      | 46 ++++++++----
 .../common/rest/api/service/AnyService.java     | 76 +++++++++++++++++---
 .../common/rest/api/service/GroupService.java   | 46 ++++++++----
 .../common/rest/api/service/UserService.java    | 65 ++++++++++++-----
 4 files changed, 181 insertions(+), 52 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/syncope/blob/2c7138b2/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/AnyObjectService.java
----------------------------------------------------------------------
diff --git a/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/AnyObjectService.java b/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/AnyObjectService.java
index 9736860..8bd75cc 100644
--- a/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/AnyObjectService.java
+++ b/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/AnyObjectService.java
@@ -51,6 +51,14 @@ import org.apache.syncope.common.rest.api.beans.AnyQuery;
 @Path("anyObjects")
 public interface AnyObjectService extends AnyService<AnyObjectTO> {
 
+    @ApiResponses(
+            @ApiResponse(code = 200,
+                    message =
+                    "Any object matching the provided key; if value looks like a UUID then it is interpreted as key,"
+                    + " otherwise as a name.", responseHeaders =
+                    @ResponseHeader(name = HttpHeaders.ETAG, response = String.class,
+                            description = "Opaque identifier for the latest modification made to the entity returned"
+                            + " by this endpoint")))
     @Override
     AnyObjectTO read(String key);
 
@@ -92,11 +100,15 @@ public interface AnyObjectService extends AnyService<AnyObjectTO> {
      * @param anyObjectPatch modification to be applied to any object matching the provided key
      * @return Response object featuring the updated any object enriched with propagation status information
      */
-    @ApiImplicitParams(
-            @ApiImplicitParam(name = RESTHeaders.PREFER, paramType = "header", dataType = "string",
-                    value = "Allows the client to specify a preference for the result to be returned from the server",
-                    defaultValue = "return-content", allowableValues = "return-content, return-no-content",
-                    allowEmptyValue = true))
+    @ApiImplicitParams({
+        @ApiImplicitParam(name = RESTHeaders.PREFER, paramType = "header", dataType = "string",
+                value = "Allows the client to specify a preference for the result to be returned from the server",
+                defaultValue = "return-content", allowableValues = "return-content, return-no-content",
+                allowEmptyValue = true)
+        , @ApiImplicitParam(name = HttpHeaders.IF_MATCH, paramType = "header", dataType = "string",
+                value = "When the provided ETag value does not match the latest modification date of the entity, "
+                + "an error is reported and the requested operation is not performed.",
+                allowEmptyValue = true) })
     @ApiResponses({
         @ApiResponse(code = 200,
                 message = "Any object successfully updated enriched with propagation status information, as Entity",
@@ -105,7 +117,10 @@ public interface AnyObjectService extends AnyService<AnyObjectTO> {
                 message = "No content if 'Prefer: return-no-content' was specified", responseHeaders =
                 @ResponseHeader(name = RESTHeaders.PREFERENCE_APPLIED, response = String.class,
                         description = "Allows the server to inform the "
-                        + "client about the fact that a specified preference was applied")) })
+                        + "client about the fact that a specified preference was applied"))
+        , @ApiResponse(code = 412,
+                message = "The ETag value provided via the 'If-Match' header does not match the latest modification "
+                + "date of the entity") })
     @PATCH
     @Path("{key}")
     @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
@@ -118,11 +133,15 @@ public interface AnyObjectService extends AnyService<AnyObjectTO> {
      * @param anyObjectTO complete update
      * @return Response object featuring the updated any object enriched with propagation status information
      */
-    @ApiImplicitParams(
-            @ApiImplicitParam(name = RESTHeaders.PREFER, paramType = "header", dataType = "string",
-                    value = "Allows the client to specify a preference for the result to be returned from the server",
-                    defaultValue = "return-content", allowableValues = "return-content, return-no-content",
-                    allowEmptyValue = true))
+    @ApiImplicitParams({
+        @ApiImplicitParam(name = RESTHeaders.PREFER, paramType = "header", dataType = "string",
+                value = "Allows the client to specify a preference for the result to be returned from the server",
+                defaultValue = "return-content", allowableValues = "return-content, return-no-content",
+                allowEmptyValue = true)
+        , @ApiImplicitParam(name = HttpHeaders.IF_MATCH, paramType = "header", dataType = "string",
+                value = "When the provided ETag value does not match the latest modification date of the entity, "
+                + "an error is reported and the requested operation is not performed.",
+                allowEmptyValue = true) })
     @ApiResponses({
         @ApiResponse(code = 200,
                 message = "Any object successfully updated enriched with propagation status information, as Entity",
@@ -131,7 +150,10 @@ public interface AnyObjectService extends AnyService<AnyObjectTO> {
                 message = "No content if 'Prefer: return-no-content' was specified", responseHeaders =
                 @ResponseHeader(name = RESTHeaders.PREFERENCE_APPLIED, response = String.class,
                         description = "Allows the server to inform the "
-                        + "client about the fact that a specified preference was applied")) })
+                        + "client about the fact that a specified preference was applied"))
+        , @ApiResponse(code = 412,
+                message = "The ETag value provided via the 'If-Match' header does not match the latest modification "
+                + "date of the entity") })
     @PUT
     @Path("{key}")
     @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })

http://git-wip-us.apache.org/repos/asf/syncope/blob/2c7138b2/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/AnyService.java
----------------------------------------------------------------------
diff --git a/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/AnyService.java b/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/AnyService.java
index 4d4725d..2b9ff04 100644
--- a/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/AnyService.java
+++ b/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/AnyService.java
@@ -34,6 +34,7 @@ import javax.ws.rs.PUT;
 import javax.ws.rs.Path;
 import javax.ws.rs.PathParam;
 import javax.ws.rs.Produces;
+import javax.ws.rs.core.HttpHeaders;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
 import org.apache.syncope.common.lib.patch.AssociationPatch;
@@ -41,6 +42,7 @@ import org.apache.syncope.common.lib.patch.DeassociationPatch;
 import org.apache.syncope.common.lib.to.AnyTO;
 import org.apache.syncope.common.lib.to.AttrTO;
 import org.apache.syncope.common.lib.to.BulkAction;
+import org.apache.syncope.common.lib.to.BulkActionResult;
 import org.apache.syncope.common.lib.to.PagedResult;
 import org.apache.syncope.common.lib.to.ProvisioningResult;
 import org.apache.syncope.common.lib.types.SchemaType;
@@ -86,10 +88,7 @@ public interface AnyService<TO extends AnyTO> extends JAXRSService {
     /**
      * Reads the any object matching the provided key.
      *
-     * Note that for the UserService, GroupService and AnyObjectService subclasses, if the key parameter
-     * looks like a UUID then it is interpreted as as key, otherwise as a (user)name.
-     *
-     * @param key any object key or name
+     * @param key if value looks like a UUID then it is interpreted as key, otherwise as a (user)name
      * @return any object with matching key
      */
     @GET
@@ -146,11 +145,15 @@ public interface AnyService<TO extends AnyTO> extends JAXRSService {
      * @param key any object key or name
      * @return Response object featuring the deleted any object enriched with propagation status information
      */
-    @ApiImplicitParams(
-            @ApiImplicitParam(name = RESTHeaders.PREFER, paramType = "header", dataType = "string",
-                    value = "Allows the client to specify a preference for the result to be returned from the server",
-                    defaultValue = "return-content", allowableValues = "return-content, return-no-content",
-                    allowEmptyValue = true))
+    @ApiImplicitParams({
+        @ApiImplicitParam(name = RESTHeaders.PREFER, paramType = "header", dataType = "string",
+                value = "Allows the client to specify a preference for the result to be returned from the server",
+                defaultValue = "return-content", allowableValues = "return-content, return-no-content",
+                allowEmptyValue = true)
+        , @ApiImplicitParam(name = HttpHeaders.IF_MATCH, paramType = "header", dataType = "string",
+                value = "When the provided ETag value does not match the latest modification date of the entity, "
+                + "an error is reported and the requested operation is not performed.",
+                allowEmptyValue = true) })
     @ApiResponses({
         @ApiResponse(code = 200,
                 message = "User, Group or Any Object successfully deleted enriched with propagation status information,"
@@ -160,7 +163,10 @@ public interface AnyService<TO extends AnyTO> extends JAXRSService {
                 message = "No content if 'Prefer: return-no-content' was specified", responseHeaders =
                 @ResponseHeader(name = RESTHeaders.PREFERENCE_APPLIED, response = String.class,
                         description = "Allows the server to inform the "
-                        + "client about the fact that a specified preference was applied")) })
+                        + "client about the fact that a specified preference was applied"))
+        , @ApiResponse(code = 412,
+                message = "The ETag value provided via the 'If-Match' header does not match the latest modification "
+                + "date of the entity") })
     @DELETE
     @Path("{key}")
     @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
@@ -172,6 +178,25 @@ public interface AnyService<TO extends AnyTO> extends JAXRSService {
      * @param patch external resources to be used for propagation-related operations
      * @return Response object featuring BulkActionResult as Entity
      */
+    @ApiImplicitParams({
+        @ApiImplicitParam(name = RESTHeaders.PREFER, paramType = "header", dataType = "string",
+                value = "Allows the client to specify a preference for the result to be returned from the server",
+                defaultValue = "return-content", allowableValues = "return-content, return-no-content",
+                allowEmptyValue = true)
+        , @ApiImplicitParam(name = HttpHeaders.IF_MATCH, paramType = "header", dataType = "string",
+                value = "When the provided ETag value does not match the latest modification date of the entity, "
+                + "an error is reported and the requested operation is not performed.",
+                allowEmptyValue = true) })
+    @ApiResponses({
+        @ApiResponse(code = 200, message = "Bulk action result", response = BulkActionResult.class)
+        , @ApiResponse(code = 204,
+                message = "No content if 'Prefer: return-no-content' was specified", responseHeaders =
+                @ResponseHeader(name = RESTHeaders.PREFERENCE_APPLIED, response = String.class,
+                        description = "Allows the server to inform the "
+                        + "client about the fact that a specified preference was applied"))
+        , @ApiResponse(code = 412,
+                message = "The ETag value provided via the 'If-Match' header does not match the latest modification "
+                + "date of the entity") })
     @POST
     @Path("{key}/deassociate/{action}")
     @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
@@ -184,6 +209,25 @@ public interface AnyService<TO extends AnyTO> extends JAXRSService {
      * @param patch external resources to be used for propagation-related operations
      * @return Response object featuring BulkActionResult as Entity
      */
+    @ApiImplicitParams({
+        @ApiImplicitParam(name = RESTHeaders.PREFER, paramType = "header", dataType = "string",
+                value = "Allows the client to specify a preference for the result to be returned from the server",
+                defaultValue = "return-content", allowableValues = "return-content, return-no-content",
+                allowEmptyValue = true)
+        , @ApiImplicitParam(name = HttpHeaders.IF_MATCH, paramType = "header", dataType = "string",
+                value = "When the provided ETag value does not match the latest modification date of the entity, "
+                + "an error is reported and the requested operation is not performed.",
+                allowEmptyValue = true) })
+    @ApiResponses({
+        @ApiResponse(code = 200, message = "Bulk action result", response = BulkActionResult.class)
+        , @ApiResponse(code = 204,
+                message = "No content if 'Prefer: return-no-content' was specified", responseHeaders =
+                @ResponseHeader(name = RESTHeaders.PREFERENCE_APPLIED, response = String.class,
+                        description = "Allows the server to inform the "
+                        + "client about the fact that a specified preference was applied"))
+        , @ApiResponse(code = 412,
+                message = "The ETag value provided via the 'If-Match' header does not match the latest modification "
+                + "date of the entity") })
     @POST
     @Path("{key}/associate/{action}")
     @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
@@ -196,6 +240,18 @@ public interface AnyService<TO extends AnyTO> extends JAXRSService {
      * @param bulkAction list of any object ids against which the bulk action will be performed.
      * @return Response object featuring BulkActionResult as Entity
      */
+    @ApiImplicitParams(
+            @ApiImplicitParam(name = RESTHeaders.PREFER, paramType = "header", dataType = "string",
+                    value = "Allows the client to specify a preference for the result to be returned from the server",
+                    defaultValue = "return-content", allowableValues = "return-content, return-no-content",
+                    allowEmptyValue = true))
+    @ApiResponses({
+        @ApiResponse(code = 200, message = "Bulk action result", response = BulkActionResult.class)
+        , @ApiResponse(code = 204,
+                message = "No content if 'Prefer: return-no-content' was specified", responseHeaders =
+                @ResponseHeader(name = RESTHeaders.PREFERENCE_APPLIED, response = String.class,
+                        description = "Allows the server to inform the "
+                        + "client about the fact that a specified preference was applied")) })
     @POST
     @Path("bulk")
     @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })

http://git-wip-us.apache.org/repos/asf/syncope/blob/2c7138b2/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/GroupService.java
----------------------------------------------------------------------
diff --git a/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/GroupService.java b/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/GroupService.java
index 8764eec..197c755 100644
--- a/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/GroupService.java
+++ b/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/GroupService.java
@@ -56,6 +56,14 @@ import org.apache.syncope.common.rest.api.beans.AnyQuery;
 @Path("groups")
 public interface GroupService extends AnyService<GroupTO> {
 
+    @ApiResponses(
+            @ApiResponse(code = 200,
+                    message =
+                    "Group matching the provided key; if value looks like a UUID then it is interpreted as key,"
+                    + " otherwise as a name.", responseHeaders =
+                    @ResponseHeader(name = HttpHeaders.ETAG, response = String.class,
+                            description = "Opaque identifier for the latest modification made to the entity returned"
+                            + " by this endpoint")))
     @Override
     GroupTO read(String key);
 
@@ -97,11 +105,15 @@ public interface GroupService extends AnyService<GroupTO> {
      * @param groupPatch modification to be applied to group matching the provided key
      * @return Response object featuring the updated group enriched with propagation status information
      */
-    @ApiImplicitParams(
-            @ApiImplicitParam(name = RESTHeaders.PREFER, paramType = "header", dataType = "string",
-                    value = "Allows the client to specify a preference for the result to be returned from the server",
-                    defaultValue = "return-content", allowableValues = "return-content, return-no-content",
-                    allowEmptyValue = true))
+    @ApiImplicitParams({
+        @ApiImplicitParam(name = RESTHeaders.PREFER, paramType = "header", dataType = "string",
+                value = "Allows the client to specify a preference for the result to be returned from the server",
+                defaultValue = "return-content", allowableValues = "return-content, return-no-content",
+                allowEmptyValue = true)
+        , @ApiImplicitParam(name = HttpHeaders.IF_MATCH, paramType = "header", dataType = "string",
+                value = "When the provided ETag value does not match the latest modification date of the entity, "
+                + "an error is reported and the requested operation is not performed.",
+                allowEmptyValue = true) })
     @ApiResponses({
         @ApiResponse(code = 200,
                 message = "Group successfully updated enriched with propagation status information, as Entity",
@@ -110,7 +122,10 @@ public interface GroupService extends AnyService<GroupTO> {
                 message = "No content if 'Prefer: return-no-content' was specified", responseHeaders =
                 @ResponseHeader(name = RESTHeaders.PREFERENCE_APPLIED, response = String.class,
                         description = "Allows the server to inform the "
-                        + "client about the fact that a specified preference was applied")) })
+                        + "client about the fact that a specified preference was applied"))
+        , @ApiResponse(code = 412,
+                message = "The ETag value provided via the 'If-Match' header does not match the latest modification "
+                + "date of the entity") })
     @PATCH
     @Path("{key}")
     @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
@@ -123,11 +138,15 @@ public interface GroupService extends AnyService<GroupTO> {
      * @param groupTO complete update
      * @return Response object featuring the updated group enriched with propagation status information
      */
-    @ApiImplicitParams(
-            @ApiImplicitParam(name = RESTHeaders.PREFER, paramType = "header", dataType = "string",
-                    value = "Allows the client to specify a preference for the result to be returned from the server",
-                    defaultValue = "return-content", allowableValues = "return-content, return-no-content",
-                    allowEmptyValue = true))
+    @ApiImplicitParams({
+        @ApiImplicitParam(name = RESTHeaders.PREFER, paramType = "header", dataType = "string",
+                value = "Allows the client to specify a preference for the result to be returned from the server",
+                defaultValue = "return-content", allowableValues = "return-content, return-no-content",
+                allowEmptyValue = true)
+        , @ApiImplicitParam(name = HttpHeaders.IF_MATCH, paramType = "header", dataType = "string",
+                value = "When the provided ETag value does not match the latest modification date of the entity, "
+                + "an error is reported and the requested operation is not performed.",
+                allowEmptyValue = true) })
     @ApiResponses({
         @ApiResponse(code = 200,
                 message = "Group successfully updated enriched with propagation status information, as Entity",
@@ -136,7 +155,10 @@ public interface GroupService extends AnyService<GroupTO> {
                 message = "No content if 'Prefer: return-no-content' was specified", responseHeaders =
                 @ResponseHeader(name = RESTHeaders.PREFERENCE_APPLIED, response = String.class,
                         description = "Allows the server to inform the "
-                        + "client about the fact that a specified preference was applied")) })
+                        + "client about the fact that a specified preference was applied"))
+        , @ApiResponse(code = 412,
+                message = "The ETag value provided via the 'If-Match' header does not match the latest modification "
+                + "date of the entity") })
     @PUT
     @Path("{key}")
     @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })

http://git-wip-us.apache.org/repos/asf/syncope/blob/2c7138b2/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/UserService.java
----------------------------------------------------------------------
diff --git a/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/UserService.java b/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/UserService.java
index 5e9c155..86bbb73 100644
--- a/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/UserService.java
+++ b/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/UserService.java
@@ -54,6 +54,14 @@ import org.apache.syncope.common.rest.api.beans.AnyQuery;
 @Path("users")
 public interface UserService extends AnyService<UserTO> {
 
+    @ApiResponses(
+            @ApiResponse(code = 200,
+                    message =
+                    "User matching the provided key; if value looks like a UUID then it is interpreted as key,"
+                    + " otherwise as a username.", responseHeaders =
+                    @ResponseHeader(name = HttpHeaders.ETAG, response = String.class,
+                            description = "Opaque identifier for the latest modification made to the entity returned"
+                            + " by this endpoint")))
     @Override
     UserTO read(String key);
 
@@ -98,11 +106,15 @@ public interface UserService extends AnyService<UserTO> {
      * @param userPatch modification to be applied to user matching the provided key
      * @return Response object featuring the updated user enriched with propagation status information
      */
-    @ApiImplicitParams(
-            @ApiImplicitParam(name = RESTHeaders.PREFER, paramType = "header", dataType = "string",
-                    value = "Allows the client to specify a preference for the result to be returned from the server",
-                    defaultValue = "return-content", allowableValues = "return-content, return-no-content",
-                    allowEmptyValue = true))
+    @ApiImplicitParams({
+        @ApiImplicitParam(name = RESTHeaders.PREFER, paramType = "header", dataType = "string",
+                value = "Allows the client to specify a preference for the result to be returned from the server",
+                defaultValue = "return-content", allowableValues = "return-content, return-no-content",
+                allowEmptyValue = true)
+        , @ApiImplicitParam(name = HttpHeaders.IF_MATCH, paramType = "header", dataType = "string",
+                value = "When the provided ETag value does not match the latest modification date of the entity, "
+                + "an error is reported and the requested operation is not performed.",
+                allowEmptyValue = true) })
     @ApiResponses({
         @ApiResponse(code = 200,
                 message = "User successfully updated enriched with propagation status information, as Entity",
@@ -111,7 +123,10 @@ public interface UserService extends AnyService<UserTO> {
                 message = "No content if 'Prefer: return-no-content' was specified", responseHeaders =
                 @ResponseHeader(name = RESTHeaders.PREFERENCE_APPLIED, response = String.class,
                         description = "Allows the server to inform the "
-                        + "client about the fact that a specified preference was applied")) })
+                        + "client about the fact that a specified preference was applied"))
+        , @ApiResponse(code = 412,
+                message = "The ETag value provided via the 'If-Match' header does not match the latest modification "
+                + "date of the entity") })
     @PATCH
     @Path("{key}")
     @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
@@ -124,11 +139,15 @@ public interface UserService extends AnyService<UserTO> {
      * @param userTO complete update
      * @return Response object featuring the updated user enriched with propagation status information
      */
-    @ApiImplicitParams(
-            @ApiImplicitParam(name = RESTHeaders.PREFER, paramType = "header", dataType = "string",
-                    value = "Allows the client to specify a preference for the result to be returned from the server",
-                    defaultValue = "return-content", allowableValues = "return-content, return-no-content",
-                    allowEmptyValue = true))
+    @ApiImplicitParams({
+        @ApiImplicitParam(name = RESTHeaders.PREFER, paramType = "header", dataType = "string",
+                value = "Allows the client to specify a preference for the result to be returned from the server",
+                defaultValue = "return-content", allowableValues = "return-content, return-no-content",
+                allowEmptyValue = true)
+        , @ApiImplicitParam(name = HttpHeaders.IF_MATCH, paramType = "header", dataType = "string",
+                value = "When the provided ETag value does not match the latest modification date of the entity, "
+                + "an error is reported and the requested operation is not performed.",
+                allowEmptyValue = true) })
     @ApiResponses({
         @ApiResponse(code = 200,
                 message = "User successfully updated enriched with propagation status information, as Entity",
@@ -137,7 +156,10 @@ public interface UserService extends AnyService<UserTO> {
                 message = "No content if 'Prefer: return-no-content' was specified", responseHeaders =
                 @ResponseHeader(name = RESTHeaders.PREFERENCE_APPLIED, response = String.class,
                         description = "Allows the server to inform the "
-                        + "client about the fact that a specified preference was applied")) })
+                        + "client about the fact that a specified preference was applied"))
+        , @ApiResponse(code = 412,
+                message = "The ETag value provided via the 'If-Match' header does not match the latest modification "
+                + "date of the entity") })
     @PUT
     @Path("{key}")
     @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
@@ -150,11 +172,15 @@ public interface UserService extends AnyService<UserTO> {
      * @param statusPatch status update details
      * @return Response object featuring the updated user enriched with propagation status information
      */
-    @ApiImplicitParams(
-            @ApiImplicitParam(name = RESTHeaders.PREFER, paramType = "header", dataType = "string",
-                    value = "Allows the client to specify a preference for the result to be returned from the server",
-                    defaultValue = "return-content", allowableValues = "return-content, return-no-content",
-                    allowEmptyValue = true))
+    @ApiImplicitParams({
+        @ApiImplicitParam(name = RESTHeaders.PREFER, paramType = "header", dataType = "string",
+                value = "Allows the client to specify a preference for the result to be returned from the server",
+                defaultValue = "return-content", allowableValues = "return-content, return-no-content",
+                allowEmptyValue = true)
+        , @ApiImplicitParam(name = HttpHeaders.IF_MATCH, paramType = "header", dataType = "string",
+                value = "When the provided ETag value does not match the latest modification date of the entity, "
+                + "an error is reported and the requested operation is not performed.",
+                allowEmptyValue = true) })
     @ApiResponses({
         @ApiResponse(code = 200,
                 message = "User successfully updated enriched with propagation status information, as Entity",
@@ -163,7 +189,10 @@ public interface UserService extends AnyService<UserTO> {
                 message = "No content if 'Prefer: return-no-content' was specified", responseHeaders =
                 @ResponseHeader(name = RESTHeaders.PREFERENCE_APPLIED, response = String.class,
                         description = "Allows the server to inform the "
-                        + "client about the fact that a specified preference was applied")) })
+                        + "client about the fact that a specified preference was applied"))
+        , @ApiResponse(code = 412,
+                message = "The ETag value provided via the 'If-Match' header does not match the latest modification "
+                + "date of the entity") })
     @POST
     @Path("{key}/status")
     @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })