From 1c083346cdfdf9db08a39fe33ed9eadec068d55f Mon Sep 17 00:00:00 2001 From: Stefan Guilhen Date: Sun, 10 Jan 2021 16:48:35 -0300 Subject: [PATCH] [KEYCLOAK-16373] Document the streamified variant of the user storage interfaces --- server_development/topics.adoc | 1 + .../provider-capability-interfaces.adoc | 1 + .../user-storage/stream-interfaces.adoc | 57 +++++++++++++++++++ 3 files changed, 59 insertions(+) create mode 100644 server_development/topics/user-storage/stream-interfaces.adoc diff --git a/server_development/topics.adoc b/server_development/topics.adoc index d4401f14d4..a2975e4db8 100644 --- a/server_development/topics.adoc +++ b/server_development/topics.adoc @@ -30,4 +30,5 @@ include::topics/user-storage/cache.adoc[] include::topics/user-storage/javaee.adoc[] include::topics/user-storage/rest.adoc[] include::topics/user-storage/migration.adoc[] +include::topics/user-storage/stream-interfaces.adoc[] include::topics/vault.adoc[] diff --git a/server_development/topics/user-storage/provider-capability-interfaces.adoc b/server_development/topics/user-storage/provider-capability-interfaces.adoc index 322a59be49..ff10c75743 100644 --- a/server_development/topics/user-storage/provider-capability-interfaces.adoc +++ b/server_development/topics/user-storage/provider-capability-interfaces.adoc @@ -1,3 +1,4 @@ +[[_provider_capability_interfaces]] === Provider Capability Interfaces diff --git a/server_development/topics/user-storage/stream-interfaces.adoc b/server_development/topics/user-storage/stream-interfaces.adoc new file mode 100644 index 0000000000..fcd5c8711d --- /dev/null +++ b/server_development/topics/user-storage/stream-interfaces.adoc @@ -0,0 +1,57 @@ + +=== Stream-based Interfaces + +Many of the user storage interfaces in {project_name} contain query methods that can return potentially large sets of objects, +which might lead to significant impacts in terms of memory consumption and processing time. This is especially true when only +a small subset of the objects' internal state is used in the query method's logic. + +To provide developers with a more efficient alternative to process large data sets in these query methods, a `Streams` +sub-interface has been added to user storage interfaces. These `Streams` sub-interfaces replace the original collection-based +methods in the super-interfaces with stream-based variants, making the collection-based methods default. The default implementation +of a collection-based query method invokes its `Stream` counterpart and collects the result into the proper collection type. + +The `Streams` sub-interfaces allow for implementations to focus on the stream-based approach for processing sets of data and +benefit from the potential memory and performance optimizations of that approach. The interfaces that offer a `Streams` +sub-interface to be implemented include a few _<<_provider_capability_interfaces,capability interfaces>>_, all interfaces in the `org.keycloak.storage.federated` +package and a few others that might be implemented depending on the scope of the custom storage implementation. + +See this list of the interfaces that offer a `Streams` sub-interface to developers. + +|=== +| Package | Classes +ifeval::[{project_community}==true] +| `org.keycloak.credential` | `CredentialInputUpdater`(*), `UserCredentialStore` +| `org.keycloak.models` | `GroupModel`, `RoleMapperModel`, `UserCredentialManager`, `UserModel`, `UserProvider` +| `org.keycloak.models.cache` | `CachedUserModel`, `UserCache` +| `org.keycloak.storage.federated` | All interfaces +| `org.kecyloak.storage.user` | `UserQueryProvider`(*) +endif::[] +ifeval::[{project_product}==true] +| `org.keycloak.credential` | `CredentialInputUpdater`(*) +| `org.keycloak.models` | `GroupModel`, `RoleMapperModel`, `UserModel` +| `org.keycloak.storage.federated` | All interfaces +| `org.kecyloak.storage.user` | `UserQueryProvider`(*) +endif::[] +|=== +(*) indicates the interface is a _<<_provider_capability_interfaces,capability interface>>_ + +Custom user storage implementation that want to benefit from the streams approach should simply implement the `Streams` +sub-interfaces instead of the original interfaces. For example, the following code uses the `Streams` variant of the `UserQueryProvider` +interface: + +[source,java] +---- +public class CustomQueryProvider extends UserQueryProvider.Streams { +... + @Override + Stream getUsersStream(RealmModel realm, Integer firstResult, Integer maxResults) { + // custom logic here + } + + @Override + Stream searchForUserStream(String search, RealmModel realm) { + // custom logic here + } +... +} +---- \ No newline at end of file