Allow Quarkus configuration to mix different storage providers
Closes #13312
This commit is contained in:
parent
4e83b9be9d
commit
67e2f342a9
9 changed files with 393 additions and 100 deletions
2
.github/workflows/ci.yml
vendored
2
.github/workflows/ci.yml
vendored
|
@ -492,7 +492,7 @@ jobs:
|
|||
|
||||
- name: Run Quarkus Storage Tests
|
||||
run: |
|
||||
./mvnw clean install -nsu -B -f quarkus/tests/pom.xml -Ptest-database -Dtest=PostgreSQLDistTest,DatabaseOptionsDistTest,JPAStoreDistTest,HotRodStoreDistTest | misc/log/trimmer.sh
|
||||
./mvnw clean install -nsu -B -f quarkus/tests/pom.xml -Ptest-database -Dtest=PostgreSQLDistTest,DatabaseOptionsDistTest,JPAStoreDistTest,HotRodStoreDistTest,MixedStoreDistTest | misc/log/trimmer.sh
|
||||
TEST_RESULT=${PIPESTATUS[0]}
|
||||
find . -path '*/target/surefire-reports/*.xml' | zip -q reports-quarkus-tests.zip -@
|
||||
exit $TEST_RESULT
|
||||
|
|
|
@ -47,8 +47,7 @@ public class StorageOptions {
|
|||
|
||||
public static final Option<StorageType> STORAGE = new OptionBuilder<>("storage", StorageType.class)
|
||||
.category(OptionCategory.STORAGE)
|
||||
.description(String.format("Sets a storage mechanism. Possible values are: %s.",
|
||||
String.join(",", String.join(", ", Arrays.stream(StorageType.values()).map(StorageType::name).collect(Collectors.toList())))))
|
||||
.description(String.format("Sets the default storage mechanism for all areas. Possible values are: %s.", storageAreas()))
|
||||
.expectedValues(StorageType.values())
|
||||
.defaultValue(Optional.empty())
|
||||
.hidden()
|
||||
|
@ -60,18 +59,22 @@ public class StorageOptions {
|
|||
.buildTime(true)
|
||||
.build();
|
||||
|
||||
public static final Option<StorageType> STORAGE_EVENT_STORE = new OptionBuilder<>("storage-event-store", StorageType.class)
|
||||
public static final Option<String> STORAGE_EVENT_STORE_PROVIDER = new OptionBuilder<>("storage-event-store-provider", String.class)
|
||||
.category(OptionCategory.STORAGE)
|
||||
.buildTime(true)
|
||||
.build();
|
||||
|
||||
public static final Option<StorageType> STORAGE_EVENT_ADMIN_STORE = new OptionBuilder<>("storage-event-admin", StorageType.class)
|
||||
.category(OptionCategory.STORAGE)
|
||||
.description(descriptionForStorageAreas("admin events"))
|
||||
.expectedValues(StorageType.values())
|
||||
.buildTime(true)
|
||||
.build();
|
||||
|
||||
public static final Option<StorageType> STORAGE_EVENT_AUTH_STORE = new OptionBuilder<>("storage-event-auth", StorageType.class)
|
||||
.category(OptionCategory.STORAGE)
|
||||
.description(descriptionForStorageAreas("authentication and authorization events"))
|
||||
.expectedValues(StorageType.values())
|
||||
.buildTime(true)
|
||||
.build();
|
||||
|
||||
|
@ -80,123 +83,139 @@ public class StorageOptions {
|
|||
.buildTime(true)
|
||||
.build();
|
||||
|
||||
public static final Option<String> STORAGE_REALM = new OptionBuilder<>("storage-realm", String.class)
|
||||
public static final Option<String> STORAGE_REALM_PROVIDER = new OptionBuilder<>("storage-realm-provider", String.class)
|
||||
.category(OptionCategory.STORAGE)
|
||||
.hidden()
|
||||
.buildTime(true)
|
||||
.build();
|
||||
|
||||
public static final Option<String> STORAGE_REALM_STORE = new OptionBuilder<>("storage-realm-store", String.class)
|
||||
public static final Option<StorageType> STORAGE_REALM_STORE = new OptionBuilder<>("storage-realm", StorageType.class)
|
||||
.category(OptionCategory.STORAGE)
|
||||
.description(descriptionForStorageAreas("realms"))
|
||||
.expectedValues(StorageType.values())
|
||||
.buildTime(true)
|
||||
.build();
|
||||
|
||||
public static final Option<String> STORAGE_CLIENT_PROVIDER = new OptionBuilder<>("storage-client-provider", String.class)
|
||||
.category(OptionCategory.STORAGE)
|
||||
.hidden()
|
||||
.buildTime(true)
|
||||
.build();
|
||||
|
||||
public static final Option<String> STORAGE_CLIENT = new OptionBuilder<>("storage-client", String.class)
|
||||
public static final Option<StorageType> STORAGE_CLIENT_STORE = new OptionBuilder<>("storage-client", StorageType.class)
|
||||
.category(OptionCategory.STORAGE)
|
||||
.description(descriptionForStorageAreas("clients"))
|
||||
.expectedValues(StorageType.values())
|
||||
.buildTime(true)
|
||||
.build();
|
||||
|
||||
public static final Option<String> STORAGE_CLIENT_SCOPE_PROVIDER = new OptionBuilder<>("storage-client-scope-provider", String.class)
|
||||
.category(OptionCategory.STORAGE)
|
||||
.hidden()
|
||||
.buildTime(true)
|
||||
.build();
|
||||
|
||||
public static final Option<String> STORAGE_CLIENT_STORE = new OptionBuilder<>("storage-client-store", String.class)
|
||||
public static final Option<StorageType> STORAGE_CLIENT_SCOPE_STORE = new OptionBuilder<>("storage-client-scope", StorageType.class)
|
||||
.category(OptionCategory.STORAGE)
|
||||
.description(descriptionForStorageAreas("client scopes"))
|
||||
.expectedValues(StorageType.values())
|
||||
.buildTime(true)
|
||||
.build();
|
||||
|
||||
public static final Option<String> STORAGE_GROUP_PROVIDER = new OptionBuilder<>("storage-group-provider", String.class)
|
||||
.category(OptionCategory.STORAGE)
|
||||
.hidden()
|
||||
.buildTime(true)
|
||||
.build();
|
||||
|
||||
public static final Option<String> STORAGE_CLIENT_SCOPE = new OptionBuilder<>("storage-client-scope", String.class)
|
||||
public static final Option<StorageType> STORAGE_GROUP_STORE = new OptionBuilder<>("storage-group", StorageType.class)
|
||||
.category(OptionCategory.STORAGE)
|
||||
.description(descriptionForStorageAreas("groups"))
|
||||
.expectedValues(StorageType.values())
|
||||
.buildTime(true)
|
||||
.build();
|
||||
|
||||
public static final Option<String> STORAGE_ROLE_PROVIDER = new OptionBuilder<>("storage-role-provider", String.class)
|
||||
.category(OptionCategory.STORAGE)
|
||||
.hidden()
|
||||
.buildTime(true)
|
||||
.build();
|
||||
|
||||
public static final Option<String> STORAGE_CLIENT_SCOPE_STORE = new OptionBuilder<>("storage-client-scope-store", String.class)
|
||||
public static final Option<StorageType> STORAGE_ROLE_STORE = new OptionBuilder<>("storage-role", StorageType.class)
|
||||
.category(OptionCategory.STORAGE)
|
||||
.description(descriptionForStorageAreas("roles"))
|
||||
.expectedValues(StorageType.values())
|
||||
.buildTime(true)
|
||||
.build();
|
||||
|
||||
public static final Option<String> STORAGE_USER_PROVIDER = new OptionBuilder<>("storage-user-provider", String.class)
|
||||
.category(OptionCategory.STORAGE)
|
||||
.hidden()
|
||||
.buildTime(true)
|
||||
.build();
|
||||
|
||||
public static final Option<String> STORAGE_GROUP = new OptionBuilder<>("storage-group", String.class)
|
||||
public static final Option<StorageType> STORAGE_USER_STORE = new OptionBuilder<>("storage-user", StorageType.class)
|
||||
.category(OptionCategory.STORAGE)
|
||||
.description(descriptionForStorageAreas("users"))
|
||||
.expectedValues(StorageType.values())
|
||||
.buildTime(true)
|
||||
.build();
|
||||
|
||||
public static final Option<String> STORAGE_DEPLOYMENT_STATE_PROVIDER = new OptionBuilder<>("storage-deployment-state-provider", String.class)
|
||||
.category(OptionCategory.STORAGE)
|
||||
.hidden()
|
||||
.buildTime(true)
|
||||
.build();
|
||||
|
||||
public static final Option<String> STORAGE_GROUP_STORE = new OptionBuilder<>("storage-group-store", String.class)
|
||||
public static final Option<String> STORAGE_AUTH_SESSION_PROVIDER = new OptionBuilder<>("storage-auth-session-provider", String.class)
|
||||
.category(OptionCategory.STORAGE)
|
||||
.hidden()
|
||||
.buildTime(true)
|
||||
.build();
|
||||
|
||||
public static final Option<String> STORAGE_ROLE = new OptionBuilder<>("storage-role", String.class)
|
||||
public static final Option<StorageType> STORAGE_AUTH_SESSION_STORE = new OptionBuilder<>("storage-auth-session", StorageType.class)
|
||||
.category(OptionCategory.STORAGE)
|
||||
.description(descriptionForStorageAreas("authentication sessions"))
|
||||
.expectedValues(StorageType.values())
|
||||
.buildTime(true)
|
||||
.build();
|
||||
|
||||
public static final Option<String> STORAGE_USER_SESSION_PROVIDER = new OptionBuilder<>("storage-user-session-provider", String.class)
|
||||
.category(OptionCategory.STORAGE)
|
||||
.hidden()
|
||||
.buildTime(true)
|
||||
.build();
|
||||
|
||||
public static final Option<String> STORAGE_ROLE_STORE = new OptionBuilder<>("storage-role-store", String.class)
|
||||
public static final Option<StorageType> STORAGE_USER_SESSION_STORE = new OptionBuilder<>("storage-user-session", StorageType.class)
|
||||
.category(OptionCategory.STORAGE)
|
||||
.description(descriptionForStorageAreas("user and client sessions"))
|
||||
.expectedValues(StorageType.values())
|
||||
.buildTime(true)
|
||||
.build();
|
||||
|
||||
public static final Option<String> STORAGE_LOGIN_FAILURE_PROVIDER = new OptionBuilder<>("storage-login-failure-provider", String.class)
|
||||
.category(OptionCategory.STORAGE)
|
||||
.hidden()
|
||||
.buildTime(true)
|
||||
.build();
|
||||
|
||||
public static final Option<String> STORAGE_USER = new OptionBuilder<>("storage-user", String.class)
|
||||
public static final Option<StorageType> STORAGE_LOGIN_FAILURE_STORE = new OptionBuilder<>("storage-login-failure", StorageType.class)
|
||||
.category(OptionCategory.STORAGE)
|
||||
.description(descriptionForStorageAreas("login failures"))
|
||||
.expectedValues(StorageType.values())
|
||||
.buildTime(true)
|
||||
.build();
|
||||
|
||||
public static final Option<String> STORAGE_AUTHORIZATION_PROVIDER = new OptionBuilder<>("storage-authorization-provider", String.class)
|
||||
.category(OptionCategory.STORAGE)
|
||||
.hidden()
|
||||
.buildTime(true)
|
||||
.build();
|
||||
|
||||
public static final Option<String> STORAGE_USER_STORE = new OptionBuilder<>("storage-user-store", String.class)
|
||||
public static final Option<StorageType> STORAGE_AUTHORIZATION_STORE = new OptionBuilder<>("storage-authorization", StorageType.class)
|
||||
.category(OptionCategory.STORAGE)
|
||||
.hidden()
|
||||
.buildTime(true)
|
||||
.build();
|
||||
|
||||
public static final Option<String> STORAGE_DEPLOYMENT_STATE = new OptionBuilder<>("storage-deployment-state", String.class)
|
||||
.category(OptionCategory.STORAGE)
|
||||
.hidden()
|
||||
.buildTime(true)
|
||||
.build();
|
||||
|
||||
public static final Option<String> STORAGE_AUTH_SESSION = new OptionBuilder<>("storage-auth-session", String.class)
|
||||
.category(OptionCategory.STORAGE)
|
||||
.hidden()
|
||||
.buildTime(true)
|
||||
.build();
|
||||
|
||||
public static final Option<String> STORAGE_AUTH_SESSION_STORE = new OptionBuilder<>("storage-auth-session-store", String.class)
|
||||
.category(OptionCategory.STORAGE)
|
||||
.hidden()
|
||||
.buildTime(true)
|
||||
.build();
|
||||
|
||||
public static final Option<String> STORAGE_USER_SESSION = new OptionBuilder<>("storage-user-session", String.class)
|
||||
.category(OptionCategory.STORAGE)
|
||||
.hidden()
|
||||
.buildTime(true)
|
||||
.build();
|
||||
|
||||
public static final Option<String> STORAGE_USER_SESSION_STORE = new OptionBuilder<>("storage-user-session-store", String.class)
|
||||
.category(OptionCategory.STORAGE)
|
||||
.hidden()
|
||||
.buildTime(true)
|
||||
.build();
|
||||
|
||||
public static final Option<String> STORAGE_LOGIN_FAILURE = new OptionBuilder<>("storage-login-failure", String.class)
|
||||
.category(OptionCategory.STORAGE)
|
||||
.hidden()
|
||||
.buildTime(true)
|
||||
.build();
|
||||
|
||||
public static final Option<String> STORAGE_LOGIN_FAILURE_STORE = new OptionBuilder<>("storage-login-failure-store", String.class)
|
||||
.category(OptionCategory.STORAGE)
|
||||
.hidden()
|
||||
.buildTime(true)
|
||||
.build();
|
||||
|
||||
public static final Option<String> STORAGE_AUTHORIZATION_PERSISTER = new OptionBuilder<>("storage-authorization-persister", String.class)
|
||||
.category(OptionCategory.STORAGE)
|
||||
.hidden()
|
||||
.description(descriptionForStorageAreas("authorizations"))
|
||||
.expectedValues(StorageType.values())
|
||||
.buildTime(true)
|
||||
.build();
|
||||
|
||||
|
@ -206,15 +225,16 @@ public class StorageOptions {
|
|||
.buildTime(true)
|
||||
.build();
|
||||
|
||||
public static final Option<String> STORAGE_ACTION_TOKEN = new OptionBuilder<>("storage-action-token", String.class)
|
||||
public static final Option<String> STORAGE_ACTION_TOKEN_PROVIDER = new OptionBuilder<>("storage-action-token-provider", String.class)
|
||||
.category(OptionCategory.STORAGE)
|
||||
.hidden()
|
||||
.buildTime(true)
|
||||
.build();
|
||||
|
||||
public static final Option<String> STORAGE_ACTION_TOKEN_STORE = new OptionBuilder<>("storage-action-token-store", String.class)
|
||||
public static final Option<StorageType> STORAGE_ACTION_TOKEN_STORE = new OptionBuilder<>("storage-action-token", StorageType.class)
|
||||
.category(OptionCategory.STORAGE)
|
||||
.hidden()
|
||||
.description(descriptionForStorageAreas("action tokens"))
|
||||
.expectedValues(StorageType.values())
|
||||
.buildTime(true)
|
||||
.build();
|
||||
|
||||
|
@ -236,37 +256,38 @@ public class StorageOptions {
|
|||
.buildTime(true)
|
||||
.build();
|
||||
|
||||
public static final Option<String> STORAGE_CACHE_CLEAR_USER = new OptionBuilder<>("cache-clear-user", String.class)
|
||||
public static final Option<String> STORAGE_ADMIN_CACHE_CLEAR_USER = new OptionBuilder<>("cache-clear-user", String.class)
|
||||
.category(OptionCategory.STORAGE)
|
||||
.hidden()
|
||||
.buildTime(true)
|
||||
.build();
|
||||
|
||||
public static final Option<String> STORAGE_CACHE_CLEAR_REALM = new OptionBuilder<>("cache-clear-realm", String.class)
|
||||
public static final Option<String> STORAGE_ADMIN_CACHE_CLEAR_REALM = new OptionBuilder<>("cache-clear-realm", String.class)
|
||||
.category(OptionCategory.STORAGE)
|
||||
.hidden()
|
||||
.buildTime(true)
|
||||
.build();
|
||||
|
||||
public static final Option<String> STORAGE_CACHE_CLEAR_KEYS = new OptionBuilder<>("cache-clear-keys", String.class)
|
||||
public static final Option<String> STORAGE_ADMIN_CACHE_CLEAR_KEYS = new OptionBuilder<>("cache-clear-keys", String.class)
|
||||
.category(OptionCategory.STORAGE)
|
||||
.hidden()
|
||||
.buildTime(true)
|
||||
.build();
|
||||
|
||||
public static final Option<String> STORAGE_SINGLE_USE_OBJECT = new OptionBuilder<>("storage-single-use-object", String.class)
|
||||
public static final Option<String> STORAGE_SINGLE_USE_OBJECT_PROVIDER = new OptionBuilder<>("storage-single-use-object-provider", String.class)
|
||||
.category(OptionCategory.STORAGE)
|
||||
.hidden()
|
||||
.buildTime(true)
|
||||
.build();
|
||||
|
||||
public static final Option<String> STORAGE_SINGLE_USE_OBJECT_STORE = new OptionBuilder<>("storage-single-use-object-store", String.class)
|
||||
public static final Option<StorageType> STORAGE_SINGLE_USE_OBJECT_STORE = new OptionBuilder<>("storage-single-use-object", StorageType.class)
|
||||
.category(OptionCategory.STORAGE)
|
||||
.hidden()
|
||||
.description(descriptionForStorageAreas("single use objects"))
|
||||
.expectedValues(StorageType.values())
|
||||
.buildTime(true)
|
||||
.build();
|
||||
|
||||
public static final Option<String> STORAGE_PUBLIC_KEY_STORE = new OptionBuilder<>("storage-public-key-store", String.class)
|
||||
public static final Option<String> STORAGE_PUBLIC_KEY_STORAGE_STORE = new OptionBuilder<>("storage-public-key-storage", String.class)
|
||||
.category(OptionCategory.STORAGE)
|
||||
.hidden()
|
||||
.buildTime(true)
|
||||
|
@ -284,7 +305,7 @@ public class StorageOptions {
|
|||
.buildTime(true)
|
||||
.build();
|
||||
|
||||
public static final Option<String> STORAGE_USER_STORAGE = new OptionBuilder<>("storage-user-storage", String.class)
|
||||
public static final Option<String> STORAGE_ADMIN_USER_STORAGE = new OptionBuilder<>("storage-admin-user-storage", String.class)
|
||||
.category(OptionCategory.STORAGE)
|
||||
.hidden()
|
||||
.buildTime(true)
|
||||
|
@ -332,6 +353,20 @@ public class StorageOptions {
|
|||
|
||||
public static final List<Option<?>> ALL_OPTIONS = List.of(
|
||||
STORAGE,
|
||||
STORAGE_EVENT_ADMIN_STORE,
|
||||
STORAGE_EVENT_AUTH_STORE,
|
||||
STORAGE_REALM_STORE,
|
||||
STORAGE_CLIENT_STORE,
|
||||
STORAGE_CLIENT_SCOPE_STORE,
|
||||
STORAGE_GROUP_STORE,
|
||||
STORAGE_ROLE_STORE,
|
||||
STORAGE_USER_STORE,
|
||||
STORAGE_AUTH_SESSION_STORE,
|
||||
STORAGE_USER_SESSION_STORE,
|
||||
STORAGE_LOGIN_FAILURE_STORE,
|
||||
STORAGE_AUTHORIZATION_STORE,
|
||||
STORAGE_ACTION_TOKEN_STORE,
|
||||
STORAGE_SINGLE_USE_OBJECT_STORE,
|
||||
STORAGE_HOTROD_HOST,
|
||||
STORAGE_HOTROD_PORT,
|
||||
STORAGE_HOTROD_USERNAME,
|
||||
|
@ -339,4 +374,12 @@ public class StorageOptions {
|
|||
STORAGE_HOTROD_CACHE_CONFIGURE,
|
||||
STORAGE_HOTROD_CACHE_REINDEX
|
||||
);
|
||||
|
||||
private static String descriptionForStorageAreas(String areaAsText) {
|
||||
return String.format("Sets a storage mechanism for %s. Possible values are: %s.", areaAsText, storageAreas());
|
||||
}
|
||||
|
||||
private static String storageAreas() {
|
||||
return String.join(",", Arrays.stream(StorageType.values()).map(StorageType::name).collect(Collectors.joining(", ")));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,11 +33,14 @@ final class StoragePropertyMappers {
|
|||
public static PropertyMapper[] getMappers() {
|
||||
return new PropertyMapper[] {
|
||||
fromOption(StorageOptions.STORAGE)
|
||||
.paramLabel("type")
|
||||
.build(),
|
||||
fromOption(StorageOptions.STORAGE_PROVIDER)
|
||||
.to("kc.spi-map-storage-provider")
|
||||
.transformer(StoragePropertyMappers::resolveMapStorageProvider)
|
||||
.paramLabel("type")
|
||||
.build(),
|
||||
fromOption(StorageOptions.STORAGE_EVENT_STORE)
|
||||
fromOption(StorageOptions.STORAGE_EVENT_STORE_PROVIDER)
|
||||
.mapFrom("storage")
|
||||
.to("kc.spi-events-store-provider")
|
||||
.transformer(StoragePropertyMappers::getAreaStorage)
|
||||
|
@ -55,7 +58,7 @@ final class StoragePropertyMappers {
|
|||
.transformer(StoragePropertyMappers::resolveMapStorageProvider)
|
||||
.paramLabel("type")
|
||||
.build(),
|
||||
fromOption(StorageOptions.STORAGE_REALM)
|
||||
fromOption(StorageOptions.STORAGE_REALM_PROVIDER)
|
||||
.to("kc.spi-realm-provider")
|
||||
.mapFrom("storage")
|
||||
.transformer(StoragePropertyMappers::getAreaStorage)
|
||||
|
@ -67,7 +70,7 @@ final class StoragePropertyMappers {
|
|||
.transformer(StoragePropertyMappers::resolveMapStorageProvider)
|
||||
.paramLabel("type")
|
||||
.build(),
|
||||
fromOption(StorageOptions.STORAGE_CLIENT)
|
||||
fromOption(StorageOptions.STORAGE_CLIENT_PROVIDER)
|
||||
.to("kc.spi-client-provider")
|
||||
.mapFrom("storage")
|
||||
.transformer(StoragePropertyMappers::getAreaStorage)
|
||||
|
@ -79,7 +82,7 @@ final class StoragePropertyMappers {
|
|||
.transformer(StoragePropertyMappers::resolveMapStorageProvider)
|
||||
.paramLabel("type")
|
||||
.build(),
|
||||
fromOption(StorageOptions.STORAGE_CLIENT_SCOPE)
|
||||
fromOption(StorageOptions.STORAGE_CLIENT_SCOPE_PROVIDER)
|
||||
.to("kc.spi-client-scope-provider")
|
||||
.mapFrom("storage")
|
||||
.transformer(StoragePropertyMappers::getAreaStorage)
|
||||
|
@ -91,7 +94,7 @@ final class StoragePropertyMappers {
|
|||
.transformer(StoragePropertyMappers::resolveMapStorageProvider)
|
||||
.paramLabel("type")
|
||||
.build(),
|
||||
fromOption(StorageOptions.STORAGE_GROUP)
|
||||
fromOption(StorageOptions.STORAGE_GROUP_PROVIDER)
|
||||
.to("kc.spi-group-provider")
|
||||
.mapFrom("storage")
|
||||
.transformer(StoragePropertyMappers::getAreaStorage)
|
||||
|
@ -103,7 +106,7 @@ final class StoragePropertyMappers {
|
|||
.transformer(StoragePropertyMappers::resolveMapStorageProvider)
|
||||
.paramLabel("type")
|
||||
.build(),
|
||||
fromOption(StorageOptions.STORAGE_ROLE)
|
||||
fromOption(StorageOptions.STORAGE_ROLE_PROVIDER)
|
||||
.to("kc.spi-role-provider")
|
||||
.mapFrom("storage")
|
||||
.transformer(StoragePropertyMappers::getAreaStorage)
|
||||
|
@ -115,7 +118,7 @@ final class StoragePropertyMappers {
|
|||
.transformer(StoragePropertyMappers::resolveMapStorageProvider)
|
||||
.paramLabel("type")
|
||||
.build(),
|
||||
fromOption(StorageOptions.STORAGE_USER)
|
||||
fromOption(StorageOptions.STORAGE_USER_PROVIDER)
|
||||
.to("kc.spi-user-provider")
|
||||
.mapFrom("storage")
|
||||
.transformer(StoragePropertyMappers::getAreaStorage)
|
||||
|
@ -127,13 +130,13 @@ final class StoragePropertyMappers {
|
|||
.transformer(StoragePropertyMappers::resolveMapStorageProvider)
|
||||
.paramLabel("type")
|
||||
.build(),
|
||||
fromOption(StorageOptions.STORAGE_DEPLOYMENT_STATE)
|
||||
fromOption(StorageOptions.STORAGE_DEPLOYMENT_STATE_PROVIDER)
|
||||
.to("kc.spi-deployment-state-provider")
|
||||
.mapFrom("storage")
|
||||
.transformer(StoragePropertyMappers::getAreaStorage)
|
||||
.paramLabel("type")
|
||||
.build(),
|
||||
fromOption(StorageOptions.STORAGE_AUTH_SESSION)
|
||||
fromOption(StorageOptions.STORAGE_AUTH_SESSION_PROVIDER)
|
||||
.to("kc.spi-authentication-sessions-provider")
|
||||
.mapFrom("storage")
|
||||
.transformer(StoragePropertyMappers::getCacheStorage)
|
||||
|
@ -145,7 +148,7 @@ final class StoragePropertyMappers {
|
|||
.transformer(StoragePropertyMappers::resolveMapStorageProvider)
|
||||
.paramLabel("type")
|
||||
.build(),
|
||||
fromOption(StorageOptions.STORAGE_USER_SESSION)
|
||||
fromOption(StorageOptions.STORAGE_USER_SESSION_PROVIDER)
|
||||
.to("kc.spi-user-sessions-provider")
|
||||
.mapFrom("storage")
|
||||
.transformer(StoragePropertyMappers::getCacheStorage)
|
||||
|
@ -157,7 +160,7 @@ final class StoragePropertyMappers {
|
|||
.transformer(StoragePropertyMappers::resolveMapStorageProvider)
|
||||
.paramLabel("type")
|
||||
.build(),
|
||||
fromOption(StorageOptions.STORAGE_LOGIN_FAILURE)
|
||||
fromOption(StorageOptions.STORAGE_LOGIN_FAILURE_PROVIDER)
|
||||
.to("kc.spi-login-failure-provider")
|
||||
.mapFrom("storage")
|
||||
.transformer(StoragePropertyMappers::getCacheStorage)
|
||||
|
@ -175,13 +178,19 @@ final class StoragePropertyMappers {
|
|||
.transformer(StoragePropertyMappers::getUserSessionPersisterStorage)
|
||||
.paramLabel("type")
|
||||
.build(),
|
||||
fromOption(StorageOptions.STORAGE_AUTHORIZATION_PERSISTER)
|
||||
fromOption(StorageOptions.STORAGE_AUTHORIZATION_PROVIDER)
|
||||
.to("kc.spi-authorization-persister-provider")
|
||||
.mapFrom("storage")
|
||||
.transformer(StoragePropertyMappers::getAreaStorage)
|
||||
.paramLabel("type")
|
||||
.build(),
|
||||
fromOption(StorageOptions.STORAGE_ACTION_TOKEN)
|
||||
fromOption(StorageOptions.STORAGE_AUTHORIZATION_STORE)
|
||||
.to("kc.spi-authorization-persister-map-storage-provider")
|
||||
.mapFrom("storage")
|
||||
.transformer(StoragePropertyMappers::resolveMapStorageProvider)
|
||||
.paramLabel("type")
|
||||
.build(),
|
||||
fromOption(StorageOptions.STORAGE_ACTION_TOKEN_PROVIDER)
|
||||
.to("kc.spi-action-token-provider")
|
||||
.mapFrom("storage")
|
||||
.transformer(StoragePropertyMappers::getCacheStorage)
|
||||
|
@ -217,7 +226,7 @@ final class StoragePropertyMappers {
|
|||
.transformer(StoragePropertyMappers::isCacheAreaEnabledForStorage)
|
||||
.paramLabel(Boolean.TRUE + "|" + Boolean.FALSE)
|
||||
.build(),
|
||||
fromOption(StorageOptions.STORAGE_SINGLE_USE_OBJECT)
|
||||
fromOption(StorageOptions.STORAGE_SINGLE_USE_OBJECT_PROVIDER)
|
||||
.to("kc.spi-single-use-object-provider")
|
||||
.mapFrom("storage")
|
||||
.transformer(StoragePropertyMappers::getCacheStorage)
|
||||
|
@ -229,10 +238,10 @@ final class StoragePropertyMappers {
|
|||
.transformer(StoragePropertyMappers::resolveMapStorageProvider)
|
||||
.paramLabel("type")
|
||||
.build(),
|
||||
fromOption(StorageOptions.STORAGE_PUBLIC_KEY_STORE)
|
||||
fromOption(StorageOptions.STORAGE_PUBLIC_KEY_STORAGE_STORE)
|
||||
.to("kc.spi-public-key-storage-map-storage-provider")
|
||||
.mapFrom("storage")
|
||||
.transformer(StoragePropertyMappers::resolveMapStorageProvider)
|
||||
.transformer(StoragePropertyMappers::resolveMapStorageProviderPublicKeyStorage)
|
||||
.paramLabel("type")
|
||||
.build(),
|
||||
fromOption(StorageOptions.STORAGE_EXCEPTION_CONVERTER)
|
||||
|
@ -241,19 +250,19 @@ final class StoragePropertyMappers {
|
|||
.transformer(StoragePropertyMappers::isLegacyStoreEnabled)
|
||||
.paramLabel(Boolean.TRUE + "|" + Boolean.FALSE)
|
||||
.build(),
|
||||
fromOption(StorageOptions.STORAGE_CACHE_CLEAR_REALM)
|
||||
fromOption(StorageOptions.STORAGE_ADMIN_CACHE_CLEAR_REALM)
|
||||
.to("kc.spi-admin-realm-restapi-extension-clear-realm-cache-enabled")
|
||||
.mapFrom("storage")
|
||||
.transformer(StoragePropertyMappers::isLegacyStoreEnabled)
|
||||
.paramLabel(Boolean.TRUE + "|" + Boolean.FALSE)
|
||||
.build(),
|
||||
fromOption(StorageOptions.STORAGE_CACHE_CLEAR_USER)
|
||||
fromOption(StorageOptions.STORAGE_ADMIN_CACHE_CLEAR_USER)
|
||||
.to("kc.spi-admin-realm-restapi-extension-clear-user-cache-enabled")
|
||||
.mapFrom("storage")
|
||||
.transformer(StoragePropertyMappers::isLegacyStoreEnabled)
|
||||
.paramLabel(Boolean.TRUE + "|" + Boolean.FALSE)
|
||||
.build(),
|
||||
fromOption(StorageOptions.STORAGE_CACHE_CLEAR_KEYS)
|
||||
fromOption(StorageOptions.STORAGE_ADMIN_CACHE_CLEAR_KEYS)
|
||||
.to("kc.spi-admin-realm-restapi-extension-clear-keys-cache-enabled")
|
||||
.mapFrom("storage")
|
||||
.transformer(StoragePropertyMappers::isLegacyStoreEnabled)
|
||||
|
@ -265,7 +274,7 @@ final class StoragePropertyMappers {
|
|||
.transformer(StoragePropertyMappers::isLegacyStoreEnabled)
|
||||
.paramLabel("type")
|
||||
.build(),
|
||||
fromOption(StorageOptions.STORAGE_USER_STORAGE)
|
||||
fromOption(StorageOptions.STORAGE_ADMIN_USER_STORAGE)
|
||||
.to("kc.spi-admin-realm-restapi-extension-user-storage-enabled")
|
||||
.mapFrom("storage")
|
||||
.transformer(StoragePropertyMappers::isLegacyStoreEnabled)
|
||||
|
@ -343,6 +352,20 @@ final class StoragePropertyMappers {
|
|||
return value;
|
||||
}
|
||||
|
||||
private static Optional<String> resolveMapStorageProviderPublicKeyStorage(Optional<String> value, ConfigSourceInterceptorContext context) {
|
||||
try {
|
||||
if (value.isPresent()) {
|
||||
// there is only one public key storage provider available
|
||||
return of(StorageType.chm.getProvider());
|
||||
}
|
||||
} catch (IllegalArgumentException iae) {
|
||||
throw new IllegalArgumentException("Invalid storage provider: " + value.orElse(null), iae);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
private static Optional<String> isCacheAreaEnabledForStorage(Optional<String> storage, ConfigSourceInterceptorContext context) {
|
||||
return of(storage.isEmpty() ? Boolean.TRUE.toString() : Boolean.FALSE.toString());
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
package org.keycloak.quarkus.runtime.configuration.test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.keycloak.quarkus.runtime.configuration.ConfigArgsConfigSource.CLI_ARGS;
|
||||
|
||||
|
@ -485,6 +486,30 @@ public class ConfigurationTest {
|
|||
assertEquals("true", config4.getConfigValue("quarkus.log.handler.gelf.enabled").getValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStorageMixedStorageOptions() {
|
||||
System.setProperty(CLI_ARGS, "--storage=jpa" + ARG_SEPARATOR + "--storage-realm=chm");
|
||||
SmallRyeConfig config = createConfig();
|
||||
assertEquals("jpa", config.getConfigValue("kc.storage").getValue());
|
||||
assertNull(config.getConfigValue("kc.spi-map-storage-provider").getValue());
|
||||
assertEquals("map", config.getConfigValue("kc.spi-realm-provider").getValue());
|
||||
assertEquals("concurrenthashmap", config.getConfigValue("kc.spi-realm-map-storage-provider").getValue());
|
||||
assertEquals("map", config.getConfigValue("kc.spi-user-provider").getValue());
|
||||
assertEquals("jpa", config.getConfigValue("kc.spi-user-map-storage-provider").getValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStoragePureJpa() {
|
||||
System.setProperty(CLI_ARGS, "--storage=jpa");
|
||||
SmallRyeConfig config = createConfig();
|
||||
assertEquals("jpa", config.getConfigValue("kc.storage").getValue());
|
||||
assertNull(config.getConfigValue("kc.spi-map-storage-provider").getValue());
|
||||
assertEquals("map", config.getConfigValue("kc.spi-realm-provider").getValue());
|
||||
assertEquals("jpa", config.getConfigValue("kc.spi-realm-map-storage-provider").getValue());
|
||||
assertEquals("map", config.getConfigValue("kc.spi-user-provider").getValue());
|
||||
assertEquals("jpa", config.getConfigValue("kc.spi-user-map-storage-provider").getValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOptionValueWithEqualSign() {
|
||||
System.setProperty(CLI_ARGS, "--db=postgres" + ARG_SEPARATOR + "--db-password=my_secret=");
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
package org.keycloak.it.storage.map;
|
||||
|
||||
import io.quarkus.test.junit.main.Launch;
|
||||
import io.quarkus.test.junit.main.LaunchResult;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.keycloak.it.junit5.extension.CLIResult;
|
||||
import org.keycloak.it.junit5.extension.DistributionTest;
|
||||
import org.keycloak.it.junit5.extension.RawDistOnly;
|
||||
import org.keycloak.it.junit5.extension.WithDatabase;
|
||||
import org.keycloak.it.utils.RawDistRootPath;
|
||||
|
||||
import java.io.File;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
@DistributionTest
|
||||
@RawDistOnly(reason = "Containers are immutable")
|
||||
@WithDatabase(alias = "postgres", buildOptions = {"storage=jpa", "storage-realm=chm"})
|
||||
public class MixedStoreDistTest {
|
||||
|
||||
@Test
|
||||
@Launch({ "start", "--http-enabled=true", "--hostname-strict=false" })
|
||||
void testStartUsingMixedStorage(LaunchResult result, RawDistRootPath distRoot) {
|
||||
CLIResult cliResult = (CLIResult) result;
|
||||
cliResult.assertStarted();
|
||||
File chmRealmsFile = Paths.get(distRoot.getDistRootPath().toString(), "data","chm", "map-realms.json").toFile();
|
||||
assertTrue(chmRealmsFile.isFile(), "File for realms does not exist!");
|
||||
}
|
||||
}
|
|
@ -29,7 +29,32 @@ Cache:
|
|||
|
||||
Storage (Experimental):
|
||||
|
||||
--storage <type> Experimental: Sets a storage mechanism. Possible values are: jpa, chm, hotrod.
|
||||
--storage <type> Experimental: Sets the default storage mechanism for all areas. Possible
|
||||
values are: jpa, chm, hotrod.
|
||||
--storage-action-token <type>
|
||||
Experimental: Sets a storage mechanism for action tokens. Possible values are:
|
||||
jpa, chm, hotrod.
|
||||
--storage-auth-session <type>
|
||||
Experimental: Sets a storage mechanism for authentication sessions. Possible
|
||||
values are: jpa, chm, hotrod.
|
||||
--storage-authorization <type>
|
||||
Experimental: Sets a storage mechanism for authorizations. Possible values
|
||||
are: jpa, chm, hotrod.
|
||||
--storage-client <type>
|
||||
Experimental: Sets a storage mechanism for clients. Possible values are: jpa,
|
||||
chm, hotrod.
|
||||
--storage-client-scope <type>
|
||||
Experimental: Sets a storage mechanism for client scopes. Possible values are:
|
||||
jpa, chm, hotrod.
|
||||
--storage-event-admin <type>
|
||||
Experimental: Sets a storage mechanism for admin events. Possible values are:
|
||||
jpa, chm, hotrod.
|
||||
--storage-event-auth <type>
|
||||
Experimental: Sets a storage mechanism for authentication and authorization
|
||||
events. Possible values are: jpa, chm, hotrod.
|
||||
--storage-group <type>
|
||||
Experimental: Sets a storage mechanism for groups. Possible values are: jpa,
|
||||
chm, hotrod.
|
||||
--storage-hotrod-cache-configure <true|false>
|
||||
Experimental: When set to true, Keycloak will create and configure Infinispan
|
||||
caches on startup. Default: true.
|
||||
|
@ -44,6 +69,24 @@ Storage (Experimental):
|
|||
Experimental: Sets the port of the Infinispan server.
|
||||
--storage-hotrod-username <username>
|
||||
Experimental: Sets the username of the Infinispan user.
|
||||
--storage-login-failure <type>
|
||||
Experimental: Sets a storage mechanism for login failures. Possible values
|
||||
are: jpa, chm, hotrod.
|
||||
--storage-realm <type>
|
||||
Experimental: Sets a storage mechanism for realms. Possible values are: jpa,
|
||||
chm, hotrod.
|
||||
--storage-role <type>
|
||||
Experimental: Sets a storage mechanism for roles. Possible values are: jpa,
|
||||
chm, hotrod.
|
||||
--storage-single-use-object <type>
|
||||
Experimental: Sets a storage mechanism for single use objects. Possible values
|
||||
are: jpa, chm, hotrod.
|
||||
--storage-user <type>
|
||||
Experimental: Sets a storage mechanism for users. Possible values are: jpa,
|
||||
chm, hotrod.
|
||||
--storage-user-session <type>
|
||||
Experimental: Sets a storage mechanism for user and client sessions. Possible
|
||||
values are: jpa, chm, hotrod.
|
||||
|
||||
Database:
|
||||
|
||||
|
|
|
@ -29,7 +29,32 @@ Cache:
|
|||
|
||||
Storage (Experimental):
|
||||
|
||||
--storage <type> Experimental: Sets a storage mechanism. Possible values are: jpa, chm, hotrod.
|
||||
--storage <type> Experimental: Sets the default storage mechanism for all areas. Possible
|
||||
values are: jpa, chm, hotrod.
|
||||
--storage-action-token <type>
|
||||
Experimental: Sets a storage mechanism for action tokens. Possible values are:
|
||||
jpa, chm, hotrod.
|
||||
--storage-auth-session <type>
|
||||
Experimental: Sets a storage mechanism for authentication sessions. Possible
|
||||
values are: jpa, chm, hotrod.
|
||||
--storage-authorization <type>
|
||||
Experimental: Sets a storage mechanism for authorizations. Possible values
|
||||
are: jpa, chm, hotrod.
|
||||
--storage-client <type>
|
||||
Experimental: Sets a storage mechanism for clients. Possible values are: jpa,
|
||||
chm, hotrod.
|
||||
--storage-client-scope <type>
|
||||
Experimental: Sets a storage mechanism for client scopes. Possible values are:
|
||||
jpa, chm, hotrod.
|
||||
--storage-event-admin <type>
|
||||
Experimental: Sets a storage mechanism for admin events. Possible values are:
|
||||
jpa, chm, hotrod.
|
||||
--storage-event-auth <type>
|
||||
Experimental: Sets a storage mechanism for authentication and authorization
|
||||
events. Possible values are: jpa, chm, hotrod.
|
||||
--storage-group <type>
|
||||
Experimental: Sets a storage mechanism for groups. Possible values are: jpa,
|
||||
chm, hotrod.
|
||||
--storage-hotrod-cache-configure <true|false>
|
||||
Experimental: When set to true, Keycloak will create and configure Infinispan
|
||||
caches on startup. Default: true.
|
||||
|
@ -44,6 +69,24 @@ Storage (Experimental):
|
|||
Experimental: Sets the port of the Infinispan server.
|
||||
--storage-hotrod-username <username>
|
||||
Experimental: Sets the username of the Infinispan user.
|
||||
--storage-login-failure <type>
|
||||
Experimental: Sets a storage mechanism for login failures. Possible values
|
||||
are: jpa, chm, hotrod.
|
||||
--storage-realm <type>
|
||||
Experimental: Sets a storage mechanism for realms. Possible values are: jpa,
|
||||
chm, hotrod.
|
||||
--storage-role <type>
|
||||
Experimental: Sets a storage mechanism for roles. Possible values are: jpa,
|
||||
chm, hotrod.
|
||||
--storage-single-use-object <type>
|
||||
Experimental: Sets a storage mechanism for single use objects. Possible values
|
||||
are: jpa, chm, hotrod.
|
||||
--storage-user <type>
|
||||
Experimental: Sets a storage mechanism for users. Possible values are: jpa,
|
||||
chm, hotrod.
|
||||
--storage-user-session <type>
|
||||
Experimental: Sets a storage mechanism for user and client sessions. Possible
|
||||
values are: jpa, chm, hotrod.
|
||||
|
||||
Database:
|
||||
|
||||
|
|
|
@ -35,7 +35,32 @@ Cache:
|
|||
|
||||
Storage (Experimental):
|
||||
|
||||
--storage <type> Experimental: Sets a storage mechanism. Possible values are: jpa, chm, hotrod.
|
||||
--storage <type> Experimental: Sets the default storage mechanism for all areas. Possible
|
||||
values are: jpa, chm, hotrod.
|
||||
--storage-action-token <type>
|
||||
Experimental: Sets a storage mechanism for action tokens. Possible values are:
|
||||
jpa, chm, hotrod.
|
||||
--storage-auth-session <type>
|
||||
Experimental: Sets a storage mechanism for authentication sessions. Possible
|
||||
values are: jpa, chm, hotrod.
|
||||
--storage-authorization <type>
|
||||
Experimental: Sets a storage mechanism for authorizations. Possible values
|
||||
are: jpa, chm, hotrod.
|
||||
--storage-client <type>
|
||||
Experimental: Sets a storage mechanism for clients. Possible values are: jpa,
|
||||
chm, hotrod.
|
||||
--storage-client-scope <type>
|
||||
Experimental: Sets a storage mechanism for client scopes. Possible values are:
|
||||
jpa, chm, hotrod.
|
||||
--storage-event-admin <type>
|
||||
Experimental: Sets a storage mechanism for admin events. Possible values are:
|
||||
jpa, chm, hotrod.
|
||||
--storage-event-auth <type>
|
||||
Experimental: Sets a storage mechanism for authentication and authorization
|
||||
events. Possible values are: jpa, chm, hotrod.
|
||||
--storage-group <type>
|
||||
Experimental: Sets a storage mechanism for groups. Possible values are: jpa,
|
||||
chm, hotrod.
|
||||
--storage-hotrod-cache-configure <true|false>
|
||||
Experimental: When set to true, Keycloak will create and configure Infinispan
|
||||
caches on startup. Default: true.
|
||||
|
@ -50,6 +75,24 @@ Storage (Experimental):
|
|||
Experimental: Sets the port of the Infinispan server.
|
||||
--storage-hotrod-username <username>
|
||||
Experimental: Sets the username of the Infinispan user.
|
||||
--storage-login-failure <type>
|
||||
Experimental: Sets a storage mechanism for login failures. Possible values
|
||||
are: jpa, chm, hotrod.
|
||||
--storage-realm <type>
|
||||
Experimental: Sets a storage mechanism for realms. Possible values are: jpa,
|
||||
chm, hotrod.
|
||||
--storage-role <type>
|
||||
Experimental: Sets a storage mechanism for roles. Possible values are: jpa,
|
||||
chm, hotrod.
|
||||
--storage-single-use-object <type>
|
||||
Experimental: Sets a storage mechanism for single use objects. Possible values
|
||||
are: jpa, chm, hotrod.
|
||||
--storage-user <type>
|
||||
Experimental: Sets a storage mechanism for users. Possible values are: jpa,
|
||||
chm, hotrod.
|
||||
--storage-user-session <type>
|
||||
Experimental: Sets a storage mechanism for user and client sessions. Possible
|
||||
values are: jpa, chm, hotrod.
|
||||
|
||||
Database:
|
||||
|
||||
|
|
|
@ -35,7 +35,32 @@ Cache:
|
|||
|
||||
Storage (Experimental):
|
||||
|
||||
--storage <type> Experimental: Sets a storage mechanism. Possible values are: jpa, chm, hotrod.
|
||||
--storage <type> Experimental: Sets the default storage mechanism for all areas. Possible
|
||||
values are: jpa, chm, hotrod.
|
||||
--storage-action-token <type>
|
||||
Experimental: Sets a storage mechanism for action tokens. Possible values are:
|
||||
jpa, chm, hotrod.
|
||||
--storage-auth-session <type>
|
||||
Experimental: Sets a storage mechanism for authentication sessions. Possible
|
||||
values are: jpa, chm, hotrod.
|
||||
--storage-authorization <type>
|
||||
Experimental: Sets a storage mechanism for authorizations. Possible values
|
||||
are: jpa, chm, hotrod.
|
||||
--storage-client <type>
|
||||
Experimental: Sets a storage mechanism for clients. Possible values are: jpa,
|
||||
chm, hotrod.
|
||||
--storage-client-scope <type>
|
||||
Experimental: Sets a storage mechanism for client scopes. Possible values are:
|
||||
jpa, chm, hotrod.
|
||||
--storage-event-admin <type>
|
||||
Experimental: Sets a storage mechanism for admin events. Possible values are:
|
||||
jpa, chm, hotrod.
|
||||
--storage-event-auth <type>
|
||||
Experimental: Sets a storage mechanism for authentication and authorization
|
||||
events. Possible values are: jpa, chm, hotrod.
|
||||
--storage-group <type>
|
||||
Experimental: Sets a storage mechanism for groups. Possible values are: jpa,
|
||||
chm, hotrod.
|
||||
--storage-hotrod-cache-configure <true|false>
|
||||
Experimental: When set to true, Keycloak will create and configure Infinispan
|
||||
caches on startup. Default: true.
|
||||
|
@ -50,6 +75,24 @@ Storage (Experimental):
|
|||
Experimental: Sets the port of the Infinispan server.
|
||||
--storage-hotrod-username <username>
|
||||
Experimental: Sets the username of the Infinispan user.
|
||||
--storage-login-failure <type>
|
||||
Experimental: Sets a storage mechanism for login failures. Possible values
|
||||
are: jpa, chm, hotrod.
|
||||
--storage-realm <type>
|
||||
Experimental: Sets a storage mechanism for realms. Possible values are: jpa,
|
||||
chm, hotrod.
|
||||
--storage-role <type>
|
||||
Experimental: Sets a storage mechanism for roles. Possible values are: jpa,
|
||||
chm, hotrod.
|
||||
--storage-single-use-object <type>
|
||||
Experimental: Sets a storage mechanism for single use objects. Possible values
|
||||
are: jpa, chm, hotrod.
|
||||
--storage-user <type>
|
||||
Experimental: Sets a storage mechanism for users. Possible values are: jpa,
|
||||
chm, hotrod.
|
||||
--storage-user-session <type>
|
||||
Experimental: Sets a storage mechanism for user and client sessions. Possible
|
||||
values are: jpa, chm, hotrod.
|
||||
|
||||
Database:
|
||||
|
||||
|
|
Loading…
Reference in a new issue