Copilot commented on code in PR #1025:
URL:
https://github.com/apache/directory-scimple/pull/1025#discussion_r2823275990
##########
scim-server-examples/scim-server-quarkus/src/main/java/org/apache/directory/scim/example/quarkus/service/InMemoryUserService.java:
##########
@@ -179,23 +176,20 @@ public void delete(String id) throws ResourceException {
}
/**
- * @see Repository#find(Filter, PageRequest, SortRequest, java.util.Set,
java.util.Set)
+ * @see Repository#find(Filter, ScimRequestContext)
*/
@Override
- public FilterResponse<ScimUser> find(Filter filter, PageRequest pageRequest,
SortRequest sortRequest, Set<AttributeReference> includedAttributes,
Set<AttributeReference> excludedAttributes) {
-
- long count = pageRequest.getCount() != null ? pageRequest.getCount() :
users.size();
- long startIndex = pageRequest.getStartIndex() != null
- ? pageRequest.getStartIndex() - 1 // SCIM is 1-based indexed
- : 0;
+ public FilterResponse<ScimUser> find(Filter filter, ScimRequestContext
requestContext) {
+ long count =
requestContext.getPageRequest().map(PageRequest::getCount).orElse(users.size());
+ long startIndex =
requestContext.getPageRequest().map(PageRequest::getStartIndex).map(it -> it -
1).orElse(0);
List<ScimUser> result = users.values().stream()
.skip(startIndex)
.limit(count)
.filter(FilterExpressions.inMemory(filter,
schemaRegistry.getSchema(ScimUser.SCHEMA_URI)))
.collect(Collectors.toList());
- return new FilterResponse<>(result, pageRequest, result.size());
+ return new FilterResponse<>(result, result.size());
Review Comment:
Pagination is applied before filtering (`skip/limit` happen upstream of the
`filter`), which can return the wrong page for a given SCIM filter. Also,
`totalResults` is currently derived from the paged `result.size()`; SCIM
`totalResults` should reflect the total number of matches *before* pagination.
Consider applying the filter first, computing total matches, then applying
`skip/limit` for the requested page.
##########
scim-core/src/main/java/org/apache/directory/scim/core/repository/ScimRequestContext.java:
##########
@@ -0,0 +1,149 @@
+/*
+ * 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.core.repository;
+
+import org.apache.directory.scim.spec.filter.PageRequest;
+import org.apache.directory.scim.spec.filter.SortRequest;
+import org.apache.directory.scim.spec.filter.attribute.AttributeReference;
+
+import java.util.Collections;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.Set;
+
+public class ScimRequestContext {
+
+ private Set<AttributeReference> includedAttributes;
+ private Set<AttributeReference> excludedAttributes;
+ private PageRequest pageRequest;
+ private SortRequest sortRequest;
+
+ /**
+ * Optional ETag(s) in 'If-Match' header. If not null, to avoid dirty
writing, {@code ScimResource.meta.version} must match one of this set (the set
should contain only one element).
+ */
+ private Set<ETag> eTag;
+
+ public ScimRequestContext() {}
+
+ /**
+ * Create a ScimRequestContext object.
+ *
+ * @param includedAttributes optional set of attributes to include from
returned ScimResources, may be used to optimize queries.
+ * @param excludedAttributes optional set of attributes to exclude from
returned ScimResources, may be used to optimize queries.
+ */
+ public ScimRequestContext(Set<AttributeReference> includedAttributes,
+ Set<AttributeReference> excludedAttributes) {
+ this(includedAttributes, excludedAttributes, null, null, Set.of());
+ }
+ /**
+ * Create a ScimRequestContext object.
+ *
+ * @param includedAttributes optional set of attributes to include from
returned ScimResources, may be used to optimize queries.
+ * @param excludedAttributes optional set of attributes to exclude from
returned ScimResources, may be used to optimize queries.
+ * @param pageRequest For paged requests, this object specifies the start
+ * index and number of ScimResources that should be returned.
+ * @param sortRequest Specifies which fields the returned ScimResources
+ * should be sorted by and whether the sort order is ascending or
+ * descending.
+ */
+ public ScimRequestContext(Set<AttributeReference> includedAttributes,
+ Set<AttributeReference> excludedAttributes,
+ PageRequest pageRequest,
+ SortRequest sortRequest,
+ Set<ETag> eTag) {
+ this.includedAttributes = includedAttributes;
+ this.excludedAttributes = excludedAttributes;
+ this.pageRequest = pageRequest;
+ this.sortRequest = sortRequest;
+ this.eTag = eTag != null ? Collections.unmodifiableSet(eTag) : Set.of();
+ }
+
+ public Set<AttributeReference> getIncludedAttributes() {
+ return this.includedAttributes;
+ }
+
+ public ScimRequestContext setIncludedAttributes(Set<AttributeReference>
includedAttributes) {
+ this.includedAttributes = includedAttributes;
+ return this;
+ }
+
+ public Set<AttributeReference> getExcludedAttributes() {
+ return this.excludedAttributes;
+ }
+
+ public ScimRequestContext setExcludedAttributes(Set<AttributeReference>
excludedAttributes) {
+ this.excludedAttributes = excludedAttributes;
+ return this;
+ }
+
+ public Optional<PageRequest> getPageRequest() {
+ return Optional.ofNullable(pageRequest);
+ }
+
+ public ScimRequestContext setPageRequest(PageRequest pageRequest) {
+ this.pageRequest = pageRequest;
+ return this;
+ }
+
+ public SortRequest getSortRequest() {
+ return sortRequest;
+ }
+
+ public ScimRequestContext setSortRequest(SortRequest sortRequest) {
+ this.sortRequest = sortRequest;
+ return this;
+ }
+
+ public Set<ETag> getETag() {
+ return eTag;
+ }
+
+ public ScimRequestContext setETag(Set<ETag> eTag) {
+ this.eTag = eTag;
Review Comment:
`ScimRequestContext#setETag` assigns the provided set directly and allows
`null`, which can make `getETag()` return `null` and break the class’s own
Javadoc/equals/hashCode assumptions. Consider normalizing `null` to an empty
set and wrapping with `Collections.unmodifiableSet(...)` (consistent with the
constructor) to keep the context safe/immutable.
```suggestion
return eTag == null ? Collections.emptySet() : eTag;
}
public ScimRequestContext setETag(Set<ETag> eTag) {
this.eTag = (eTag == null) ? Collections.emptySet() :
Collections.unmodifiableSet(eTag);
```
##########
support/spring-boot/src/test/java/org/apache/directory/scim/spring/it/app/InMemoryUserService.java:
##########
@@ -171,23 +168,20 @@ public void delete(String id) throws ResourceException {
}
/**
- * @see Repository#find(Filter, PageRequest, SortRequest, java.util.Set,
java.util.Set)
+ * @see Repository#find(Filter, ScimRequestContext)
*/
@Override
- public FilterResponse<ScimUser> find(Filter filter, PageRequest pageRequest,
SortRequest sortRequest, Set<AttributeReference> includedAttributes,
Set<AttributeReference> excludedAttributes) {
-
- long count = pageRequest.getCount() != null ? pageRequest.getCount() :
users.size();
- long startIndex = pageRequest.getStartIndex() != null
- ? pageRequest.getStartIndex() - 1 // SCIM is 1-based indexed
- : 0;
+ public FilterResponse<ScimUser> find(Filter filter, ScimRequestContext
requestContext) {
+ long count =
requestContext.getPageRequest().map(PageRequest::getCount).orElse(users.size());
+ long startIndex =
requestContext.getPageRequest().map(PageRequest::getStartIndex).map(it -> it -
1).orElse(0);
List<ScimUser> result = users.values().stream()
.skip(startIndex)
.limit(count)
.filter(FilterExpressions.inMemory(filter,
schemaRegistry.getSchema(ScimUser.SCHEMA_URI)))
.collect(Collectors.toList());
- return new FilterResponse<>(result, pageRequest, result.size());
+ return new FilterResponse<>(result, result.size());
Review Comment:
Pagination is applied before filtering (`skip/limit` happen upstream of the
`filter`), which can return the wrong page for a given SCIM filter. Also,
`totalResults` is currently derived from the paged `result.size()`; SCIM
`totalResults` should reflect the total number of matches *before* pagination.
Consider applying the filter first, computing total matches, then applying
`skip/limit` for the requested page.
##########
scim-server-examples/scim-server-spring-boot-4/src/main/java/org/apache/directory/scim/example/spring/service/InMemoryGroupService.java:
##########
@@ -132,19 +129,17 @@ public void delete(String id) throws
ResourceNotFoundException {
}
@Override
- public FilterResponse<ScimGroup> find(Filter filter, PageRequest
pageRequest, SortRequest sortRequest, Set<AttributeReference>
includedAttributes, Set<AttributeReference> excludedAttributes) {
- long count = pageRequest.getCount() != null ? pageRequest.getCount() :
groups.size();
- long startIndex = pageRequest.getStartIndex() != null
- ? pageRequest.getStartIndex() - 1 // SCIM is 1-based indexed
- : 0;
+ public FilterResponse<ScimGroup> find(Filter filter, ScimRequestContext
requestContext) {
+ long count =
requestContext.getPageRequest().map(PageRequest::getCount).orElse(groups.size());
+ long startIndex =
requestContext.getPageRequest().map(PageRequest::getStartIndex).map(it -> it -
1).orElse(0);
List<ScimGroup> result = groups.values().stream()
.skip(startIndex)
.limit(count)
.filter(FilterExpressions.inMemory(filter,
schemaRegistry.getSchema(ScimGroup.SCHEMA_URI)))
.collect(Collectors.toList());
- return new FilterResponse<>(result, pageRequest, result.size());
+ return new FilterResponse<>(result, result.size());
Review Comment:
Pagination is applied before filtering (`skip/limit` happen upstream of the
`filter`), which can return the wrong page for a given SCIM filter. Also,
`totalResults` is currently derived from the paged `result.size()`; SCIM
`totalResults` should reflect the total number of matches *before* pagination.
Consider applying the filter first, computing total matches, then applying
`skip/limit` for the requested page.
##########
scim-server-examples/scim-server-jersey-4/src/main/java/org/apache/directory/scim/example/jersey4/service/InMemoryUserService.java:
##########
@@ -180,23 +177,20 @@ public void delete(String id) throws ResourceException {
}
/**
- * @see Repository#find(Filter, PageRequest, SortRequest, java.util.Set,
java.util.Set)
+ * @see Repository#find(Filter, ScimRequestContext)
*/
@Override
- public FilterResponse<ScimUser> find(Filter filter, PageRequest pageRequest,
SortRequest sortRequest, Set<AttributeReference> includedAttributes,
Set<AttributeReference> excludedAttributes) {
-
- long count = pageRequest.getCount() != null ? pageRequest.getCount() :
users.size();
- long startIndex = pageRequest.getStartIndex() != null
- ? pageRequest.getStartIndex() - 1 // SCIM is 1-based indexed
- : 0;
+ public FilterResponse<ScimUser> find(Filter filter, ScimRequestContext
requestContext) {
+ long count =
requestContext.getPageRequest().map(PageRequest::getCount).orElse(users.size());
+ long startIndex =
requestContext.getPageRequest().map(PageRequest::getStartIndex).map(it -> it -
1).orElse(0);
List<ScimUser> result = users.values().stream()
.skip(startIndex)
.limit(count)
.filter(FilterExpressions.inMemory(filter,
schemaRegistry.getSchema(ScimUser.SCHEMA_URI)))
.collect(Collectors.toList());
- return new FilterResponse<>(result, pageRequest, result.size());
+ return new FilterResponse<>(result, result.size());
Review Comment:
Pagination is applied before filtering (`skip/limit` happen upstream of the
`filter`), which can return the wrong page for a given SCIM filter. Also,
`totalResults` is currently derived from the paged `result.size()`; SCIM
`totalResults` should reflect the total number of matches *before* pagination.
Consider applying the filter first, computing total matches, then applying
`skip/limit` for the requested page.
##########
MIGRATION_GUIDE.md:
##########
@@ -0,0 +1,243 @@
+# Migration Guide
+
+## Migrating from `1.0.0-M1` to `1.0.0`
+
+This guide covers the breaking changes to the
`org.apache.directory.scim.core.repository.Repository` interface and how to
update your implementations.
+
+> [!CAUTION]
+> The `Repository` interface has **breaking changes** that require updates to
all implementations.
+
+---
+
+## Summary of Changes
+
+The `Repository` interface has been refactored to use `ScimRequestContext`
instead of passing individual parameters. This consolidates request metadata
(included/excluded attributes, pagination, sorting, and ETags) into a single
context object.
+
+### Key Changes
+
+1. **Package Change**: `ScimRequestContext` moved from
`org.apache.directory.scim.spec` to `org.apache.directory.scim.core.repository`
+2. **ETag Handling**: ETag information is now accessed via
`ScimRequestContext.getETag()` instead of being a separate method parameter
+3. **Simplified Signatures**: All methods now use `ScimRequestContext` to
consolidate request metadata
+
+### Method Signature Changes
+
+| Method | Old Signature (1.0.0-M1) | New Signature (1.0.0) |
+|--------|--------------------------|----------------------|
+| `create` | `create(T)` | `create(T, ScimRequestContext)` |
+| `get` | `get(String)` | `get(String, ScimRequestContext)` |
+| `find` | `find(Filter, PageRequest, SortRequest)` | `find(Filter,
ScimRequestContext)` |
+| `update` | `update(String, String, T, Set<AttributeReference>,
Set<AttributeReference>)` | `update(String, T, ScimRequestContext)` |
+| `patch` | `patch(String, String, List<PatchOperation>,
Set<AttributeReference>, Set<AttributeReference>)` | `patch(String,
List<PatchOperation>, ScimRequestContext)` |
Review Comment:
The migration guide lists the old `ScimRequestContext` package as
`org.apache.directory.scim.spec` and shows old method signatures like
`create(T)`/`get(String)` and `update(String, String, ...)`, but the pre-change
code used `org.apache.directory.scim.spec.filter.attribute.ScimRequestContext`
and repository methods included included/excluded attribute sets plus
`Set<ETag>` (not a `String` version). Updating the package/method-signature
examples here will prevent misleading migrations.
```suggestion
1. **Package Change**: `ScimRequestContext` moved from
`org.apache.directory.scim.spec.filter.attribute` to
`org.apache.directory.scim.core.repository`
2. **ETag Handling**: ETag information is now accessed via
`ScimRequestContext.getETags()` instead of being passed as a separate
`Set<ETag>` method parameter
3. **Simplified Signatures**: All methods now use `ScimRequestContext` to
consolidate request metadata
### Method Signature Changes
| Method | Old Signature (1.0.0-M1) | New Signature (1.0.0) |
|--------|--------------------------|----------------------|
| `create` | `create(T, Set<AttributeReference>, Set<AttributeReference>,
Set<ETag>)` | `create(T, ScimRequestContext)` |
| `get` | `get(String, Set<AttributeReference>, Set<AttributeReference>,
Set<ETag>)` | `get(String, ScimRequestContext)` |
| `find` | `find(Filter, PageRequest, SortRequest, Set<AttributeReference>,
Set<AttributeReference>, Set<ETag>)` | `find(Filter, ScimRequestContext)` |
| `update` | `update(String, T, Set<AttributeReference>,
Set<AttributeReference>, Set<ETag>)` | `update(String, T, ScimRequestContext)` |
| `patch` | `patch(String, List<PatchOperation>, Set<AttributeReference>,
Set<AttributeReference>, Set<ETag>)` | `patch(String, List<PatchOperation>,
ScimRequestContext)` |
```
##########
scim-server-examples/scim-server-spring-boot-4/src/main/java/org/apache/directory/scim/example/spring/service/InMemoryUserService.java:
##########
@@ -175,23 +172,20 @@ public void delete(String id) throws ResourceException {
}
/**
- * @see Repository#find(Filter, PageRequest, SortRequest, java.util.Set,
java.util.Set)
+ * @see Repository#find(Filter, ScimRequestContext)
*/
@Override
- public FilterResponse<ScimUser> find(Filter filter, PageRequest pageRequest,
SortRequest sortRequest, Set<AttributeReference> includedAttributes,
Set<AttributeReference> excludedAttributes) {
-
- long count = pageRequest.getCount() != null ? pageRequest.getCount() :
users.size();
- long startIndex = pageRequest.getStartIndex() != null
- ? pageRequest.getStartIndex() - 1 // SCIM is 1-based indexed
- : 0;
+ public FilterResponse<ScimUser> find(Filter filter, ScimRequestContext
requestContext) {
+ long count =
requestContext.getPageRequest().map(PageRequest::getCount).orElse(users.size());
+ long startIndex =
requestContext.getPageRequest().map(PageRequest::getStartIndex).map(it -> it -
1).orElse(0);
List<ScimUser> result = users.values().stream()
.skip(startIndex)
.limit(count)
.filter(FilterExpressions.inMemory(filter,
schemaRegistry.getSchema(ScimUser.SCHEMA_URI)))
.collect(Collectors.toList());
- return new FilterResponse<>(result, pageRequest, result.size());
+ return new FilterResponse<>(result, result.size());
Review Comment:
Pagination is applied before filtering (`skip/limit` happen upstream of the
`filter`), which can return the wrong page for a given SCIM filter. Also,
`totalResults` is currently derived from the paged `result.size()`; SCIM
`totalResults` should reflect the total number of matches *before* pagination.
Consider applying the filter first, computing total matches, then applying
`skip/limit` for the requested page.
##########
scim-server-examples/scim-server-spring-boot/src/main/java/org/apache/directory/scim/example/spring/service/InMemoryGroupService.java:
##########
@@ -132,19 +129,17 @@ public void delete(String id) throws
ResourceNotFoundException {
}
@Override
- public FilterResponse<ScimGroup> find(Filter filter, PageRequest
pageRequest, SortRequest sortRequest, Set<AttributeReference>
includedAttributes, Set<AttributeReference> excludedAttributes) {
- long count = pageRequest.getCount() != null ? pageRequest.getCount() :
groups.size();
- long startIndex = pageRequest.getStartIndex() != null
- ? pageRequest.getStartIndex() - 1 // SCIM is 1-based indexed
- : 0;
+ public FilterResponse<ScimGroup> find(Filter filter, ScimRequestContext
requestContext) {
+ long count =
requestContext.getPageRequest().map(PageRequest::getCount).orElse(groups.size());
+ long startIndex =
requestContext.getPageRequest().map(PageRequest::getStartIndex).map(it -> it -
1).orElse(0);
List<ScimGroup> result = groups.values().stream()
.skip(startIndex)
.limit(count)
.filter(FilterExpressions.inMemory(filter,
schemaRegistry.getSchema(ScimGroup.SCHEMA_URI)))
.collect(Collectors.toList());
- return new FilterResponse<>(result, pageRequest, result.size());
+ return new FilterResponse<>(result, result.size());
Review Comment:
Pagination is applied before filtering (`skip/limit` happen upstream of the
`filter`), which can return the wrong page for a given SCIM filter. Also,
`totalResults` is currently derived from the paged `result.size()`; SCIM
`totalResults` should reflect the total number of matches *before* pagination.
Consider applying the filter first, computing total matches, then applying
`skip/limit` for the requested page.
##########
scim-server-examples/scim-server-quarkus/src/main/java/org/apache/directory/scim/example/quarkus/service/InMemoryGroupService.java:
##########
@@ -136,19 +133,17 @@ public void delete(String id) throws ResourceException {
}
@Override
- public FilterResponse<ScimGroup> find(Filter filter, PageRequest
pageRequest, SortRequest sortRequest, Set<AttributeReference>
includedAttributes, Set<AttributeReference> excludedAttributes) {
- long count = pageRequest.getCount() != null ? pageRequest.getCount() :
groups.size();
- long startIndex = pageRequest.getStartIndex() != null
- ? pageRequest.getStartIndex() - 1 // SCIM is 1-based indexed
- : 0;
+ public FilterResponse<ScimGroup> find(Filter filter, ScimRequestContext
requestContext) {
+ long count =
requestContext.getPageRequest().map(PageRequest::getCount).orElse(groups.size());
+ long startIndex =
requestContext.getPageRequest().map(PageRequest::getStartIndex).map(it -> it -
1).orElse(0);
List<ScimGroup> result = groups.values().stream()
.skip(startIndex)
.limit(count)
.filter(FilterExpressions.inMemory(filter,
schemaRegistry.getSchema(ScimGroup.SCHEMA_URI)))
.collect(Collectors.toList());
- return new FilterResponse<>(result, pageRequest, result.size());
+ return new FilterResponse<>(result, result.size());
Review Comment:
Pagination is applied before filtering (`skip/limit` happen upstream of the
`filter`), which can return the wrong page for a given SCIM filter. Also,
`totalResults` is currently derived from the paged `result.size()`; SCIM
`totalResults` should reflect the total number of matches *before* pagination.
Consider applying the filter first, computing total matches, then applying
`skip/limit` for the requested page.
##########
scim-server-examples/scim-server-jersey-4/src/main/java/org/apache/directory/scim/example/jersey4/service/InMemoryGroupService.java:
##########
@@ -138,19 +135,17 @@ public void delete(String id) throws ResourceException {
}
@Override
- public FilterResponse<ScimGroup> find(Filter filter, PageRequest
pageRequest, SortRequest sortRequest, Set<AttributeReference>
includedAttributes, Set<AttributeReference> excludedAttributes) {
- long count = pageRequest.getCount() != null ? pageRequest.getCount() :
groups.size();
- long startIndex = pageRequest.getStartIndex() != null
- ? pageRequest.getStartIndex() - 1 // SCIM is 1-based indexed
- : 0;
+ public FilterResponse<ScimGroup> find(Filter filter, ScimRequestContext
requestContext) {
+ long count =
requestContext.getPageRequest().map(PageRequest::getCount).orElse(groups.size());
+ long startIndex =
requestContext.getPageRequest().map(PageRequest::getStartIndex).map(it -> it -
1).orElse(0);
List<ScimGroup> result = groups.values().stream()
- .skip(startIndex)
- .limit(count)
- .filter(FilterExpressions.inMemory(filter,
schemaRegistry.getSchema(ScimGroup.SCHEMA_URI)))
- .collect(Collectors.toList());
+ .skip(startIndex)
+ .limit(count)
+ .filter(FilterExpressions.inMemory(filter,
schemaRegistry.getSchema(ScimGroup.SCHEMA_URI)))
+ .collect(Collectors.toList());
- return new FilterResponse<>(result, pageRequest, result.size());
+ return new FilterResponse<>(result, result.size());
Review Comment:
Pagination is applied before filtering (`skip/limit` happen upstream of the
`filter`), which can return the wrong page for a given SCIM filter. Also,
`totalResults` is currently derived from the paged `result.size()`; SCIM
`totalResults` should reflect the total number of matches *before* pagination.
Consider applying the filter first, computing total matches, then applying
`skip/limit` for the requested page.
##########
scim-server-examples/scim-server-jersey/src/main/java/org/apache/directory/scim/example/jersey/service/InMemoryGroupService.java:
##########
@@ -138,19 +135,17 @@ public void delete(String id) throws ResourceException {
}
@Override
- public FilterResponse<ScimGroup> find(Filter filter, PageRequest
pageRequest, SortRequest sortRequest, Set<AttributeReference>
includedAttributes, Set<AttributeReference> excludedAttributes) {
- long count = pageRequest.getCount() != null ? pageRequest.getCount() :
groups.size();
- long startIndex = pageRequest.getStartIndex() != null
- ? pageRequest.getStartIndex() - 1 // SCIM is 1-based indexed
- : 0;
+ public FilterResponse<ScimGroup> find(Filter filter, ScimRequestContext
requestContext) {
+ long count =
requestContext.getPageRequest().map(PageRequest::getCount).orElse(groups.size());
+ long startIndex =
requestContext.getPageRequest().map(PageRequest::getStartIndex).map(it -> it -
1).orElse(0);
List<ScimGroup> result = groups.values().stream()
.skip(startIndex)
.limit(count)
.filter(FilterExpressions.inMemory(filter,
schemaRegistry.getSchema(ScimGroup.SCHEMA_URI)))
.collect(Collectors.toList());
- return new FilterResponse<>(result, pageRequest, result.size());
+ return new FilterResponse<>(result, result.size());
Review Comment:
Pagination is applied before filtering (`skip/limit` happen upstream of the
`filter`), which can return the wrong page for a given SCIM filter. Also,
`totalResults` is currently derived from the paged `result.size()`; SCIM
`totalResults` should reflect the total number of matches *before* pagination.
Consider applying the filter first, computing total matches, then applying
`skip/limit` for the requested page.
##########
scim-server-examples/scim-server-memory/src/main/java/org/apache/directory/scim/example/memory/service/InMemoryGroupService.java:
##########
@@ -137,19 +133,17 @@ public void delete(String id) throws ResourceException {
}
@Override
- public FilterResponse<ScimGroup> find(Filter filter, PageRequest
pageRequest, SortRequest sortRequest, Set<AttributeReference>
includedAttributes, Set<AttributeReference> excludedAttributes) {
- long count = pageRequest.getCount() != null ? pageRequest.getCount() :
groups.size();
- long startIndex = pageRequest.getStartIndex() != null
- ? pageRequest.getStartIndex() - 1 // SCIM is 1-based indexed
- : 0;
+ public FilterResponse<ScimGroup> find(Filter filter, ScimRequestContext
requestContext) {
+ long count =
requestContext.getPageRequest().map(PageRequest::getCount).orElse(groups.size());
+ long startIndex =
requestContext.getPageRequest().map(PageRequest::getStartIndex).map(it -> it -
1).orElse(0);
List<ScimGroup> result = groups.values().stream()
.skip(startIndex)
.limit(count)
.filter(FilterExpressions.inMemory(filter,
schemaRegistry.getSchema(ScimGroup.SCHEMA_URI)))
.collect(Collectors.toList());
- return new FilterResponse<>(result, pageRequest, result.size());
+ return new FilterResponse<>(result, result.size());
Review Comment:
Pagination is applied before filtering (`skip/limit` happen upstream of the
`filter`), which can return the wrong page for a given SCIM filter. Also,
`totalResults` is currently derived from the paged `result.size()`; SCIM
`totalResults` should reflect the total number of matches *before* pagination.
Consider applying the filter first, computing total matches, then applying
`skip/limit` for the requested page.
##########
scim-server/src/main/java/org/apache/directory/scim/server/rest/BulkResourceImpl.java:
##########
@@ -463,7 +464,7 @@ private void
handleBulkOperationMethod(List<IWishJavaHadTuples> unresolveds, Bul
+ 1);
try {
- repository.update(id, null, scimResource, Collections.emptySet(),
Collections.emptySet());
+ repository.update(id, scimResource, new ScimRequestContext());
Review Comment:
Passing a default `new ScimRequestContext()` here means included/excluded
attributes and ETags are `null` unless the context class defensively defaults
them. Consider constructing the context with explicit empty sets (or a static
`ScimRequestContext.empty()` factory) to avoid repository implementations
having to null-check context fields.
##########
scim-server/src/test/java/org/apache/directory/scim/server/it/testapp/InMemoryGroupService.java:
##########
@@ -136,19 +133,17 @@ public void delete(String id) throws ResourceException {
}
@Override
- public FilterResponse<ScimGroup> find(Filter filter, PageRequest
pageRequest, SortRequest sortRequest, Set<AttributeReference>
includedAttributes, Set<AttributeReference> excludedAttributes) {
- long count = pageRequest.getCount() != null ? pageRequest.getCount() :
groups.size();
- long startIndex = pageRequest.getStartIndex() != null
- ? pageRequest.getStartIndex() - 1 // SCIM is 1-based indexed
- : 0;
+ public FilterResponse<ScimGroup> find(Filter filter, ScimRequestContext
requestContext) {
+ long count =
requestContext.getPageRequest().map(PageRequest::getCount).orElse(groups.size());
+ long startIndex =
requestContext.getPageRequest().map(PageRequest::getStartIndex).map(it -> it -
1).orElse(0);
List<ScimGroup> result = groups.values().stream()
.skip(startIndex)
.limit(count)
.filter(FilterExpressions.inMemory(filter,
schemaRegistry.getSchema(ScimGroup.SCHEMA_URI)))
.collect(Collectors.toList());
- return new FilterResponse<>(result, pageRequest, result.size());
+ return new FilterResponse<>(result, result.size());
Review Comment:
Pagination is applied before filtering (`skip/limit` happen upstream of the
`filter`), which can return the wrong page for a given SCIM filter. Also,
`totalResults` is currently derived from the paged `result.size()`; SCIM
`totalResults` should reflect the total number of matches *before* pagination.
Consider applying the filter first, computing total matches, then applying
`skip/limit` for the requested page.
##########
scim-server/src/main/java/org/apache/directory/scim/server/rest/BulkResourceImpl.java:
##########
@@ -290,7 +291,7 @@ public Response doBulk(BulkRequest request, UriInfo
uriInfo) {
Class<ScimResource> scimResourceClass = (Class<ScimResource>)
scimResource.getClass();
Repository<ScimResource> repository =
repositoryRegistry.getRepository(scimResourceClass);
- repository.update(scimResourceId, null, scimResource,
Collections.emptySet(), Collections.emptySet());
+ repository.update(scimResourceId, scimResource, new
ScimRequestContext());
Review Comment:
Passing a default `new ScimRequestContext()` here means included/excluded
attributes and ETags are `null` unless the context class defensively defaults
them. Consider constructing the context with explicit empty sets (or a static
`ScimRequestContext.empty()` factory) to avoid repository implementations
having to null-check context fields.
```suggestion
repository.update(scimResourceId, scimResource,
ScimRequestContext.empty());
```
##########
scim-server-examples/scim-server-spring-boot/src/main/java/org/apache/directory/scim/example/spring/service/InMemoryUserService.java:
##########
@@ -175,23 +172,20 @@ public void delete(String id) throws ResourceException {
}
/**
- * @see Repository#find(Filter, PageRequest, SortRequest, java.util.Set,
java.util.Set)
+ * @see Repository#find(Filter, ScimRequestContext)
*/
@Override
- public FilterResponse<ScimUser> find(Filter filter, PageRequest pageRequest,
SortRequest sortRequest, Set<AttributeReference> includedAttributes,
Set<AttributeReference> excludedAttributes) {
-
- long count = pageRequest.getCount() != null ? pageRequest.getCount() :
users.size();
- long startIndex = pageRequest.getStartIndex() != null
- ? pageRequest.getStartIndex() - 1 // SCIM is 1-based indexed
- : 0;
+ public FilterResponse<ScimUser> find(Filter filter, ScimRequestContext
requestContext) {
+ long count =
requestContext.getPageRequest().map(PageRequest::getCount).orElse(users.size());
+ long startIndex =
requestContext.getPageRequest().map(PageRequest::getStartIndex).map(it -> it -
1).orElse(0);
List<ScimUser> result = users.values().stream()
.skip(startIndex)
.limit(count)
.filter(FilterExpressions.inMemory(filter,
schemaRegistry.getSchema(ScimUser.SCHEMA_URI)))
.collect(Collectors.toList());
- return new FilterResponse<>(result, pageRequest, result.size());
+ return new FilterResponse<>(result, result.size());
Review Comment:
Pagination is applied before filtering (`skip/limit` happen upstream of the
`filter`), which can return the wrong page for a given SCIM filter. Also,
`totalResults` is currently derived from the paged `result.size()`; SCIM
`totalResults` should reflect the total number of matches *before* pagination.
Consider applying the filter first, computing total matches, then applying
`skip/limit` for the requested page.
##########
scim-server-examples/scim-server-memory/src/main/java/org/apache/directory/scim/example/memory/service/InMemoryUserService.java:
##########
@@ -179,23 +176,20 @@ public void delete(String id) throws ResourceException {
}
/**
- * @see Repository#find(Filter, PageRequest, SortRequest, java.util.Set,
java.util.Set)
+ * @see Repository#find(Filter, ScimRequestContext)
*/
@Override
- public FilterResponse<ScimUser> find(Filter filter, PageRequest pageRequest,
SortRequest sortRequest, Set<AttributeReference> includedAttributes,
Set<AttributeReference> excludedAttributes) {
-
- long count = pageRequest.getCount() != null ? pageRequest.getCount() :
users.size();
- long startIndex = pageRequest.getStartIndex() != null
- ? pageRequest.getStartIndex() - 1 // SCIM is 1-based indexed
- : 0;
+ public FilterResponse<ScimUser> find(Filter filter, ScimRequestContext
requestContext) {
+ long count =
requestContext.getPageRequest().map(PageRequest::getCount).orElse(users.size());
+ long startIndex =
requestContext.getPageRequest().map(PageRequest::getStartIndex).map(it -> it -
1).orElse(0);
List<ScimUser> result = users.values().stream()
.skip(startIndex)
.limit(count)
.filter(FilterExpressions.inMemory(filter,
schemaRegistry.getSchema(ScimUser.SCHEMA_URI)))
.collect(Collectors.toList());
- return new FilterResponse<>(result, pageRequest, result.size());
+ return new FilterResponse<>(result, result.size());
Review Comment:
Pagination is applied before filtering (`skip/limit` happen upstream of the
`filter`), which can return the wrong page for a given SCIM filter. Also,
`totalResults` is currently derived from the paged `result.size()`; SCIM
`totalResults` should reflect the total number of matches *before* pagination.
Consider applying the filter first, computing total matches, then applying
`skip/limit` for the requested page.
##########
MIGRATION_GUIDE.md:
##########
@@ -0,0 +1,243 @@
+# Migration Guide
+
+## Migrating from `1.0.0-M1` to `1.0.0`
+
+This guide covers the breaking changes to the
`org.apache.directory.scim.core.repository.Repository` interface and how to
update your implementations.
+
+> [!CAUTION]
+> The `Repository` interface has **breaking changes** that require updates to
all implementations.
+
+---
+
+## Summary of Changes
+
+The `Repository` interface has been refactored to use `ScimRequestContext`
instead of passing individual parameters. This consolidates request metadata
(included/excluded attributes, pagination, sorting, and ETags) into a single
context object.
+
+### Key Changes
+
+1. **Package Change**: `ScimRequestContext` moved from
`org.apache.directory.scim.spec` to `org.apache.directory.scim.core.repository`
+2. **ETag Handling**: ETag information is now accessed via
`ScimRequestContext.getETag()` instead of being a separate method parameter
+3. **Simplified Signatures**: All methods now use `ScimRequestContext` to
consolidate request metadata
+
+### Method Signature Changes
+
+| Method | Old Signature (1.0.0-M1) | New Signature (1.0.0) |
+|--------|--------------------------|----------------------|
+| `create` | `create(T)` | `create(T, ScimRequestContext)` |
+| `get` | `get(String)` | `get(String, ScimRequestContext)` |
+| `find` | `find(Filter, PageRequest, SortRequest)` | `find(Filter,
ScimRequestContext)` |
+| `update` | `update(String, String, T, Set<AttributeReference>,
Set<AttributeReference>)` | `update(String, T, ScimRequestContext)` |
+| `patch` | `patch(String, String, List<PatchOperation>,
Set<AttributeReference>, Set<AttributeReference>)` | `patch(String,
List<PatchOperation>, ScimRequestContext)` |
+
+---
+
+## New Classes
+
+### `org.apache.directory.scim.core.repository.ETag`
+
+A new `ETag` class has been added to represent HTTP ETags for optimistic
concurrency control:
Review Comment:
This section describes `org.apache.directory.scim.core.repository.ETag` as a
"new" class, but `ETag` already exists in the codebase (it was previously a
parameter to `Repository.update/patch`). Consider rephrasing to avoid implying
a new type was introduced in this release.
```suggestion
## ETag Class
### `org.apache.directory.scim.core.repository.ETag`
The `ETag` class represents HTTP ETags for optimistic concurrency control.
In this release it is accessed via `ScimRequestContext` instead of being passed
as a separate method parameter:
```
##########
scim-server-examples/scim-server-jersey/src/main/java/org/apache/directory/scim/example/jersey/service/InMemoryUserService.java:
##########
@@ -180,23 +177,20 @@ public void delete(String id) throws ResourceException {
}
/**
- * @see Repository#find(Filter, PageRequest, SortRequest, java.util.Set,
java.util.Set)
+ * @see Repository#find(Filter, ScimRequestContext)
*/
@Override
- public FilterResponse<ScimUser> find(Filter filter, PageRequest pageRequest,
SortRequest sortRequest, Set<AttributeReference> includedAttributes,
Set<AttributeReference> excludedAttributes) {
-
- long count = pageRequest.getCount() != null ? pageRequest.getCount() :
users.size();
- long startIndex = pageRequest.getStartIndex() != null
- ? pageRequest.getStartIndex() - 1 // SCIM is 1-based indexed
- : 0;
+ public FilterResponse<ScimUser> find(Filter filter, ScimRequestContext
requestContext) {
+ long count =
requestContext.getPageRequest().map(PageRequest::getCount).orElse(users.size());
+ long startIndex =
requestContext.getPageRequest().map(PageRequest::getStartIndex).map(it -> it -
1).orElse(0);
List<ScimUser> result = users.values().stream()
.skip(startIndex)
.limit(count)
.filter(FilterExpressions.inMemory(filter,
schemaRegistry.getSchema(ScimUser.SCHEMA_URI)))
.collect(Collectors.toList());
- return new FilterResponse<>(result, pageRequest, result.size());
+ return new FilterResponse<>(result, result.size());
Review Comment:
Pagination is applied before filtering (`skip/limit` happen upstream of the
`filter`), which can return the wrong page for a given SCIM filter. Also,
`totalResults` is currently derived from the paged `result.size()`; SCIM
`totalResults` should reflect the total number of matches *before* pagination.
Consider applying the filter first, computing total matches, then applying
`skip/limit` for the requested page.
##########
scim-server/src/main/java/org/apache/directory/scim/server/rest/BulkResourceImpl.java:
##########
@@ -417,7 +418,7 @@ private void
handleBulkOperationMethod(List<IWishJavaHadTuples> unresolveds, Bul
log.debug("Creating {}", scimResource);
- ScimResource newScimResource = repository.create(scimResource,
Collections.emptySet(), Collections.emptySet());
+ ScimResource newScimResource = repository.create(scimResource, new
ScimRequestContext());
Review Comment:
Passing a default `new ScimRequestContext()` here means included/excluded
attributes and ETags are `null` unless the context class defensively defaults
them. Consider constructing the context with explicit empty sets (or a static
`ScimRequestContext.empty()` factory) to avoid repository implementations
having to null-check context fields.
##########
scim-server/src/test/java/org/apache/directory/scim/server/it/testapp/InMemoryUserService.java:
##########
@@ -173,23 +170,20 @@ public void delete(String id) throws ResourceException {
}
/**
- * @see Repository#find(Filter, PageRequest, SortRequest, java.util.Set,
java.util.Set)
+ * @see Repository#find(Filter, ScimRequestContext)
*/
@Override
- public FilterResponse<ScimUser> find(Filter filter, PageRequest pageRequest,
SortRequest sortRequest, Set<AttributeReference> includedAttributes,
Set<AttributeReference> excludedAttributes) {
-
- long count = pageRequest.getCount() != null ? pageRequest.getCount() :
users.size();
- long startIndex = pageRequest.getStartIndex() != null
- ? pageRequest.getStartIndex() - 1 // SCIM is 1-based indexed
- : 0;
+ public FilterResponse<ScimUser> find(Filter filter, ScimRequestContext
requestContext) {
+ long count =
requestContext.getPageRequest().map(PageRequest::getCount).orElse(users.size());
+ long startIndex =
requestContext.getPageRequest().map(PageRequest::getStartIndex).map(it -> it -
1).orElse(0);
List<ScimUser> result = users.values().stream()
.skip(startIndex)
.limit(count)
.filter(FilterExpressions.inMemory(filter,
schemaRegistry.getSchema(ScimUser.SCHEMA_URI)))
.collect(Collectors.toList());
- return new FilterResponse<>(result, pageRequest, result.size());
+ return new FilterResponse<>(result, result.size());
Review Comment:
Pagination is applied before filtering (`skip/limit` happen upstream of the
`filter`), which can return the wrong page for a given SCIM filter. Also,
`totalResults` is currently derived from the paged `result.size()`; SCIM
`totalResults` should reflect the total number of matches *before* pagination.
Consider applying the filter first, computing total matches, then applying
`skip/limit` for the requested page.
##########
MIGRATION_GUIDE.md:
##########
@@ -0,0 +1,243 @@
+# Migration Guide
+
+## Migrating from `1.0.0-M1` to `1.0.0`
+
+This guide covers the breaking changes to the
`org.apache.directory.scim.core.repository.Repository` interface and how to
update your implementations.
+
+> [!CAUTION]
+> The `Repository` interface has **breaking changes** that require updates to
all implementations.
+
+---
+
+## Summary of Changes
+
+The `Repository` interface has been refactored to use `ScimRequestContext`
instead of passing individual parameters. This consolidates request metadata
(included/excluded attributes, pagination, sorting, and ETags) into a single
context object.
+
+### Key Changes
+
+1. **Package Change**: `ScimRequestContext` moved from
`org.apache.directory.scim.spec` to `org.apache.directory.scim.core.repository`
+2. **ETag Handling**: ETag information is now accessed via
`ScimRequestContext.getETag()` instead of being a separate method parameter
+3. **Simplified Signatures**: All methods now use `ScimRequestContext` to
consolidate request metadata
+
+### Method Signature Changes
+
+| Method | Old Signature (1.0.0-M1) | New Signature (1.0.0) |
+|--------|--------------------------|----------------------|
+| `create` | `create(T)` | `create(T, ScimRequestContext)` |
+| `get` | `get(String)` | `get(String, ScimRequestContext)` |
+| `find` | `find(Filter, PageRequest, SortRequest)` | `find(Filter,
ScimRequestContext)` |
+| `update` | `update(String, String, T, Set<AttributeReference>,
Set<AttributeReference>)` | `update(String, T, ScimRequestContext)` |
+| `patch` | `patch(String, String, List<PatchOperation>,
Set<AttributeReference>, Set<AttributeReference>)` | `patch(String,
List<PatchOperation>, ScimRequestContext)` |
+
+---
+
+## New Classes
+
+### `org.apache.directory.scim.core.repository.ETag`
+
+A new `ETag` class has been added to represent HTTP ETags for optimistic
concurrency control:
+
+```java
+import org.apache.directory.scim.core.repository.ETag;
+
+// ETag is used for versioning and optimistic concurrency
+// The constructor takes a value and a boolean indicating if it's a weak ETag
+ETag etag = new ETag("abc123", false); // Strong ETag
+ETag weakEtag = new ETag("abc123", true); // Weak ETag
+
+// Useful methods
+etag.getValue(); // Returns the ETag value
+etag.isWeak(); // Returns true if this is a weak ETag
+```
+
+---
+
+## Migration Steps
+
+### Step 1: Update Imports
+
+Update the import for `ScimRequestContext` - the package has changed:
+
+**Before (1.0.0-M1):**
+```java
+import org.apache.directory.scim.spec.ScimRequestContext;
+```
+
+**After (1.0.0):**
+```java
+import org.apache.directory.scim.core.repository.ScimRequestContext;
+```
Review Comment:
The "Before (1.0.0-M1)" import example uses
`org.apache.directory.scim.spec.ScimRequestContext`, but the removed class was
under `org.apache.directory.scim.spec.filter.attribute.ScimRequestContext`.
Adjusting the import snippet will make the guide match what users will actually
be migrating from.
##########
scim-core/src/main/java/org/apache/directory/scim/core/repository/ScimRequestContext.java:
##########
@@ -0,0 +1,149 @@
+/*
+ * 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.core.repository;
+
+import org.apache.directory.scim.spec.filter.PageRequest;
+import org.apache.directory.scim.spec.filter.SortRequest;
+import org.apache.directory.scim.spec.filter.attribute.AttributeReference;
+
+import java.util.Collections;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.Set;
+
+public class ScimRequestContext {
+
+ private Set<AttributeReference> includedAttributes;
+ private Set<AttributeReference> excludedAttributes;
+ private PageRequest pageRequest;
+ private SortRequest sortRequest;
+
+ /**
+ * Optional ETag(s) in 'If-Match' header. If not null, to avoid dirty
writing, {@code ScimResource.meta.version} must match one of this set (the set
should contain only one element).
+ */
+ private Set<ETag> eTag;
+
+ public ScimRequestContext() {}
+
+ /**
+ * Create a ScimRequestContext object.
+ *
+ * @param includedAttributes optional set of attributes to include from
returned ScimResources, may be used to optimize queries.
+ * @param excludedAttributes optional set of attributes to exclude from
returned ScimResources, may be used to optimize queries.
+ */
+ public ScimRequestContext(Set<AttributeReference> includedAttributes,
+ Set<AttributeReference> excludedAttributes) {
+ this(includedAttributes, excludedAttributes, null, null, Set.of());
+ }
+ /**
+ * Create a ScimRequestContext object.
+ *
+ * @param includedAttributes optional set of attributes to include from
returned ScimResources, may be used to optimize queries.
+ * @param excludedAttributes optional set of attributes to exclude from
returned ScimResources, may be used to optimize queries.
+ * @param pageRequest For paged requests, this object specifies the start
+ * index and number of ScimResources that should be returned.
+ * @param sortRequest Specifies which fields the returned ScimResources
+ * should be sorted by and whether the sort order is ascending or
+ * descending.
+ */
+ public ScimRequestContext(Set<AttributeReference> includedAttributes,
+ Set<AttributeReference> excludedAttributes,
+ PageRequest pageRequest,
+ SortRequest sortRequest,
+ Set<ETag> eTag) {
+ this.includedAttributes = includedAttributes;
+ this.excludedAttributes = excludedAttributes;
+ this.pageRequest = pageRequest;
+ this.sortRequest = sortRequest;
+ this.eTag = eTag != null ? Collections.unmodifiableSet(eTag) : Set.of();
+ }
+
+ public Set<AttributeReference> getIncludedAttributes() {
+ return this.includedAttributes;
+ }
+
+ public ScimRequestContext setIncludedAttributes(Set<AttributeReference>
includedAttributes) {
+ this.includedAttributes = includedAttributes;
+ return this;
+ }
+
+ public Set<AttributeReference> getExcludedAttributes() {
+ return this.excludedAttributes;
+ }
+
Review Comment:
The no-arg `ScimRequestContext` constructor leaves
`includedAttributes`/`excludedAttributes` unset, so
`getIncludedAttributes()`/`getExcludedAttributes()` can return `null`. Since
callers may reasonably treat these as collections, it would be safer to default
them (and `eTag`) to empty sets (or have the getters return
`Collections.emptySet()` when unset).
##########
support/spring-boot/src/test/java/org/apache/directory/scim/spring/it/app/InMemoryGroupService.java:
##########
@@ -130,19 +127,17 @@ public void delete(String id) throws ResourceException {
}
@Override
- public FilterResponse<ScimGroup> find(Filter filter, PageRequest
pageRequest, SortRequest sortRequest, Set<AttributeReference>
includedAttributes, Set<AttributeReference> excludedAttributes) {
- long count = pageRequest.getCount() != null ? pageRequest.getCount() :
groups.size();
- long startIndex = pageRequest.getStartIndex() != null
- ? pageRequest.getStartIndex() - 1 // SCIM is 1-based indexed
- : 0;
+ public FilterResponse<ScimGroup> find(Filter filter, ScimRequestContext
requestContext) {
+ long count =
requestContext.getPageRequest().map(PageRequest::getCount).orElse(groups.size());
+ long startIndex =
requestContext.getPageRequest().map(PageRequest::getStartIndex).map(it -> it -
1).orElse(0);
List<ScimGroup> result = groups.values().stream()
.skip(startIndex)
.limit(count)
.filter(FilterExpressions.inMemory(filter,
schemaRegistry.getSchema(ScimGroup.SCHEMA_URI)))
.collect(Collectors.toList());
- return new FilterResponse<>(result, pageRequest, result.size());
+ return new FilterResponse<>(result, result.size());
Review Comment:
Pagination is applied before filtering (`skip/limit` happen upstream of the
`filter`), which can return the wrong page for a given SCIM filter. Also,
`totalResults` is currently derived from the paged `result.size()`; SCIM
`totalResults` should reflect the total number of matches *before* pagination.
Consider applying the filter first, computing total matches, then applying
`skip/limit` for the requested page.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]