diff --git a/oak-security-spi/src/main/java/org/apache/jackrabbit/oak/spi/security/principal/PrincipalProvider.java b/oak-security-spi/src/main/java/org/apache/jackrabbit/oak/spi/security/principal/PrincipalProvider.java
index 5291275d6c..69182f233a 100644
--- a/oak-security-spi/src/main/java/org/apache/jackrabbit/oak/spi/security/principal/PrincipalProvider.java
+++ b/oak-security-spi/src/main/java/org/apache/jackrabbit/oak/spi/security/principal/PrincipalProvider.java
@@ -21,6 +21,11 @@ import java.security.acl.Group;
import java.util.Collections;
import java.util.Iterator;
import java.util.Set;
+import java.util.Spliterator;
+import java.util.Spliterators;
+import java.util.stream.Stream;
+import java.util.stream.StreamSupport;
+
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.osgi.annotation.versioning.ProviderType;
@@ -116,6 +121,36 @@ public interface PrincipalProvider {
@NotNull
Iterator extends Principal> findPrincipals(@Nullable String nameHint, int searchType);
+ /**
+ * Find the principals that match the specified nameHint and search type.
+ *
+ * @param nameHint A name hint to use for non-exact matching.
+ * @param searchType Limit the search to certain types of principals. Valid
+ * values are any of
+ *
- {@link org.apache.jackrabbit.api.security.principal.PrincipalManager#SEARCH_TYPE_ALL}
+ * - {@link org.apache.jackrabbit.api.security.principal.PrincipalManager#SEARCH_TYPE_NOT_GROUP}
+ * - {@link org.apache.jackrabbit.api.security.principal.PrincipalManager#SEARCH_TYPE_GROUP}
+ * @param offset Offset from where to start returning results. 0 for no offset.
+ * @param limit Maximal number of results to return. -1 for no limit.
+ * @return An iterator of principals.
+ * @throws IllegalArgumentException if {@code offset} is negative
+ */
+ @NotNull
+ default Iterator extends Principal> findPrincipals(@Nullable String nameHint, int searchType, long offset, long limit) {
+ if (offset < 0) {
+ throw new IllegalArgumentException(Long.toString(offset));
+ }
+ Iterator extends Principal> principals = findPrincipals(nameHint, searchType);
+ Spliterator extends Principal> spliterator = Spliterators.spliteratorUnknownSize(principals, 0);
+ Stream extends Principal> stream = StreamSupport.stream(spliterator, false);
+ if (offset > 0) {
+ stream = stream.skip(offset);
+ }
+ if (limit >= 0) {
+ stream = stream.limit(limit);
+ }
+ return stream.iterator();
+ }
/**
* Find all principals that match the search type.
@@ -129,4 +164,34 @@ public interface PrincipalProvider {
*/
@NotNull
Iterator extends Principal> findPrincipals(int searchType);
+
+ /**
+ * Find all principals that match the search type.
+ *
+ * @param searchType Limit the search to certain types of principals. Valid
+ * values are any of
+ * - {@link org.apache.jackrabbit.api.security.principal.PrincipalManager#SEARCH_TYPE_ALL}
+ * - {@link org.apache.jackrabbit.api.security.principal.PrincipalManager#SEARCH_TYPE_NOT_GROUP}
+ * - {@link org.apache.jackrabbit.api.security.principal.PrincipalManager#SEARCH_TYPE_GROUP}
+ * @param offset Offset from where to start returning results. {@code 0} for no offset.
+ * @param limit Maximal number of results to return. {@code -1} for no limit.
+ * @return An iterator of principals.
+ * @throws IllegalArgumentException if {@code offset} is negative
+ */
+ @NotNull
+ default Iterator extends Principal> findPrincipals(int searchType, long offset, long limit) {
+ if (offset < 0) {
+ throw new IllegalArgumentException(Long.toString(offset));
+ }
+ Iterator extends Principal> principals = findPrincipals(searchType);
+ Spliterator extends Principal> spliterator = Spliterators.spliteratorUnknownSize(principals, 0);
+ Stream extends Principal> stream = StreamSupport.stream(spliterator, false);
+ if (offset > 0) {
+ stream = stream.skip(offset);
+ }
+ if (limit >= 0) {
+ stream = stream.limit(limit);
+ }
+ return stream.iterator();
+ }
}
diff --git a/oak-security-spi/src/main/java/org/apache/jackrabbit/oak/spi/security/principal/package-info.java b/oak-security-spi/src/main/java/org/apache/jackrabbit/oak/spi/security/principal/package-info.java
index ee57ad99b6..014ab7aabe 100644
--- a/oak-security-spi/src/main/java/org/apache/jackrabbit/oak/spi/security/principal/package-info.java
+++ b/oak-security-spi/src/main/java/org/apache/jackrabbit/oak/spi/security/principal/package-info.java
@@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-@Version("1.6.0")
+@Version("1.7.0")
package org.apache.jackrabbit.oak.spi.security.principal;
import org.osgi.annotation.versioning.Version;
diff --git a/oak-security-spi/src/test/java/org/apache/jackrabbit/oak/spi/security/principal/CompositePrincipalProviderTest.java b/oak-security-spi/src/test/java/org/apache/jackrabbit/oak/spi/security/principal/CompositePrincipalProviderTest.java
index f8eac01219..0ced3724e2 100644
--- a/oak-security-spi/src/test/java/org/apache/jackrabbit/oak/spi/security/principal/CompositePrincipalProviderTest.java
+++ b/oak-security-spi/src/test/java/org/apache/jackrabbit/oak/spi/security/principal/CompositePrincipalProviderTest.java
@@ -17,7 +17,9 @@
package org.apache.jackrabbit.oak.spi.security.principal;
import java.security.Principal;
+import java.util.ArrayList;
import java.util.Iterator;
+import java.util.List;
import com.google.common.base.Predicate;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
@@ -135,4 +137,31 @@ public class CompositePrincipalProviderTest {
Iterator extends Principal> result = cpp.findPrincipals(PrincipalManager.SEARCH_TYPE_ALL);
assertIterator(Iterables.concat(ImmutableSet.of(EveryonePrincipal.getInstance()), testPrincipals()), result);
}
+
+ @Test
+ public void testRangeDefault() {
+ String[] pps = new String[] { "p0", "p1", "p2" };
+ PrincipalProvider p = new TestPrincipalProvider(pps);
+ PrincipalProvider cpp = CompositePrincipalProvider.of(ImmutableList.of(p));
+ List expected = ImmutableList.of("p0", "p1", "p2", "everyone");
+ for (int offset = 0; offset < expected.size() + 1; offset++) {
+ for (int limit = -1; limit < expected.size() + 2; limit++) {
+ int to = expected.size();
+ if (limit >= 0) {
+ to = Math.min(offset + limit, to);
+ }
+ List sub = expected.subList(offset, to);
+ Iterator extends Principal> i = cpp.findPrincipals(PrincipalManager.SEARCH_TYPE_ALL, offset, limit);
+ assertEquals(sub, getNames(i));
+ }
+ }
+ }
+
+ private static List getNames(Iterator extends Principal> i) {
+ List l = new ArrayList<>();
+ while (i.hasNext()) {
+ l.add(i.next().getName());
+ }
+ return l;
+ }
}