You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@directory.apache.org by bd...@apache.org on 2022/08/26 19:01:17 UTC
[directory-scimple] 01/01: Add tests for BulkResourceImpl
This is an automated email from the ASF dual-hosted git repository.
bdemers pushed a commit to branch bulk-resource-test
in repository https://gitbox.apache.org/repos/asf/directory-scimple.git
commit 5ba6f401915b0123acd20f9ca50b5edc585243fd
Author: Brian Demers <bd...@apache.org>
AuthorDate: Fri Aug 26 15:01:10 2022 -0400
Add tests for BulkResourceImpl
Few minor fixes found along the way:
* null checks
* Object mapper should be transient
* Missing ReferenceTypes (shown in the Protocol Spec, in the bulk resource section)
---
.../scim/server/rest/BulkResourceImpl.java | 72 ++++---
.../scim/server/rest/BulkResourceImplTest.java | 230 +++++++++++++++++++++
.../scim/spec/json/ObjectMapperFactory.java | 6 +
.../scim/spec/resources/ScimResource.java | 2 +-
.../scim/spec/schema/ResourceReference.java | 4 +-
5 files changed, 281 insertions(+), 33 deletions(-)
diff --git a/scim-server/src/main/java/org/apache/directory/scim/server/rest/BulkResourceImpl.java b/scim-server/src/main/java/org/apache/directory/scim/server/rest/BulkResourceImpl.java
index 85a0632..00f2a78 100644
--- a/scim-server/src/main/java/org/apache/directory/scim/server/rest/BulkResourceImpl.java
+++ b/scim-server/src/main/java/org/apache/directory/scim/server/rest/BulkResourceImpl.java
@@ -19,14 +19,7 @@
package org.apache.directory.scim.server.rest;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
+import java.util.*;
import java.util.regex.Pattern;
import jakarta.enterprise.context.ApplicationScoped;
@@ -35,6 +28,7 @@ import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.core.Response.Status;
import jakarta.ws.rs.core.UriInfo;
+import org.apache.commons.lang3.StringUtils;
import org.apache.directory.scim.server.exception.UnableToCreateResourceException;
import org.apache.directory.scim.server.exception.UnableToDeleteResourceException;
import org.apache.directory.scim.server.exception.UnableToRetrieveResourceException;
@@ -112,9 +106,9 @@ public class BulkResourceImpl implements BulkResource {
public Response doBulk(BulkRequest request, UriInfo uriInfo) {
BulkResponse response;
int errorCount = 0;
- int requestFailOnErrors = request.getFailOnErrors();
- int maxErrorCount = requestFailOnErrors > 0 ? requestFailOnErrors : Integer.MAX_VALUE;
- int errorCountIncrement = requestFailOnErrors > 0 ? 1 : 0;
+ Integer requestFailOnErrors = request.getFailOnErrors();
+ int maxErrorCount = requestFailOnErrors != null && requestFailOnErrors > 0 ? requestFailOnErrors : Integer.MAX_VALUE;
+ int errorCountIncrement = requestFailOnErrors == null || requestFailOnErrors > 0 ? 1 : 0;
List<BulkOperation> bulkOperations = request.getOperations();
Map<String, BulkOperation> bulkIdKeyToOperationResult = new HashMap<>();
List<IWishJavaHadTuples> allUnresolveds = new ArrayList<>();
@@ -211,7 +205,7 @@ public class BulkResourceImpl implements BulkResource {
operationRequest.setData(null);
if (bulkIdKey != null) {
- Set<String> reverseDependencies = transitiveReverseDependencies.get(bulkIdKey);
+ Set<String> reverseDependencies = transitiveReverseDependencies.getOrDefault(bulkIdKey, Collections.emptySet());
String detail = String.format(OPERATION_DEPENDS_ON_FAILED_OPERATION, bulkIdKey);
for (String dependentBulkIdKey : reverseDependencies) {
@@ -225,9 +219,11 @@ public class BulkResourceImpl implements BulkResource {
}
}
}
+
+ boolean errorCountExceeded = false;
+
// do the operations
for (BulkOperation operationResult : bulkOperations) {
- boolean errorCountExceeded = errorCount >= maxErrorCount;
if (!errorCountExceeded && !(operationResult.getResponse() instanceof ErrorResponse)) {
try {
@@ -236,6 +232,7 @@ public class BulkResourceImpl implements BulkResource {
log.error("Failed to do bulk operation", resourceException);
errorCount += errorCountIncrement;
+ errorCountExceeded = errorCount >= maxErrorCount;
String detail = resourceException.getLocalizedMessage();
createAndSetErrorResponse(operationResult, resourceException.getStatus(), detail);
@@ -244,6 +241,7 @@ public class BulkResourceImpl implements BulkResource {
String bulkIdKey = "bulkId:" + operationResult.getBulkId();
this.cleanup(bulkIdKey, transitiveReverseDependencies, bulkIdKeyToOperationResult);
+ operationResult.setData(null);
}
} catch (UnresolvableOperationException unresolvableOperationException) {
log.error("Could not resolve bulkId during Bulk Operation method handling", unresolvableOperationException);
@@ -257,11 +255,14 @@ public class BulkResourceImpl implements BulkResource {
String bulkIdKey = "bulkId:" + operationResult.getBulkId();
this.cleanup(bulkIdKey, transitiveReverseDependencies, bulkIdKeyToOperationResult);
+ operationResult.setData(null);
}
}
} else if (errorCountExceeded) {
- createAndSetErrorResponse(operationResult, Status.CONFLICT, "failOnErrors count reached");
+ // continue processing bulk operations to cleanup any dependencies
+
+ createAndSetErrorResponse(operationResult, Status.CONFLICT, "failOnErrors count reached");
if (operationResult.getBulkId() != null) {
String bulkIdKey = "bulkId:" + operationResult.getBulkId();
@@ -318,12 +319,16 @@ public class BulkResourceImpl implements BulkResource {
this.cleanup(bulkIdKey, transitiveReverseDependencies, bulkIdKeyToOperationResult);
}
}
- response = new BulkResponse();
- response.setOperations(bulkOperations);
- response.setStatus(Status.OK);
- return Response.ok(response)
- .build();
+ Status status = errorCountExceeded ? Status.BAD_REQUEST : Status.OK;
+
+ response = new BulkResponse()
+ .setOperations(bulkOperations)
+ .setStatus(status);
+
+ return Response.status(status)
+ .entity(response)
+ .build();
}
/**
@@ -335,7 +340,7 @@ public class BulkResourceImpl implements BulkResource {
* @param bulkIdKeyToOperationResult
*/
private void cleanup(String bulkIdKeyToCleanup, Map<String, Set<String>> transitiveReverseDependencies, Map<String, BulkOperation> bulkIdKeyToOperationResult) {
- Set<String> reverseDependencies = transitiveReverseDependencies.get(bulkIdKeyToCleanup);
+ Set<String> reverseDependencies = transitiveReverseDependencies.getOrDefault(bulkIdKeyToCleanup, Collections.emptySet());
BulkOperation operationResult = bulkIdKeyToOperationResult.get(bulkIdKeyToCleanup);
String bulkId = operationResult.getBulkId();
ScimResource scimResource = operationResult.getData();
@@ -344,7 +349,9 @@ public class BulkResourceImpl implements BulkResource {
Repository<ScimResource> repository = this.repositoryRegistry.getRepository(scimResourceClass);
try {
- repository.delete(scimResource.getId());
+ if (StringUtils.isNotBlank(scimResource.getId())) {
+ repository.delete(scimResource.getId());
+ }
} catch (UnableToDeleteResourceException unableToDeleteResourceException) {
log.error("Could not delete ScimResource after failure: {}", scimResource);
}
@@ -426,7 +433,8 @@ public class BulkResourceImpl implements BulkResource {
.setData(newScimResource);
}
operationResult.setData(newScimResource);
- operationResult.setLocation(newResourceUri.toString());
+ operationResult.setLocation(newResourceUri);
+ operationResult.setPath(null);
operationResult.setStatus(StatusWrapper.wrap(Status.CREATED));
}
break;
@@ -481,6 +489,7 @@ public class BulkResourceImpl implements BulkResource {
ErrorResponse error = new ErrorResponse(status, detail);
operationResult.setResponse(error);
operationResult.setStatus(new StatusWrapper(status));
+ operationResult.setPath(null);
}
@AllArgsConstructor
@@ -726,8 +735,7 @@ public class BulkResourceImpl implements BulkResource {
if (!root.equals(current) && !visited.contains(current)) {
visited.add(current);
- Set<String> dependencies = dependencyGraph.get(current);
-
+ Set<String> dependencies = dependencyGraph.getOrDefault(current, Collections.emptySet());
for (String dependency : dependencies) {
generateVisited(visited, dependencyGraph, root, dependency);
}
@@ -772,13 +780,15 @@ public class BulkResourceImpl implements BulkResource {
// all COMPLEXES are
// multiValued
Object attributeObject = scimObjectAttribute.getAccessor().get(scimObject);
- Class<?> attributeObjectClass = attributeObject.getClass();
- boolean isCollection = Collection.class.isAssignableFrom(attributeObjectClass);
- Collection<?> attributeValues = isCollection ? (Collection<?>) attributeObject : Arrays.asList(attributeObject);
- List<Schema.Attribute> subAttributes = scimObjectAttribute.getAttributes();
-
- for (Object attributeValue : attributeValues) {
- generateReverseDependenciesGraph(reverseDependenciesGraph, dependentBulkId, attributeValue, subAttributes);
+ if (attributeObject != null) {
+ Class<?> attributeObjectClass = attributeObject.getClass();
+ boolean isCollection = Collection.class.isAssignableFrom(attributeObjectClass);
+ Collection<?> attributeValues = isCollection ? (Collection<?>) attributeObject : List.of(attributeObject);
+ List<Schema.Attribute> subAttributes = scimObjectAttribute.getAttributes();
+
+ for (Object attributeValue : attributeValues) {
+ generateReverseDependenciesGraph(reverseDependenciesGraph, dependentBulkId, attributeValue, subAttributes);
+ }
}
} else if (scimObjectAttribute.getType() == Schema.Attribute.Type.COMPLEX) {
Object attributeValue = scimObjectAttribute.getAccessor().get(scimObject);
diff --git a/scim-server/src/test/java/org/apache/directory/scim/server/rest/BulkResourceImplTest.java b/scim-server/src/test/java/org/apache/directory/scim/server/rest/BulkResourceImplTest.java
new file mode 100644
index 0000000..514773d
--- /dev/null
+++ b/scim-server/src/test/java/org/apache/directory/scim/server/rest/BulkResourceImplTest.java
@@ -0,0 +1,230 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.directory.scim.server.rest;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.ObjectWriter;
+import jakarta.enterprise.inject.Instance;
+import jakarta.ws.rs.core.Response;
+import jakarta.ws.rs.core.UriBuilder;
+import jakarta.ws.rs.core.UriInfo;
+import org.apache.directory.scim.server.exception.UnableToCreateResourceException;
+import org.apache.directory.scim.server.repository.Repository;
+import org.apache.directory.scim.server.repository.RepositoryRegistry;
+import org.apache.directory.scim.server.schema.SchemaRegistry;
+import org.apache.directory.scim.spec.extension.ScimExtensionRegistry;
+import org.apache.directory.scim.spec.json.ObjectMapperFactory;
+import org.apache.directory.scim.spec.protocol.data.BulkOperation;
+import org.apache.directory.scim.spec.protocol.data.BulkRequest;
+import org.apache.directory.scim.spec.protocol.data.BulkResponse;
+import org.apache.directory.scim.spec.protocol.data.ErrorResponse;
+import org.apache.directory.scim.spec.resources.ScimGroup;
+import org.apache.directory.scim.spec.resources.ScimResource;
+import org.apache.directory.scim.spec.resources.ScimUser;
+import org.apache.directory.scim.spec.schema.ResourceReference;
+import org.junit.jupiter.api.Test;
+import org.mockito.InOrder;
+
+import java.net.URI;
+import java.util.Collections;
+import java.util.List;
+import java.util.stream.Stream;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.atLeast;
+import static org.mockito.Mockito.inOrder;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class BulkResourceImplTest {
+
+ @Test
+ public void bulkIdTemporaryIdentifiersTest() throws Exception {
+ // Request copied from RFC 7644 section 3.7.2
+ ScimUser alice = new ScimUser()
+ .setUserName("Alice");
+
+ ScimGroup tourGuides = new ScimGroup()
+ .setDisplayName("Tour Guides")
+ .setMembers(List.of(new ResourceReference()
+ .setType(ResourceReference.ReferenceType.USER)
+ .setValue("bulkId:qwerty")));
+
+ BulkRequest bulkRequest = new BulkRequest()
+ .setOperations(List.of(
+ new BulkOperation()
+ .setMethod(BulkOperation.Method.POST)
+ .setPath("/Users")
+ .setBulkId("qwerty")
+ .setData(alice),
+ new BulkOperation()
+ .setMethod(BulkOperation.Method.POST)
+ .setPath("/Groups")
+ .setBulkId("ytrewq")
+ .setData(tourGuides)));
+
+ Instance<Repository<? extends ScimResource>> emptyInstance = mock(Instance.class);
+ when(emptyInstance.stream()).thenReturn(Stream.empty());
+
+ SchemaRegistry schemaRegistry = new SchemaRegistry();
+ RepositoryRegistry repositoryRegistry = new RepositoryRegistry(schemaRegistry, ScimExtensionRegistry.getInstance(), emptyInstance);
+
+ Instance<Repository<ScimUser>> userRepositoryInstance = mock(Instance.class);
+ Repository<ScimUser> userRepository = mock(Repository.class);
+ ScimUser user = new ScimUser();
+ user.setId("alice-id");
+ when(userRepositoryInstance.get()).thenReturn(userRepository);
+ repositoryRegistry.registerRepository(ScimUser.class, userRepository);
+ when(userRepository.create(any())).thenReturn(user);
+
+ Instance<Repository<ScimGroup>> groupProviderInstance = mock(Instance.class);
+ Repository<ScimGroup> groupRepository = mock(Repository.class);
+ ScimGroup group = new ScimGroup();
+ group.setId("tour-guides");
+ when(groupProviderInstance.get()).thenReturn(groupRepository);
+ repositoryRegistry.registerRepository(ScimGroup.class, groupRepository);
+ when(groupRepository.getExtensionList()).thenReturn(Collections.emptyList());
+ when(groupRepository.create(any())).thenReturn(group);
+
+ BulkResourceImpl impl = new BulkResourceImpl(schemaRegistry, repositoryRegistry);
+ UriInfo uriInfo = mock(UriInfo.class);
+ UriBuilder uriBuilder = mock(UriBuilder.class);
+ when(uriInfo.getBaseUriBuilder()).thenReturn(uriBuilder);
+ when(uriBuilder.path("/Users")).thenReturn(uriBuilder);
+ when(uriBuilder.path("alice-id")).thenReturn(uriBuilder);
+ when(uriBuilder.build())
+ .thenReturn(URI.create("https://scim.example.com/Users/alice-id"))
+ .thenReturn(URI.create("https://scim.example.com/Groups/tour-guides"));
+ when(uriBuilder.path("/Groups")).thenReturn(uriBuilder);
+ when(uriBuilder.path("tour-guides")).thenReturn(uriBuilder);
+
+ Response response = impl.doBulk(bulkRequest, uriInfo);
+ BulkResponse bulkResponse = (BulkResponse) response.getEntity();
+
+ assertThat(bulkResponse.getErrorResponse()).isNull();
+ assertThat(bulkResponse.getStatus()).isEqualTo(Response.Status.OK);
+ assertThat(bulkResponse.getSchemas()).containsOnly(BulkResponse.SCHEMA_URI);
+ assertThat(bulkResponse.getOperations())
+ .hasSize(2)
+ .contains(new BulkOperation()
+ .setMethod(BulkOperation.Method.POST)
+ .setBulkId("qwerty")
+ .setData(new ScimUser()
+ .setId("alice-id"))
+ .setLocation("https://scim.example.com/Users/alice-id")
+ .setStatus(new BulkOperation.StatusWrapper(Response.Status.CREATED)))
+ .contains(new BulkOperation()
+ .setMethod(BulkOperation.Method.POST)
+ .setBulkId("ytrewq")
+ .setData(new ScimGroup()
+ .setId("tour-guides"))
+ .setLocation("https://scim.example.com/Groups/tour-guides")
+ .setStatus(new BulkOperation.StatusWrapper(Response.Status.CREATED)));
+
+ // Verify behavior
+ InOrder inOrder = inOrder(userRepository, groupRepository);
+ inOrder.verify(userRepository, atLeast(1)).getExtensionList();
+ inOrder.verify(groupRepository, atLeast(1)).getExtensionList();
+
+ // User was created before group due to calculated dependency
+ inOrder.verify(userRepository).create(alice);
+ inOrder.verify(groupRepository).create(tourGuides);
+ inOrder.verifyNoMoreInteractions();
+ }
+
+ @Test
+ public void bulkFailedTest() throws Exception {
+ ScimUser alice = new ScimUser()
+ .setUserName("Alice");
+ ScimUser bob = new ScimUser()
+ .setUserName("Bob");
+
+ BulkRequest bulkRequest = new BulkRequest()
+ .setFailOnErrors(1)
+ .setOperations(List.of(
+ new BulkOperation()
+ .setMethod(BulkOperation.Method.POST)
+ .setPath("/Users")
+ .setBulkId("bulk-id-alice")
+ .setData(alice),
+ new BulkOperation()
+ .setMethod(BulkOperation.Method.POST)
+ .setPath("/Users")
+ .setBulkId("bulk-id-bob")
+ .setData(bob)
+ ));
+ Instance<Repository<? extends ScimResource>> emptyInstance = mock(Instance.class);
+ when(emptyInstance.stream()).thenReturn(Stream.empty());
+
+ SchemaRegistry schemaRegistry = new SchemaRegistry();
+ RepositoryRegistry repositoryRegistry = new RepositoryRegistry(schemaRegistry, ScimExtensionRegistry.getInstance(), emptyInstance );
+
+ Instance<Repository<ScimUser>> userProviderInstance = mock(Instance.class);
+ Repository<ScimUser> userRepository = mock(Repository.class);
+
+ when(userProviderInstance.get()).thenReturn(userRepository);
+ repositoryRegistry.registerRepository(ScimUser.class, userRepository);
+ when(userProviderInstance.get()).thenReturn(userRepository);
+
+ ScimUser userAlice = new ScimUser();
+ userAlice.setId("alice-id");
+
+ ScimUser userBob = new ScimUser();
+ userBob.setId("bob-id");
+
+ when(userRepository.create(any()))
+ .thenReturn(userAlice)
+ .thenThrow(new UnableToCreateResourceException(Response.Status.BAD_REQUEST, "Expected Test Exception when bob is created"));
+
+
+ BulkResourceImpl impl = new BulkResourceImpl(schemaRegistry, repositoryRegistry);
+ UriInfo uriInfo = mock(UriInfo.class);
+ UriBuilder uriBuilder = mock(UriBuilder.class);
+ when(uriInfo.getBaseUriBuilder()).thenReturn(uriBuilder);
+ when(uriBuilder.path("/Users")).thenReturn(uriBuilder);
+ when(uriBuilder.path("alice-id")).thenReturn(uriBuilder);
+ when(uriBuilder.path("bob-id")).thenReturn(uriBuilder);
+ when(uriBuilder.build())
+ .thenReturn(URI.create("https://scim.example.com/Users/alice-id"))
+ .thenReturn(URI.create("https://scim.example.com/Users/bob-id"));
+
+ Response response = impl.doBulk(bulkRequest, uriInfo);
+ BulkResponse bulkResponse = (BulkResponse) response.getEntity();
+
+ assertThat(bulkResponse.getErrorResponse()).isNull();
+ assertThat(bulkResponse.getStatus()).isEqualTo(Response.Status.BAD_REQUEST);
+ assertThat(bulkResponse.getSchemas()).containsOnly(BulkResponse.SCHEMA_URI);
+ assertThat(bulkResponse.getOperations())
+ .hasSize(2)
+ .contains(new BulkOperation()
+ .setMethod(BulkOperation.Method.POST)
+ .setBulkId("bulk-id-alice")
+ .setData(new ScimUser()
+ .setId("alice-id"))
+ .setLocation("https://scim.example.com/Users/alice-id")
+ .setStatus(new BulkOperation.StatusWrapper(Response.Status.CREATED)))
+ .contains(new BulkOperation()
+ .setMethod(BulkOperation.Method.POST)
+ .setBulkId("bulk-id-bob")
+ .setResponse(new ErrorResponse(Response.Status.BAD_REQUEST, "Expected Test Exception when bob is created"))
+ .setStatus(new BulkOperation.StatusWrapper(Response.Status.BAD_REQUEST)));
+ }
+}
diff --git a/scim-spec/scim-spec-schema/src/main/java/org/apache/directory/scim/spec/json/ObjectMapperFactory.java b/scim-spec/scim-spec-schema/src/main/java/org/apache/directory/scim/spec/json/ObjectMapperFactory.java
index 6421434..747006c 100644
--- a/scim-spec/scim-spec-schema/src/main/java/org/apache/directory/scim/spec/json/ObjectMapperFactory.java
+++ b/scim-spec/scim-spec-schema/src/main/java/org/apache/directory/scim/spec/json/ObjectMapperFactory.java
@@ -29,7 +29,13 @@ import com.fasterxml.jackson.module.jakarta.xmlbind.JakartaXmlBindAnnotationModu
public class ObjectMapperFactory {
+ private final static ObjectMapper objectMapper = createObjectMapper();
+
public static ObjectMapper getObjectMapper() {
+ return objectMapper;
+ }
+
+ private static ObjectMapper createObjectMapper() {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
diff --git a/scim-spec/scim-spec-schema/src/main/java/org/apache/directory/scim/spec/resources/ScimResource.java b/scim-spec/scim-spec-schema/src/main/java/org/apache/directory/scim/spec/resources/ScimResource.java
index 596a244..c84d9ca 100644
--- a/scim-spec/scim-spec-schema/src/main/java/org/apache/directory/scim/spec/resources/ScimResource.java
+++ b/scim-spec/scim-spec-schema/src/main/java/org/apache/directory/scim/spec/resources/ScimResource.java
@@ -59,7 +59,7 @@ public abstract class ScimResource extends BaseResource implements Serializable
private static final Logger LOG = LoggerFactory.getLogger(ScimResource.class);
- private final ObjectMapper objectMapper = ObjectMapperFactory.getObjectMapper();
+ private transient final ObjectMapper objectMapper = ObjectMapperFactory.getObjectMapper();
@XmlElement
@NotNull
diff --git a/scim-spec/scim-spec-schema/src/main/java/org/apache/directory/scim/spec/schema/ResourceReference.java b/scim-spec/scim-spec-schema/src/main/java/org/apache/directory/scim/spec/schema/ResourceReference.java
index 55af15f..d142c75 100644
--- a/scim-spec/scim-spec-schema/src/main/java/org/apache/directory/scim/spec/schema/ResourceReference.java
+++ b/scim-spec/scim-spec-schema/src/main/java/org/apache/directory/scim/spec/schema/ResourceReference.java
@@ -42,7 +42,9 @@ public class ResourceReference implements Serializable {
@XmlEnum
public enum ReferenceType {
@XmlEnumValue("direct") DIRECT,
- @XmlEnumValue("indirect") INDIRECT
+ @XmlEnumValue("indirect") INDIRECT,
+ @XmlEnumValue("User") USER,
+ @XmlEnumValue("Group") GROUP;
}
@ScimAttribute(description="Reference Element Identifier")