From c45524d8d49b6c7cd5690ee69ae96da8032cf453 Mon Sep 17 00:00:00 2001 From: Bill Burke Date: Fri, 19 Feb 2016 15:44:19 -0500 Subject: [PATCH 1/5] caching --- .../configuration/keycloak-server.json | 10 +- ...ltInfinispanConnectionProviderFactory.java | 10 + .../InfinispanConnectionProvider.java | 1 + .../cache/infinispan/ClientAdapter.java | 3 +- .../infinispan/DefaultCacheRealmProvider.java | 396 ------------------ .../InfinispanCacheRealmProviderFactory.java | 84 +--- .../InfinispanCacheUserProviderFactory.java | 2 +- .../infinispan/InfinispanRealmCache.java | 202 --------- .../cache/infinispan/InfinispanUserCache.java | 2 +- .../models/cache/infinispan/RealmAdapter.java | 25 +- .../models/cache/infinispan/RoleAdapter.java | 4 +- .../LockingCacheRealmProviderFactory.java | 159 ------- .../LockingConnectionProviderFactory.java | 54 --- .../infinispan/locking/LockingRealmCache.java | 300 ------------- .../infinispan/stream/ClientListQuery.java | 50 +++ .../cache/infinispan/stream/ClientQuery.java | 14 + .../stream/ClientQueryPredicate.java | 46 ++ .../stream/ClientTemplateQuery.java | 13 + .../stream/ClientTemplateQueryPredicate.java | 37 ++ .../cache/infinispan/stream/GroupQuery.java | 13 + .../stream/GroupQueryPredicate.java | 37 ++ .../infinispan/stream/HasRolePredicate.java | 40 ++ .../infinispan/stream/InClientPredicate.java | 34 ++ .../infinispan/stream/InRealmPredicate.java | 33 ++ .../infinispan/stream/RealmListQuery.java | 29 ++ .../cache/infinispan/stream/RealmQuery.java | 13 + .../stream/RealmQueryPredicate.java | 37 ++ .../cache/infinispan/stream/RoleQuery.java | 13 + .../infinispan/stream/RoleQueryPredicate.java | 37 ++ .../StreamCacheRealmProvider.java} | 326 +++++++------- .../infinispan/stream/StreamRealmCache.java | 314 ++++++++++++++ .../{locking => stream}/UpdateCounter.java | 2 +- .../stream/entities/AbstractRevisioned.java | 31 ++ .../infinispan/stream/entities/InClient.java | 9 + .../infinispan/stream/entities/InRealm.java | 9 + .../entities}/Revisioned.java | 3 +- .../entities/RevisionedCachedClient.java | 5 +- .../entities/RevisionedCachedClientRole.java | 5 +- .../RevisionedCachedClientTemplate.java | 5 +- .../entities/RevisionedCachedGroup.java | 5 +- .../entities/RevisionedCachedRealm.java | 3 +- .../entities/RevisionedCachedRealmRole.java | 5 +- .../entities/RevisionedCachedUser.java | 5 +- ...nispan.InfinispanConnectionProviderFactory | 1 - ...oak.models.cache.CacheRealmProviderFactory | 1 - .../ClusteredCacheBehaviorTest.java | 117 ++++++ .../keycloak/models/jpa/ClientAdapter.java | 28 +- .../keycloak/models/jpa/JpaRealmProvider.java | 92 ++-- .../org/keycloak/models/jpa/RealmAdapter.java | 70 ++-- .../org/keycloak/models/jpa/RoleAdapter.java | 10 +- .../models/jpa/entities/ClientEntity.java | 1 + .../models/jpa/entities/GroupEntity.java | 1 + .../models/jpa/entities/RealmEntity.java | 15 +- .../models/jpa/entities/RoleEntity.java | 5 +- .../keycloak/adapters/MongoRealmProvider.java | 54 ++- .../mongo/keycloak/adapters/RealmAdapter.java | 35 +- .../org/keycloak/models/RealmProvider.java | 6 + .../models/cache/CacheRealmProvider.java | 2 +- .../cache/entities/CachedClientRole.java | 10 +- .../resources/META-INF/keycloak-server.json | 12 +- .../testsuite/admin/ConcurrencyTest.java | 57 ++- .../resources/META-INF/keycloak-server.json | 8 +- .../src/test/resources/log4j.properties | 2 +- 63 files changed, 1403 insertions(+), 1549 deletions(-) mode change 100644 => 100755 model/infinispan/src/main/java/org/keycloak/connections/infinispan/InfinispanConnectionProvider.java delete mode 100755 model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/DefaultCacheRealmProvider.java delete mode 100755 model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/InfinispanRealmCache.java delete mode 100755 model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/locking/LockingCacheRealmProviderFactory.java delete mode 100755 model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/locking/LockingConnectionProviderFactory.java delete mode 100755 model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/locking/LockingRealmCache.java create mode 100755 model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/ClientListQuery.java create mode 100755 model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/ClientQuery.java create mode 100755 model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/ClientQueryPredicate.java create mode 100755 model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/ClientTemplateQuery.java create mode 100755 model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/ClientTemplateQueryPredicate.java create mode 100755 model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/GroupQuery.java create mode 100755 model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/GroupQueryPredicate.java create mode 100755 model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/HasRolePredicate.java create mode 100755 model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/InClientPredicate.java create mode 100755 model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/InRealmPredicate.java create mode 100755 model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/RealmListQuery.java create mode 100755 model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/RealmQuery.java create mode 100755 model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/RealmQueryPredicate.java create mode 100755 model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/RoleQuery.java create mode 100755 model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/RoleQueryPredicate.java rename model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/{locking/LockingCacheRealmProvider.java => stream/StreamCacheRealmProvider.java} (57%) create mode 100755 model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/StreamRealmCache.java rename model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/{locking => stream}/UpdateCounter.java (87%) create mode 100755 model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/entities/AbstractRevisioned.java create mode 100755 model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/entities/InClient.java create mode 100755 model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/entities/InRealm.java rename model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/{locking => stream/entities}/Revisioned.java (70%) rename model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/{locking => stream}/entities/RevisionedCachedClient.java (88%) rename model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/{locking => stream}/entities/RevisionedCachedClientRole.java (82%) rename model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/{locking => stream}/entities/RevisionedCachedClientTemplate.java (84%) rename model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/{locking => stream}/entities/RevisionedCachedGroup.java (82%) rename model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/{locking => stream}/entities/RevisionedCachedRealm.java (92%) rename model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/{locking => stream}/entities/RevisionedCachedRealmRole.java (81%) rename model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/{locking => stream}/entities/RevisionedCachedUser.java (82%) create mode 100755 model/infinispan/src/test/java/org/keycloak/models/sessions/infinispan/initializer/ClusteredCacheBehaviorTest.java diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/content/standalone/configuration/keycloak-server.json b/distribution/feature-packs/server-feature-pack/src/main/resources/content/standalone/configuration/keycloak-server.json index 407f0c003a..c4139a1ac7 100755 --- a/distribution/feature-packs/server-feature-pack/src/main/resources/content/standalone/configuration/keycloak-server.json +++ b/distribution/feature-packs/server-feature-pack/src/main/resources/content/standalone/configuration/keycloak-server.json @@ -23,7 +23,7 @@ }, "userCache": { - "infinispan" : { + "default" : { "enabled": true } }, @@ -61,15 +61,15 @@ }, "realmCache": { - "provider": "infinispan-locking", - "infinispan-locking" : { + "provider": "default", + "default" : { "enabled": true } }, "connectionsInfinispan": { - "provider": "locking", - "locking": { + "provider": "default", + "default": { "cacheContainer" : "java:comp/env/infinispan/Keycloak" } } diff --git a/model/infinispan/src/main/java/org/keycloak/connections/infinispan/DefaultInfinispanConnectionProviderFactory.java b/model/infinispan/src/main/java/org/keycloak/connections/infinispan/DefaultInfinispanConnectionProviderFactory.java index 01d229fd54..ded6c3c917 100755 --- a/model/infinispan/src/main/java/org/keycloak/connections/infinispan/DefaultInfinispanConnectionProviderFactory.java +++ b/model/infinispan/src/main/java/org/keycloak/connections/infinispan/DefaultInfinispanConnectionProviderFactory.java @@ -24,6 +24,7 @@ import org.infinispan.configuration.global.GlobalConfigurationBuilder; import org.infinispan.manager.DefaultCacheManager; import org.infinispan.manager.EmbeddedCacheManager; import org.infinispan.transaction.LockingMode; +import org.infinispan.transaction.TransactionMode; import org.infinispan.transaction.lookup.DummyTransactionManagerLookup; import org.jboss.logging.Logger; import org.keycloak.Config; @@ -154,6 +155,15 @@ public class DefaultInfinispanConnectionProviderFactory implements InfinispanCon } Configuration replicationCacheConfiguration = replicationConfigBuilder.build(); cacheManager.defineConfiguration(InfinispanConnectionProvider.WORK_CACHE_NAME, replicationCacheConfiguration); + + ConfigurationBuilder counterConfigBuilder = new ConfigurationBuilder(); + counterConfigBuilder.invocationBatching().enable() + .transaction().transactionMode(TransactionMode.TRANSACTIONAL); + counterConfigBuilder.transaction().transactionManagerLookup(new DummyTransactionManagerLookup()); + counterConfigBuilder.transaction().lockingMode(LockingMode.PESSIMISTIC); + Configuration counterCacheConfiguration = counterConfigBuilder.build(); + + cacheManager.defineConfiguration(InfinispanConnectionProvider.VERSION_CACHE_NAME, counterCacheConfiguration); } } diff --git a/model/infinispan/src/main/java/org/keycloak/connections/infinispan/InfinispanConnectionProvider.java b/model/infinispan/src/main/java/org/keycloak/connections/infinispan/InfinispanConnectionProvider.java old mode 100644 new mode 100755 index b37beb9c0c..8a21def7ec --- a/model/infinispan/src/main/java/org/keycloak/connections/infinispan/InfinispanConnectionProvider.java +++ b/model/infinispan/src/main/java/org/keycloak/connections/infinispan/InfinispanConnectionProvider.java @@ -25,6 +25,7 @@ import org.keycloak.provider.Provider; */ public interface InfinispanConnectionProvider extends Provider { + public static final String VERSION_CACHE_NAME = "realmVersions"; static final String REALM_CACHE_NAME = "realms"; static final String USER_CACHE_NAME = "users"; static final String SESSION_CACHE_NAME = "sessions"; diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/ClientAdapter.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/ClientAdapter.java index a9145b2bd1..cdaa2e7537 100755 --- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/ClientAdapter.java +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/ClientAdapter.java @@ -45,7 +45,7 @@ public class ClientAdapter implements ClientModel { private void getDelegateForUpdate() { if (updated == null) { - cacheSession.registerApplicationInvalidation(getId()); + cacheSession.registerClientInvalidation(getId()); updated = cacheSession.getDelegate().getClientById(getId(), cachedRealm); if (updated == null) throw new IllegalStateException("Not found in database"); } @@ -377,7 +377,6 @@ public class ClientAdapter implements ClientModel { public void setClientId(String clientId) { getDelegateForUpdate(); updated.setClientId(clientId); - cacheSession.registerRealmInvalidation(cachedRealm.getId()); } @Override diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/DefaultCacheRealmProvider.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/DefaultCacheRealmProvider.java deleted file mode 100755 index b998b8c02b..0000000000 --- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/DefaultCacheRealmProvider.java +++ /dev/null @@ -1,396 +0,0 @@ -/* - * Copyright 2016 Red Hat, Inc. and/or its affiliates - * and other contributors as indicated by the @author tags. - * - * Licensed 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.keycloak.models.cache.infinispan; - -import org.keycloak.migration.MigrationModel; -import org.keycloak.models.ClientModel; -import org.keycloak.models.ClientTemplateModel; -import org.keycloak.models.GroupModel; -import org.keycloak.models.KeycloakSession; -import org.keycloak.models.KeycloakTransaction; -import org.keycloak.models.RealmModel; -import org.keycloak.models.RealmProvider; -import org.keycloak.models.RoleModel; -import org.keycloak.models.cache.CacheRealmProvider; -import org.keycloak.models.cache.RealmCache; -import org.keycloak.models.cache.entities.CachedClient; -import org.keycloak.models.cache.entities.CachedClientRole; -import org.keycloak.models.cache.entities.CachedClientTemplate; -import org.keycloak.models.cache.entities.CachedGroup; -import org.keycloak.models.cache.entities.CachedRealm; -import org.keycloak.models.cache.entities.CachedRealmRole; -import org.keycloak.models.cache.entities.CachedRole; - -import java.util.HashMap; -import java.util.HashSet; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Set; - - -/** - * @author Bill Burke - * @version $Revision: 1 $ - */ -public class DefaultCacheRealmProvider implements CacheRealmProvider { - protected RealmCache cache; - protected KeycloakSession session; - protected RealmProvider delegate; - protected boolean transactionActive; - protected boolean setRollbackOnly; - - protected Set realmInvalidations = new HashSet<>(); - protected Set appInvalidations = new HashSet<>(); - protected Set clientTemplateInvalidations = new HashSet<>(); - protected Set roleInvalidations = new HashSet<>(); - protected Set groupInvalidations = new HashSet<>(); - protected Map managedRealms = new HashMap<>(); - protected Map managedApplications = new HashMap<>(); - protected Map managedClientTemplates = new HashMap<>(); - protected Map managedRoles = new HashMap<>(); - protected Map managedGroups = new HashMap<>(); - - protected boolean clearAll; - - public DefaultCacheRealmProvider(RealmCache cache, KeycloakSession session) { - this.cache = cache; - this.session = session; - - session.getTransaction().enlistAfterCompletion(getTransaction()); - } - - @Override - public void clear() { - cache.clear(); - } - - @Override - public MigrationModel getMigrationModel() { - return getDelegate().getMigrationModel(); - } - - @Override - public RealmProvider getDelegate() { - if (!transactionActive) throw new IllegalStateException("Cannot access delegate without a transaction"); - if (delegate != null) return delegate; - delegate = session.getProvider(RealmProvider.class); - return delegate; - } - - @Override - public void registerRealmInvalidation(String id) { - realmInvalidations.add(id); - } - - @Override - public void registerApplicationInvalidation(String id) { - appInvalidations.add(id); - } - @Override - public void registerClientTemplateInvalidation(String id) { - clientTemplateInvalidations.add(id); - } - - @Override - public void registerRoleInvalidation(String id) { - roleInvalidations.add(id); - } - - @Override - public void registerGroupInvalidation(String id) { - groupInvalidations.add(id); - - } - - protected void runInvalidations() { - for (String id : realmInvalidations) { - cache.invalidateRealmById(id); - } - for (String id : roleInvalidations) { - cache.invalidateRoleById(id); - } - for (String id : groupInvalidations) { - cache.invalidateGroupById(id); - } - for (String id : appInvalidations) { - cache.invalidateClientById(id); - } - for (String id : clientTemplateInvalidations) { - cache.invalidateClientTemplateById(id); - } - } - - private KeycloakTransaction getTransaction() { - return new KeycloakTransaction() { - @Override - public void begin() { - transactionActive = true; - } - - @Override - public void commit() { - if (delegate == null) return; - if (clearAll) { - cache.clear(); - } - runInvalidations(); - transactionActive = false; - } - - @Override - public void rollback() { - setRollbackOnly = true; - runInvalidations(); - transactionActive = false; - } - - @Override - public void setRollbackOnly() { - setRollbackOnly = true; - } - - @Override - public boolean getRollbackOnly() { - return setRollbackOnly; - } - - @Override - public boolean isActive() { - return transactionActive; - } - }; - } - - @Override - public RealmModel createRealm(String name) { - RealmModel realm = getDelegate().createRealm(name); - registerRealmInvalidation(realm.getId()); - return realm; - } - - @Override - public RealmModel createRealm(String id, String name) { - RealmModel realm = getDelegate().createRealm(id, name); - registerRealmInvalidation(realm.getId()); - return realm; - } - - @Override - public RealmModel getRealm(String id) { - CachedRealm cached = cache.getRealm(id); - if (cached == null) { - RealmModel model = getDelegate().getRealm(id); - if (model == null) return null; - if (realmInvalidations.contains(id)) return model; - cached = new CachedRealm(cache, this, model); - cache.addRealm(cached); - } else if (realmInvalidations.contains(id)) { - return getDelegate().getRealm(id); - } else if (managedRealms.containsKey(id)) { - return managedRealms.get(id); - } - RealmAdapter adapter = new RealmAdapter(cached, this); - managedRealms.put(id, adapter); - return adapter; - } - - @Override - public RealmModel getRealmByName(String name) { - CachedRealm cached = cache.getRealmByName(name); - if (cached == null) { - RealmModel model = getDelegate().getRealmByName(name); - if (model == null) return null; - if (realmInvalidations.contains(model.getId())) return model; - cached = new CachedRealm(cache, this, model); - cache.addRealm(cached); - } else if (realmInvalidations.contains(cached.getId())) { - return getDelegate().getRealmByName(name); - } else if (managedRealms.containsKey(cached.getId())) { - return managedRealms.get(cached.getId()); - } - RealmAdapter adapter = new RealmAdapter(cached, this); - managedRealms.put(cached.getId(), adapter); - return adapter; - } - - @Override - public List getRealms() { - // Retrieve realms from backend - List backendRealms = getDelegate().getRealms(); - - // Return cache delegates to ensure cache invalidated during write operations - List cachedRealms = new LinkedList(); - for (RealmModel realm : backendRealms) { - RealmModel cached = getRealm(realm.getId()); - cachedRealms.add(cached); - } - return cachedRealms; - } - - @Override - public boolean removeRealm(String id) { - cache.invalidateRealmById(id); - - RealmModel realm = getDelegate().getRealm(id); - Set realmRoles = null; - if (realm != null) { - realmRoles = realm.getRoles(); - } - - boolean didIt = getDelegate().removeRealm(id); - realmInvalidations.add(id); - - // TODO: Temporary workaround to invalidate cached realm roles - if (didIt && realmRoles != null) { - for (RoleModel role : realmRoles) { - roleInvalidations.add(role.getId()); - } - } - - return didIt; - } - - @Override - public void close() { - if (delegate != null) delegate.close(); - } - - @Override - public RoleModel getRoleById(String id, RealmModel realm) { - CachedRole cached = cache.getRole(id); - if (cached != null && !cached.getRealm().equals(realm.getId())) { - cached = null; - } - - if (cached == null) { - RoleModel model = getDelegate().getRoleById(id, realm); - if (model == null) return null; - if (roleInvalidations.contains(id)) return model; - if (model.getContainer() instanceof ClientModel) { - cached = new CachedClientRole(((ClientModel) model.getContainer()).getId(), model, realm); - } else { - cached = new CachedRealmRole(model, realm); - } - cache.addRole(cached); - - } else if (roleInvalidations.contains(id)) { - return getDelegate().getRoleById(id, realm); - } else if (managedRoles.containsKey(id)) { - return managedRoles.get(id); - } - RoleAdapter adapter = new RoleAdapter(cached, cache, this, realm); - managedRoles.put(id, adapter); - return adapter; - } - - @Override - public GroupModel getGroupById(String id, RealmModel realm) { - CachedGroup cached = cache.getGroup(id); - if (cached != null && !cached.getRealm().equals(realm.getId())) { - cached = null; - } - - if (cached == null) { - GroupModel model = getDelegate().getGroupById(id, realm); - if (model == null) return null; - if (groupInvalidations.contains(id)) return model; - cached = new CachedGroup(realm, model); - cache.addGroup(cached); - - } else if (groupInvalidations.contains(id)) { - return getDelegate().getGroupById(id, realm); - } else if (managedGroups.containsKey(id)) { - return managedGroups.get(id); - } - GroupAdapter adapter = new GroupAdapter(cached, this, session, realm); - managedGroups.put(id, adapter); - return adapter; - } - - @Override - public ClientModel getClientById(String id, RealmModel realm) { - CachedClient cached = cache.getClient(id); - if (cached != null && !cached.getRealm().equals(realm.getId())) { - cached = null; - } - - if (cached == null) { - ClientModel model = getDelegate().getClientById(id, realm); - if (model == null) return null; - if (appInvalidations.contains(id)) return model; - cached = new CachedClient(cache, getDelegate(), realm, model); - cache.addClient(cached); - } else if (appInvalidations.contains(id)) { - return getDelegate().getClientById(id, realm); - } else if (managedApplications.containsKey(id)) { - return managedApplications.get(id); - } - ClientAdapter adapter = new ClientAdapter(realm, cached, this, cache); - managedApplications.put(id, adapter); - return adapter; - } - - @Override - public ClientModel getClientByClientId(String clientId, RealmModel realm) { - return getDelegate().getClientByClientId(clientId, realm); - } - - @Override - public boolean removeClient(String id, RealmModel realm) { - ClientModel client = getClientById(id, realm); - if (client == null) return false; - registerApplicationInvalidation(id); - registerRealmInvalidation(realm.getId()); - cache.invalidateClientById(id); - cache.invalidateRealmById(realm.getId()); - - - - Set roles = client.getRoles(); - for (RoleModel role : roles) { - registerRoleInvalidation(role.getId()); - } - return getDelegate().removeClient(id, realm); - } - - - @Override - public ClientTemplateModel getClientTemplateById(String id, RealmModel realm) { - CachedClientTemplate cached = cache.getClientTemplate(id); - if (cached != null && !cached.getRealm().equals(realm.getId())) { - cached = null; - } - - if (cached == null) { - ClientTemplateModel model = getDelegate().getClientTemplateById(id, realm); - if (model == null) return null; - if (clientTemplateInvalidations.contains(id)) return model; - cached = new CachedClientTemplate(cache, getDelegate(), realm, model); - cache.addClientTemplate(cached); - } else if (clientTemplateInvalidations.contains(id)) { - return getDelegate().getClientTemplateById(id, realm); - } else if (managedClientTemplates.containsKey(id)) { - return managedClientTemplates.get(id); - } - ClientTemplateModel adapter = new ClientTemplateAdapter(realm, cached, this, cache); - managedClientTemplates.put(id, adapter); - return adapter; - } - -} diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/InfinispanCacheRealmProviderFactory.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/InfinispanCacheRealmProviderFactory.java index 34aa5ced85..39bc4938e4 100755 --- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/InfinispanCacheRealmProviderFactory.java +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/InfinispanCacheRealmProviderFactory.java @@ -36,6 +36,8 @@ import org.keycloak.models.cache.CacheRealmProvider; import org.keycloak.models.cache.CacheRealmProviderFactory; import org.keycloak.models.cache.entities.CachedClient; import org.keycloak.models.cache.entities.CachedRealm; +import org.keycloak.models.cache.infinispan.stream.StreamCacheRealmProvider; +import org.keycloak.models.cache.infinispan.stream.StreamRealmCache; import java.util.concurrent.ConcurrentHashMap; @@ -47,14 +49,12 @@ public class InfinispanCacheRealmProviderFactory implements CacheRealmProviderFa private static final Logger log = Logger.getLogger(InfinispanCacheRealmProviderFactory.class); - protected volatile InfinispanRealmCache realmCache; - - protected final ConcurrentHashMap realmLookup = new ConcurrentHashMap<>(); + protected volatile StreamRealmCache realmCache; @Override public CacheRealmProvider create(KeycloakSession session) { lazyInit(session); - return new DefaultCacheRealmProvider(realmCache, session); + return new StreamCacheRealmProvider(realmCache, session); } private void lazyInit(KeycloakSession session) { @@ -62,8 +62,8 @@ public class InfinispanCacheRealmProviderFactory implements CacheRealmProviderFa synchronized (this) { if (realmCache == null) { Cache cache = session.getProvider(InfinispanConnectionProvider.class).getCache(InfinispanConnectionProvider.REALM_CACHE_NAME); - cache.addListener(new CacheListener()); - realmCache = new InfinispanRealmCache(cache, realmLookup); + Cache revisions = session.getProvider(InfinispanConnectionProvider.class).getCache(InfinispanConnectionProvider.VERSION_CACHE_NAME); + realmCache = new StreamRealmCache(cache, revisions); } } } @@ -84,77 +84,7 @@ public class InfinispanCacheRealmProviderFactory implements CacheRealmProviderFa @Override public String getId() { - return "infinispan"; + return "default"; } - @Listener - public class CacheListener { - - @CacheEntryCreated - public void created(CacheEntryCreatedEvent event) { - if (!event.isPre()) { - Object object = event.getValue(); - if (object != null) { - if (object instanceof CachedRealm) { - CachedRealm realm = (CachedRealm) object; - realmLookup.put(realm.getName(), realm.getId()); - log.tracev("Realm added realm={0}", realm.getName()); - } - } - } - } - - @CacheEntryRemoved - public void removed(CacheEntryRemovedEvent event) { - if (event.isPre()) { - Object object = event.getValue(); - if (object != null) { - remove(object); - } - } - } - - @CacheEntryInvalidated - public void removed(CacheEntryInvalidatedEvent event) { - if (event.isPre()) { - Object object = event.getValue(); - if (object != null) { - remove(object); - } - } - } - - @CacheEntriesEvicted - public void userEvicted(CacheEntriesEvictedEvent event) { - for (Object object : event.getEntries().values()) { - remove(object); - } - } - - private void remove(Object object) { - if (object instanceof CachedRealm) { - CachedRealm realm = (CachedRealm) object; - - realmLookup.remove(realm.getName()); - - for (String r : realm.getRealmRoles().values()) { - realmCache.evictRoleById(r); - } - - for (String c : realm.getClients()) { - realmCache.evictClientById(c); - } - - log.tracev("Realm removed realm={0}", realm.getName()); - } else if (object instanceof CachedClient) { - CachedClient client = (CachedClient) object; - - for (String r : client.getRoles().values()) { - realmCache.evictRoleById(r); - } - - log.tracev("Client removed client={0}", client.getId()); - } - } - } } diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/InfinispanCacheUserProviderFactory.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/InfinispanCacheUserProviderFactory.java index b5f62e22fb..b473d60e9f 100755 --- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/InfinispanCacheUserProviderFactory.java +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/InfinispanCacheUserProviderFactory.java @@ -78,7 +78,7 @@ public class InfinispanCacheUserProviderFactory implements CacheUserProviderFact @Override public String getId() { - return "infinispan"; + return "default"; } @Listener diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/InfinispanRealmCache.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/InfinispanRealmCache.java deleted file mode 100755 index 8dfe923c28..0000000000 --- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/InfinispanRealmCache.java +++ /dev/null @@ -1,202 +0,0 @@ -/* - * Copyright 2016 Red Hat, Inc. and/or its affiliates - * and other contributors as indicated by the @author tags. - * - * Licensed 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.keycloak.models.cache.infinispan; - -import org.infinispan.Cache; -import org.jboss.logging.Logger; -import org.keycloak.models.cache.RealmCache; -import org.keycloak.models.cache.entities.CachedClient; -import org.keycloak.models.cache.entities.CachedClientTemplate; -import org.keycloak.models.cache.entities.CachedGroup; -import org.keycloak.models.cache.entities.CachedRealm; -import org.keycloak.models.cache.entities.CachedRole; - -import java.util.concurrent.ConcurrentHashMap; - -/** - * @author Stian Thorgersen - */ -public class InfinispanRealmCache implements RealmCache { - - protected static final Logger logger = Logger.getLogger(InfinispanRealmCache.class); - - protected final Cache cache; - protected final ConcurrentHashMap realmLookup; - - public InfinispanRealmCache(Cache cache, ConcurrentHashMap realmLookup) { - this.cache = cache; - this.realmLookup = realmLookup; - } - - public Cache getCache() { - return cache; - } - - @Override - public void clear() { - cache.clear(); - } - - @Override - public CachedRealm getRealm(String id) { - return get(id, CachedRealm.class); - } - - @Override - public void invalidateRealm(CachedRealm realm) { - logger.tracev("Invalidating realm {0}", realm.getId()); - cache.remove(realm.getId()); - realmLookup.remove(realm.getName()); - } - - @Override - public void invalidateRealmById(String id) { - CachedRealm cached = (CachedRealm) cache.remove(id); - if (cached != null) realmLookup.remove(cached.getName()); - } - - @Override - public void addRealm(CachedRealm realm) { - logger.tracev("Adding realm {0}", realm.getId()); - cache.putForExternalRead(realm.getId(), realm); - realmLookup.put(realm.getName(), realm.getId()); - } - - @Override - public CachedRealm getRealmByName(String name) { - String id = realmLookup.get(name); - return id != null ? getRealm(id) : null; - } - - @Override - public CachedClient getClient(String id) { - return get(id, CachedClient.class); - } - - @Override - public void invalidateClient(CachedClient app) { - logger.tracev("Removing application {0}", app.getId()); - cache.remove(app.getId()); - } - - @Override - public void addClient(CachedClient app) { - logger.tracev("Adding application {0}", app.getId()); - cache.putForExternalRead(app.getId(), app); - } - - @Override - public void invalidateClientById(String id) { - logger.tracev("Removing application {0}", id); - cache.remove(id); - } - - @Override - public void evictClientById(String id) { - logger.tracev("Evicting application {0}", id); - cache.evict(id); - } - - @Override - public CachedGroup getGroup(String id) { - return get(id, CachedGroup.class); - } - - @Override - public void invalidateGroup(CachedGroup role) { - logger.tracev("Removing group {0}", role.getId()); - cache.remove(role.getId()); - } - - @Override - public void addGroup(CachedGroup role) { - logger.tracev("Adding group {0}", role.getId()); - cache.putForExternalRead(role.getId(), role); - } - - @Override - public void invalidateGroupById(String id) { - logger.tracev("Removing group {0}", id); - cache.remove(id); - } - - @Override - public CachedRole getRole(String id) { - return get(id, CachedRole.class); - } - - @Override - public void invalidateRole(CachedRole role) { - logger.tracev("Removing role {0}", role.getId()); - cache.remove(role.getId()); - } - - @Override - public void invalidateRoleById(String id) { - logger.tracev("Removing role {0}", id); - cache.remove(id); - } - - @Override - public void evictRoleById(String id) { - logger.tracev("Evicting role {0}", id); - cache.evict(id); - } - - @Override - public void addRole(CachedRole role) { - logger.tracev("Adding role {0}", role.getId()); - cache.putForExternalRead(role.getId(), role); - } - - private T get(String id, Class type) { - Object o = cache.get(id); - return o != null && type.isInstance(o) ? type.cast(o) : null; - } - - @Override - public CachedClientTemplate getClientTemplate(String id) { - return get(id, CachedClientTemplate.class); - } - - @Override - public void invalidateClientTemplate(CachedClientTemplate app) { - logger.tracev("Removing client template {0}", app.getId()); - cache.remove(app.getId()); - } - - @Override - public void addClientTemplate(CachedClientTemplate app) { - logger.tracev("Adding client template {0}", app.getId()); - cache.putForExternalRead(app.getId(), app); - } - - @Override - public void invalidateClientTemplateById(String id) { - logger.tracev("Removing client template {0}", id); - cache.remove(id); - } - - @Override - public void evictClientTemplateById(String id) { - logger.tracev("Evicting client template {0}", id); - cache.evict(id); - } - - -} diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/InfinispanUserCache.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/InfinispanUserCache.java index 52edabcb7d..de83e6ac71 100755 --- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/InfinispanUserCache.java +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/InfinispanUserCache.java @@ -27,7 +27,7 @@ import org.keycloak.models.cache.entities.CachedUser; */ public class InfinispanUserCache implements UserCache { - protected static final Logger logger = Logger.getLogger(InfinispanRealmCache.class); + protected static final Logger logger = Logger.getLogger(InfinispanUserCache.class); protected volatile boolean enabled = true; diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/RealmAdapter.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/RealmAdapter.java index 2f3048ad31..39564ef434 100755 --- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/RealmAdapter.java +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/RealmAdapter.java @@ -589,40 +589,23 @@ public class RealmAdapter implements RealmModel { @Override public List getClients() { - if (updated != null) return updated.getClients(); - List apps = new LinkedList<>(); - for (String id : cached.getClients()) { - ClientModel model = cacheSession.getClientById(id, this); - if (model == null) { - throw new IllegalStateException("Cached application not found: " + id); - } - apps.add(model); - } - return Collections.unmodifiableList(apps); + return cacheSession.getClients(this); } @Override public ClientModel addClient(String name) { - getDelegateForUpdate(); - ClientModel app = updated.addClient(name); - cacheSession.registerApplicationInvalidation(app.getId()); - return app; + return cacheSession.addClient(this, name); } @Override public ClientModel addClient(String id, String clientId) { - getDelegateForUpdate(); - ClientModel app = updated.addClient(id, clientId); - cacheSession.registerApplicationInvalidation(app.getId()); - return app; + return cacheSession.addClient(this, id, clientId); } @Override public boolean removeClient(String id) { - cacheSession.registerApplicationInvalidation(id); - getDelegateForUpdate(); - return updated.removeClient(id); + return cacheSession.removeClient(id, this); } @Override diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/RoleAdapter.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/RoleAdapter.java index 6458c1ae1e..c7ebc44cfb 100755 --- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/RoleAdapter.java +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/RoleAdapter.java @@ -125,7 +125,7 @@ public class RoleAdapter implements RoleModel { for (String id : cached.getComposites()) { RoleModel role = realm.getRoleById(id); if (role == null) { - throw new IllegalStateException("Could not find composite: " + id); + throw new IllegalStateException("Could not find composite in role " + getName() + ": " + id); } set.add(role); } @@ -138,7 +138,7 @@ public class RoleAdapter implements RoleModel { return realm; } else { CachedClientRole appRole = (CachedClientRole)cached; - return realm.getClientById(appRole.getIdClient()); + return realm.getClientById(appRole.getClientId()); } } diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/locking/LockingCacheRealmProviderFactory.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/locking/LockingCacheRealmProviderFactory.java deleted file mode 100755 index d2bfbf4389..0000000000 --- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/locking/LockingCacheRealmProviderFactory.java +++ /dev/null @@ -1,159 +0,0 @@ -/* - * Copyright 2016 Red Hat, Inc. and/or its affiliates - * and other contributors as indicated by the @author tags. - * - * Licensed 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.keycloak.models.cache.infinispan.locking; - -import org.infinispan.Cache; -import org.infinispan.notifications.Listener; -import org.infinispan.notifications.cachelistener.annotation.CacheEntriesEvicted; -import org.infinispan.notifications.cachelistener.annotation.CacheEntryCreated; -import org.infinispan.notifications.cachelistener.annotation.CacheEntryInvalidated; -import org.infinispan.notifications.cachelistener.annotation.CacheEntryRemoved; -import org.infinispan.notifications.cachelistener.event.CacheEntriesEvictedEvent; -import org.infinispan.notifications.cachelistener.event.CacheEntryCreatedEvent; -import org.infinispan.notifications.cachelistener.event.CacheEntryInvalidatedEvent; -import org.infinispan.notifications.cachelistener.event.CacheEntryRemovedEvent; -import org.jboss.logging.Logger; -import org.keycloak.Config; -import org.keycloak.connections.infinispan.InfinispanConnectionProvider; -import org.keycloak.models.KeycloakSession; -import org.keycloak.models.KeycloakSessionFactory; -import org.keycloak.models.cache.CacheRealmProvider; -import org.keycloak.models.cache.CacheRealmProviderFactory; -import org.keycloak.models.cache.entities.CachedClient; -import org.keycloak.models.cache.entities.CachedRealm; - -/** - * @author Bill Burke - * @author Stian Thorgersen - */ -public class LockingCacheRealmProviderFactory implements CacheRealmProviderFactory { - - private static final Logger log = Logger.getLogger(LockingCacheRealmProviderFactory.class); - - protected volatile LockingRealmCache realmCache; - - @Override - public CacheRealmProvider create(KeycloakSession session) { - lazyInit(session); - return new LockingCacheRealmProvider(realmCache, session); - } - - private void lazyInit(KeycloakSession session) { - if (realmCache == null) { - synchronized (this) { - if (realmCache == null) { - Cache cache = session.getProvider(InfinispanConnectionProvider.class).getCache(InfinispanConnectionProvider.REALM_CACHE_NAME); - Cache counterCache = session.getProvider(InfinispanConnectionProvider.class).getCache(LockingConnectionProviderFactory.VERSION_CACHE_NAME); - cache.addListener(new CacheListener()); - realmCache = new LockingRealmCache(cache, counterCache); - } - } - } - } - - @Override - public void init(Config.Scope config) { - } - - @Override - public void postInit(KeycloakSessionFactory factory) { - - } - - @Override - public void close() { - } - - @Override - public String getId() { - return "infinispan-locking"; - } - - @Listener - public class CacheListener { - - @CacheEntryCreated - public void created(CacheEntryCreatedEvent event) { - if (!event.isPre()) { - Object object = event.getValue(); - if (object != null) { - if (object instanceof CachedRealm) { - CachedRealm realm = (CachedRealm) object; - realmCache.getRealmLookup().put(realm.getName(), realm.getId()); - log.tracev("Realm added realm={0}", realm.getName()); - } - } - } - } - - @CacheEntryRemoved - public void removed(CacheEntryRemovedEvent event) { - if (event.isPre()) { - Object object = event.getValue(); - if (object != null) { - remove(object); - } - } - } - - @CacheEntryInvalidated - public void removed(CacheEntryInvalidatedEvent event) { - if (event.isPre()) { - Object object = event.getValue(); - if (object != null) { - remove(object); - } - } - } - - @CacheEntriesEvicted - public void userEvicted(CacheEntriesEvictedEvent event) { - for (Object object : event.getEntries().values()) { - remove(object); - } - } - - private void remove(Object object) { - if (object instanceof CachedRealm) { - CachedRealm realm = (CachedRealm) object; - - realmCache.getRealmLookup().remove(realm.getName()); - - for (String r : realm.getRealmRoles().values()) { - realmCache.evictRoleById(r); - } - - for (String c : realm.getClients()) { - realmCache.evictClientById(c); - } - - log.tracev("Realm removed realm={0}", realm.getName()); - } else if (object instanceof CachedClient) { - CachedClient client = (CachedClient) object; - - realmCache.getClientLookup().remove(client.getRealm() + "." + client.getClientId()); - - for (String r : client.getRoles().values()) { - realmCache.evictRoleById(r); - } - - log.tracev("Client removed client={0}", client.getId()); - } - } - } -} diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/locking/LockingConnectionProviderFactory.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/locking/LockingConnectionProviderFactory.java deleted file mode 100755 index 68da34dac2..0000000000 --- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/locking/LockingConnectionProviderFactory.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2016 Red Hat, Inc. and/or its affiliates - * and other contributors as indicated by the @author tags. - * - * Licensed 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.keycloak.models.cache.infinispan.locking; - -import org.infinispan.configuration.cache.Configuration; -import org.infinispan.configuration.cache.ConfigurationBuilder; -import org.infinispan.transaction.LockingMode; -import org.infinispan.transaction.TransactionMode; -import org.infinispan.transaction.lookup.DummyTransactionManagerLookup; -import org.jboss.logging.Logger; -import org.keycloak.connections.infinispan.DefaultInfinispanConnectionProviderFactory; - -/** - * @author Stian Thorgersen - */ -public class LockingConnectionProviderFactory extends DefaultInfinispanConnectionProviderFactory { - public static final String VERSION_CACHE_NAME = "realmVersions"; - - protected static final Logger logger = Logger.getLogger(LockingConnectionProviderFactory.class); - - @Override - public String getId() { - return "locking"; - } - - - protected void initEmbedded() { - super.initEmbedded(); - ConfigurationBuilder counterConfigBuilder = new ConfigurationBuilder(); - counterConfigBuilder.invocationBatching().enable() - .transaction().transactionMode(TransactionMode.TRANSACTIONAL); - counterConfigBuilder.transaction().transactionManagerLookup(new DummyTransactionManagerLookup()); - counterConfigBuilder.transaction().lockingMode(LockingMode.PESSIMISTIC); - Configuration counterCacheConfiguration = counterConfigBuilder.build(); - - cacheManager.defineConfiguration(VERSION_CACHE_NAME, counterCacheConfiguration); - } - -} diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/locking/LockingRealmCache.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/locking/LockingRealmCache.java deleted file mode 100755 index a77c59b8e2..0000000000 --- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/locking/LockingRealmCache.java +++ /dev/null @@ -1,300 +0,0 @@ -/* - * Copyright 2016 Red Hat, Inc. and/or its affiliates - * and other contributors as indicated by the @author tags. - * - * Licensed 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.keycloak.models.cache.infinispan.locking; - -import org.infinispan.Cache; -import org.jboss.logging.Logger; -import org.keycloak.models.RealmModel; -import org.keycloak.models.cache.RealmCache; -import org.keycloak.models.cache.entities.CachedClient; -import org.keycloak.models.cache.entities.CachedClientTemplate; -import org.keycloak.models.cache.entities.CachedGroup; -import org.keycloak.models.cache.entities.CachedRealm; -import org.keycloak.models.cache.entities.CachedRole; - -import java.util.concurrent.ConcurrentHashMap; - -/** - * @author Stian Thorgersen - */ -public class LockingRealmCache implements RealmCache { - - protected static final Logger logger = Logger.getLogger(LockingRealmCache.class); - - protected final Cache revisions; - protected final Cache cache; - - protected final ConcurrentHashMap realmLookup = new ConcurrentHashMap<>(); - protected final ConcurrentHashMap clientLookup = new ConcurrentHashMap<>(); - - public LockingRealmCache(Cache cache, Cache revisions) { - this.cache = cache; - this.revisions = revisions; - } - - public Cache getCache() { - return cache; - } - - public Cache getRevisions() { - return revisions; - } - - public ConcurrentHashMap getRealmLookup() { - return realmLookup; - } - - public ConcurrentHashMap getClientLookup() { - return clientLookup; - } - - public Long getCurrentRevision(String id) { - return revisions.get(id); - } - - public void endRevisionBatch() { - try { - revisions.endBatch(true); - } catch (Exception e) { - } - - } - - private T get(String id, Class type) { - Revisioned o = (Revisioned)cache.get(id); - if (o == null) { - return null; - } - Long rev = revisions.get(id); - if (rev == null) { - logger.tracev("get() missing rev"); - return null; - } - long oRev = o.getRevision() == null ? -1L : o.getRevision().longValue(); - if (rev > oRev) { - logger.tracev("get() rev: {0} o.rev: {1}", rev.longValue(), oRev); - return null; - } - return o != null && type.isInstance(o) ? type.cast(o) : null; - } - - protected Object invalidateObject(String id) { - Object removed = cache.remove(id); - revisions.put(id, UpdateCounter.next()); - return removed; - } - - protected void addRevisioned(String id, Revisioned object) { - //startRevisionBatch(); - try { - //revisions.getAdvancedCache().lock(id); - Long rev = revisions.get(id); - if (rev == null) { - rev = UpdateCounter.current(); - revisions.put(id, rev); - } - revisions.startBatch(); - if (!revisions.getAdvancedCache().lock(id)) { - logger.trace("Could not obtain version lock"); - } - rev = revisions.get(id); - if (rev == null) { - return; - } - if (rev.equals(object.getRevision())) { - cache.putForExternalRead(id, object); - return; - } - if (rev > object.getRevision()) { // revision is ahead, don't cache - return; - } - // revisions cache has a lower value than the object.revision, so update revision and add it to cache - revisions.put(id, object.getRevision()); - cache.putForExternalRead(id, object); - } finally { - endRevisionBatch(); - } - - } - - - - - @Override - public void clear() { - cache.clear(); - } - - @Override - public CachedRealm getRealm(String id) { - return get(id, CachedRealm.class); - } - - @Override - public void invalidateRealm(CachedRealm realm) { - logger.tracev("Invalidating realm {0}", realm.getId()); - invalidateObject(realm.getId()); - realmLookup.remove(realm.getName()); - } - - @Override - public void invalidateRealmById(String id) { - CachedRealm cached = (CachedRealm) invalidateObject(id); - if (cached != null) realmLookup.remove(cached.getName()); - } - - @Override - public void addRealm(CachedRealm realm) { - logger.tracev("Adding realm {0}", realm.getId()); - addRevisioned(realm.getId(), (Revisioned) realm); - realmLookup.put(realm.getName(), realm.getId()); - } - - - @Override - public CachedRealm getRealmByName(String name) { - String id = realmLookup.get(name); - return id != null ? getRealm(id) : null; - } - - @Override - public CachedClient getClient(String id) { - return get(id, CachedClient.class); - } - - public CachedClient getClientByClientId(RealmModel realm, String clientId) { - String id = clientLookup.get(realm.getId() + "." + clientId); - return id != null ? getClient(id) : null; - } - - @Override - public void invalidateClient(CachedClient app) { - logger.tracev("Removing application {0}", app.getId()); - invalidateObject(app.getId()); - clientLookup.remove(getClientIdKey(app)); - } - - @Override - public void addClient(CachedClient app) { - logger.tracev("Adding application {0}", app.getId()); - addRevisioned(app.getId(), (Revisioned) app); - clientLookup.put(getClientIdKey(app), app.getId()); - } - - @Override - public void invalidateClientById(String id) { - CachedClient client = (CachedClient)invalidateObject(id); - if (client != null) { - logger.tracev("Removing application {0}", client.getClientId()); - clientLookup.remove(getClientIdKey(client)); - } - } - - protected String getClientIdKey(CachedClient client) { - return client.getRealm() + "." + client.getClientId(); - } - - @Override - public void evictClientById(String id) { - logger.tracev("Evicting application {0}", id); - cache.evict(id); - } - - @Override - public CachedGroup getGroup(String id) { - return get(id, CachedGroup.class); - } - - @Override - public void invalidateGroup(CachedGroup role) { - logger.tracev("Removing group {0}", role.getId()); - invalidateObject(role.getId()); - } - - @Override - public void addGroup(CachedGroup role) { - logger.tracev("Adding group {0}", role.getId()); - addRevisioned(role.getId(), (Revisioned) role); - } - - @Override - public void invalidateGroupById(String id) { - logger.tracev("Removing group {0}", id); - invalidateObject(id); - } - - @Override - public CachedRole getRole(String id) { - return get(id, CachedRole.class); - } - - @Override - public void invalidateRole(CachedRole role) { - logger.tracev("Removing role {0}", role.getId()); - invalidateObject(role.getId()); - } - - @Override - public void invalidateRoleById(String id) { - logger.tracev("Removing role {0}", id); - invalidateObject(id); - } - - @Override - public void evictRoleById(String id) { - logger.tracev("Evicting role {0}", id); - cache.evict(id); - } - - @Override - public void addRole(CachedRole role) { - logger.tracev("Adding role {0}", role.getId()); - addRevisioned(role.getId(), (Revisioned) role); - } - - @Override - public CachedClientTemplate getClientTemplate(String id) { - return get(id, CachedClientTemplate.class); - } - - @Override - public void invalidateClientTemplate(CachedClientTemplate app) { - logger.tracev("Removing client template {0}", app.getId()); - invalidateObject(app.getId()); - } - - @Override - public void addClientTemplate(CachedClientTemplate app) { - logger.tracev("Adding client template {0}", app.getId()); - addRevisioned(app.getId(), (Revisioned) app); - } - - @Override - public void invalidateClientTemplateById(String id) { - logger.tracev("Removing client template {0}", id); - invalidateObject(id); - } - - @Override - public void evictClientTemplateById(String id) { - logger.tracev("Evicting client template {0}", id); - cache.evict(id); - } - - -} diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/ClientListQuery.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/ClientListQuery.java new file mode 100755 index 0000000000..1a7d5e2d05 --- /dev/null +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/ClientListQuery.java @@ -0,0 +1,50 @@ +package org.keycloak.models.cache.infinispan.stream; + +import org.keycloak.models.RealmModel; +import org.keycloak.models.cache.infinispan.stream.entities.AbstractRevisioned; + +import java.util.HashSet; +import java.util.Set; + +/** + * @author Bill Burke + * @version $Revision: 1 $ + */ +public class ClientListQuery extends AbstractRevisioned implements ClientQuery { + private final Set clients; + private final String realm; + private final String realmName; + + public ClientListQuery(Long revisioned, String id, RealmModel realm, Set clients) { + super(revisioned, id); + this.realm = realm.getId(); + this.realmName = realm.getName(); + this.clients = clients; + } + + public ClientListQuery(Long revisioned, String id, RealmModel realm, String client) { + super(revisioned, id); + this.realm = realm.getId(); + this.realmName = realm.getName(); + this.clients = new HashSet<>(); + this.clients.add(client); + } + + @Override + public Set getClients() { + return clients; + } + + @Override + public String getRealm() { + return realm; + } + + @Override + public String toString() { + return "ClientListQuery{" + + "id='" + getId() + "'" + + "realmName='" + realmName + '\'' + + '}'; + } +} diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/ClientQuery.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/ClientQuery.java new file mode 100755 index 0000000000..399ec693ed --- /dev/null +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/ClientQuery.java @@ -0,0 +1,14 @@ +package org.keycloak.models.cache.infinispan.stream; + +import org.keycloak.models.cache.infinispan.stream.entities.InRealm; + +import java.util.List; +import java.util.Set; + +/** + * @author Bill Burke + * @version $Revision: 1 $ + */ +public interface ClientQuery extends InRealm { + Set getClients(); +} diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/ClientQueryPredicate.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/ClientQueryPredicate.java new file mode 100755 index 0000000000..1e0c555519 --- /dev/null +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/ClientQueryPredicate.java @@ -0,0 +1,46 @@ +package org.keycloak.models.cache.infinispan.stream; + +import org.jboss.logging.Logger; + +import java.io.Serializable; +import java.util.Map; +import java.util.function.Predicate; + +/** + * @author Bill Burke + * @version $Revision: 1 $ + */ +public class ClientQueryPredicate implements Predicate>, Serializable { + protected static final Logger logger = Logger.getLogger(ClientQueryPredicate.class); + private String client; + private String inRealm; + + public static ClientQueryPredicate create() { + return new ClientQueryPredicate(); + } + + public ClientQueryPredicate client(String client) { + this.client = client; + return this; + } + + public ClientQueryPredicate inRealm(String inRealm) { + this.inRealm = inRealm; + return this; + } + + + + + + @Override + public boolean test(Map.Entry entry) { + Object value = entry.getValue(); + if (value == null) return false; + if (!(value instanceof ClientQuery)) return false; + ClientQuery query = (ClientQuery)value; + if (client != null && !query.getClients().contains(client)) return false; + if (inRealm != null && !query.getRealm().equals(inRealm)) return false; + return true; + } +} diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/ClientTemplateQuery.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/ClientTemplateQuery.java new file mode 100755 index 0000000000..e63cb67de4 --- /dev/null +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/ClientTemplateQuery.java @@ -0,0 +1,13 @@ +package org.keycloak.models.cache.infinispan.stream; + +import org.keycloak.models.cache.infinispan.stream.entities.InRealm; + +import java.util.Set; + +/** + * @author Bill Burke + * @version $Revision: 1 $ + */ +public interface ClientTemplateQuery extends InRealm { + Set getTemplates(); +} diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/ClientTemplateQueryPredicate.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/ClientTemplateQueryPredicate.java new file mode 100755 index 0000000000..ebf4b6ce63 --- /dev/null +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/ClientTemplateQueryPredicate.java @@ -0,0 +1,37 @@ +package org.keycloak.models.cache.infinispan.stream; + +import java.io.Serializable; +import java.util.Map; +import java.util.function.Predicate; + +/** + * @author Bill Burke + * @version $Revision: 1 $ + */ +public class ClientTemplateQueryPredicate implements Predicate>, Serializable { + private String template; + + public static ClientTemplateQueryPredicate create() { + return new ClientTemplateQueryPredicate(); + } + + public ClientTemplateQueryPredicate template(String template) { + this.template = template; + return this; + } + + + + + + @Override + public boolean test(Map.Entry entry) { + Object value = entry.getValue(); + if (value == null) return false; + if (!(value instanceof ClientTemplateQuery)) return false; + ClientTemplateQuery query = (ClientTemplateQuery)value; + + + return query.getTemplates().contains(template); + } +} diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/GroupQuery.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/GroupQuery.java new file mode 100755 index 0000000000..b3d86c0c93 --- /dev/null +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/GroupQuery.java @@ -0,0 +1,13 @@ +package org.keycloak.models.cache.infinispan.stream; + +import org.keycloak.models.cache.infinispan.stream.entities.InRealm; + +import java.util.Set; + +/** + * @author Bill Burke + * @version $Revision: 1 $ + */ +public interface GroupQuery extends InRealm { + Set getGroups(); +} diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/GroupQueryPredicate.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/GroupQueryPredicate.java new file mode 100755 index 0000000000..6e4a662969 --- /dev/null +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/GroupQueryPredicate.java @@ -0,0 +1,37 @@ +package org.keycloak.models.cache.infinispan.stream; + +import java.io.Serializable; +import java.util.Map; +import java.util.function.Predicate; + +/** + * @author Bill Burke + * @version $Revision: 1 $ + */ +public class GroupQueryPredicate implements Predicate>, Serializable { + private String group; + + public static GroupQueryPredicate create() { + return new GroupQueryPredicate(); + } + + public GroupQueryPredicate group(String group) { + this.group = group; + return this; + } + + + + + + @Override + public boolean test(Map.Entry entry) { + Object value = entry.getValue(); + if (value == null) return false; + if (!(value instanceof GroupQuery)) return false; + GroupQuery query = (GroupQuery)value; + + + return query.getGroups().contains(group); + } +} diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/HasRolePredicate.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/HasRolePredicate.java new file mode 100755 index 0000000000..5946726ae7 --- /dev/null +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/HasRolePredicate.java @@ -0,0 +1,40 @@ +package org.keycloak.models.cache.infinispan.stream; + +import org.keycloak.models.cache.entities.CachedGroup; +import org.keycloak.models.cache.entities.CachedRole; + +import java.io.Serializable; +import java.util.Map; +import java.util.function.Predicate; + +/** + * @author Bill Burke + * @version $Revision: 1 $ + */ +public class HasRolePredicate implements Predicate>, Serializable { + private String role; + + public static HasRolePredicate create() { + return new HasRolePredicate(); + } + + public HasRolePredicate role(String role) { + this.role = role; + return this; + } + + @Override + public boolean test(Map.Entry entry) { + Object value = entry.getValue(); + if (value == null) return false; + if (value instanceof CachedRole) { + CachedRole cachedRole = (CachedRole)value; + if (cachedRole.getComposites().contains(role)) return true; + } + if (value instanceof CachedGroup) { + CachedGroup cachedRole = (CachedGroup)value; + if (cachedRole.getRoleMappings().contains(role)) return true; + } + return false; + } +} diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/InClientPredicate.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/InClientPredicate.java new file mode 100755 index 0000000000..ee5343f841 --- /dev/null +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/InClientPredicate.java @@ -0,0 +1,34 @@ +package org.keycloak.models.cache.infinispan.stream; + +import org.keycloak.models.cache.infinispan.stream.entities.InClient; +import org.keycloak.models.cache.infinispan.stream.entities.InRealm; + +import java.io.Serializable; +import java.util.Map; +import java.util.function.Predicate; + +/** + * @author Bill Burke + * @version $Revision: 1 $ + */ +public class InClientPredicate implements Predicate>, Serializable { + private String clientId; + + public static InClientPredicate create() { + return new InClientPredicate(); + } + + public InClientPredicate client(String id) { + clientId = id; + return this; + } + + @Override + public boolean test(Map.Entry entry) { + Object value = entry.getValue(); + if (value == null) return false; + if (!(value instanceof InClient)) return false; + + return clientId.equals(((InClient)value).getClientId()); + } +} diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/InRealmPredicate.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/InRealmPredicate.java new file mode 100755 index 0000000000..265e4d2655 --- /dev/null +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/InRealmPredicate.java @@ -0,0 +1,33 @@ +package org.keycloak.models.cache.infinispan.stream; + +import org.keycloak.models.cache.infinispan.stream.entities.InRealm; + +import java.io.Serializable; +import java.util.Map; +import java.util.function.Predicate; + +/** + * @author Bill Burke + * @version $Revision: 1 $ + */ +public class InRealmPredicate implements Predicate>, Serializable { + private String realm; + + public static InRealmPredicate create() { + return new InRealmPredicate(); + } + + public InRealmPredicate realm(String id) { + realm = id; + return this; + } + + @Override + public boolean test(Map.Entry entry) { + Object value = entry.getValue(); + if (value == null) return false; + if (!(value instanceof InRealm)) return false; + + return realm.equals(((InRealm)value).getRealm()); + } +} diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/RealmListQuery.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/RealmListQuery.java new file mode 100755 index 0000000000..22a615caf2 --- /dev/null +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/RealmListQuery.java @@ -0,0 +1,29 @@ +package org.keycloak.models.cache.infinispan.stream; + +import org.keycloak.models.cache.infinispan.stream.entities.AbstractRevisioned; + +import java.util.HashSet; +import java.util.Set; + +/** + * @author Bill Burke + * @version $Revision: 1 $ + */ +public class RealmListQuery extends AbstractRevisioned implements RealmQuery { + private final Set realms; + + public RealmListQuery(Long revision, String id, String realm) { + super(revision, id); + realms = new HashSet<>(); + realms.add(realm); + } + public RealmListQuery(Long revision, String id, Set realms) { + super(revision, id); + this.realms = realms; + } + + @Override + public Set getRealms() { + return realms; + } +} \ No newline at end of file diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/RealmQuery.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/RealmQuery.java new file mode 100755 index 0000000000..210978fb15 --- /dev/null +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/RealmQuery.java @@ -0,0 +1,13 @@ +package org.keycloak.models.cache.infinispan.stream; + +import org.keycloak.models.cache.infinispan.stream.entities.InRealm; + +import java.util.Set; + +/** + * @author Bill Burke + * @version $Revision: 1 $ + */ +public interface RealmQuery { + Set getRealms(); +} diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/RealmQueryPredicate.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/RealmQueryPredicate.java new file mode 100755 index 0000000000..179c7da043 --- /dev/null +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/RealmQueryPredicate.java @@ -0,0 +1,37 @@ +package org.keycloak.models.cache.infinispan.stream; + +import java.io.Serializable; +import java.util.Map; +import java.util.function.Predicate; + +/** + * @author Bill Burke + * @version $Revision: 1 $ + */ +public class RealmQueryPredicate implements Predicate>, Serializable { + private String realm; + + public static RealmQueryPredicate create() { + return new RealmQueryPredicate(); + } + + public RealmQueryPredicate realm(String realm) { + this.realm = realm; + return this; + } + + + + + + @Override + public boolean test(Map.Entry entry) { + Object value = entry.getValue(); + if (value == null) return false; + if (!(value instanceof RealmQuery)) return false; + RealmQuery query = (RealmQuery)value; + + + return query.getRealms().contains(realm); + } +} diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/RoleQuery.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/RoleQuery.java new file mode 100755 index 0000000000..0fcb78a98b --- /dev/null +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/RoleQuery.java @@ -0,0 +1,13 @@ +package org.keycloak.models.cache.infinispan.stream; + +import org.keycloak.models.cache.infinispan.stream.entities.InRealm; + +import java.util.Set; + +/** + * @author Bill Burke + * @version $Revision: 1 $ + */ +public interface RoleQuery extends InRealm { + Set getRoles(); +} diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/RoleQueryPredicate.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/RoleQueryPredicate.java new file mode 100755 index 0000000000..3320963d30 --- /dev/null +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/RoleQueryPredicate.java @@ -0,0 +1,37 @@ +package org.keycloak.models.cache.infinispan.stream; + +import java.io.Serializable; +import java.util.Map; +import java.util.function.Predicate; + +/** + * @author Bill Burke + * @version $Revision: 1 $ + */ +public class RoleQueryPredicate implements Predicate>, Serializable { + private String role; + + public static RoleQueryPredicate create() { + return new RoleQueryPredicate(); + } + + public RoleQueryPredicate role(String role) { + this.role = role; + return this; + } + + + + + + @Override + public boolean test(Map.Entry entry) { + Object value = entry.getValue(); + if (value == null) return false; + if (!(value instanceof RoleQuery)) return false; + RoleQuery query = (RoleQuery)value; + + + return query.getRoles().contains(role); + } +} diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/locking/LockingCacheRealmProvider.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/StreamCacheRealmProvider.java similarity index 57% rename from model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/locking/LockingCacheRealmProvider.java rename to model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/StreamCacheRealmProvider.java index 4edb046af5..d68f50c125 100755 --- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/locking/LockingCacheRealmProvider.java +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/StreamCacheRealmProvider.java @@ -15,7 +15,7 @@ * limitations under the License. */ -package org.keycloak.models.cache.infinispan.locking; +package org.keycloak.models.cache.infinispan.stream; import org.jboss.logging.Logger; import org.keycloak.migration.MigrationModel; @@ -28,22 +28,19 @@ import org.keycloak.models.RealmModel; import org.keycloak.models.RealmProvider; import org.keycloak.models.RoleModel; import org.keycloak.models.cache.CacheRealmProvider; -import org.keycloak.models.cache.entities.CachedClient; -import org.keycloak.models.cache.entities.CachedClientTemplate; -import org.keycloak.models.cache.entities.CachedGroup; -import org.keycloak.models.cache.entities.CachedRealm; import org.keycloak.models.cache.entities.CachedRole; import org.keycloak.models.cache.infinispan.ClientAdapter; import org.keycloak.models.cache.infinispan.ClientTemplateAdapter; import org.keycloak.models.cache.infinispan.GroupAdapter; import org.keycloak.models.cache.infinispan.RealmAdapter; import org.keycloak.models.cache.infinispan.RoleAdapter; -import org.keycloak.models.cache.infinispan.locking.entities.RevisionedCachedClient; -import org.keycloak.models.cache.infinispan.locking.entities.RevisionedCachedClientRole; -import org.keycloak.models.cache.infinispan.locking.entities.RevisionedCachedClientTemplate; -import org.keycloak.models.cache.infinispan.locking.entities.RevisionedCachedGroup; -import org.keycloak.models.cache.infinispan.locking.entities.RevisionedCachedRealm; -import org.keycloak.models.cache.infinispan.locking.entities.RevisionedCachedRealmRole; +import org.keycloak.models.cache.infinispan.stream.entities.Revisioned; +import org.keycloak.models.cache.infinispan.stream.entities.RevisionedCachedClient; +import org.keycloak.models.cache.infinispan.stream.entities.RevisionedCachedClientRole; +import org.keycloak.models.cache.infinispan.stream.entities.RevisionedCachedClientTemplate; +import org.keycloak.models.cache.infinispan.stream.entities.RevisionedCachedGroup; +import org.keycloak.models.cache.infinispan.stream.entities.RevisionedCachedRealm; +import org.keycloak.models.cache.infinispan.stream.entities.RevisionedCachedRealmRole; import java.util.Collections; import java.util.HashMap; @@ -55,34 +52,36 @@ import java.util.Set; /** + * + * - any relationship should be resolved from session.realms(). For example if JPA.getClientByClientId() is invoked, + * JPA should find the id of the client and then call session.realms().getClientById(). THis is to ensure that the cached + * object is invoked and all proper invalidation are being invoked. + * * @author Bill Burke * @version $Revision: 1 $ */ -public class LockingCacheRealmProvider implements CacheRealmProvider { - protected static final Logger logger = Logger.getLogger(LockingCacheRealmProvider.class); - protected LockingRealmCache cache; +public class StreamCacheRealmProvider implements CacheRealmProvider { + protected static final Logger logger = Logger.getLogger(StreamCacheRealmProvider.class); + public static final String REALM_CLIENTS_QUERY_SUFFIX = ".realm.clients"; + protected StreamRealmCache cache; protected KeycloakSession session; protected RealmProvider delegate; protected boolean transactionActive; protected boolean setRollbackOnly; - protected Set realmInvalidations = new HashSet<>(); - protected Set appInvalidations = new HashSet<>(); - protected Set clientTemplateInvalidations = new HashSet<>(); - protected Set roleInvalidations = new HashSet<>(); - protected Set groupInvalidations = new HashSet<>(); protected Map managedRealms = new HashMap<>(); protected Map managedApplications = new HashMap<>(); protected Map managedClientTemplates = new HashMap<>(); protected Map managedRoles = new HashMap<>(); protected Map managedGroups = new HashMap<>(); + protected Set clientListInvalidations = new HashSet<>(); + protected Set invalidations = new HashSet<>(); protected boolean clearAll; - public LockingCacheRealmProvider(LockingRealmCache cache, KeycloakSession session) { + public StreamCacheRealmProvider(StreamRealmCache cache, KeycloakSession session) { this.cache = cache; this.session = session; - session.getTransaction().enlistPrepare(getPrepareTransaction()); session.getTransaction().enlistAfterCompletion(getAfterTransaction()); } @@ -105,50 +104,38 @@ public class LockingCacheRealmProvider implements CacheRealmProvider { return delegate; } - public LockingRealmCache getCache() { - return cache; - } - @Override public void registerRealmInvalidation(String id) { - realmInvalidations.add(id); + invalidations.add(id); + cache.realmInvalidation(id, invalidations); } @Override - public void registerApplicationInvalidation(String id) { - appInvalidations.add(id); + public void registerClientInvalidation(String id) { + invalidations.add(id); + cache.clientInvalidation(id, invalidations); } @Override public void registerClientTemplateInvalidation(String id) { - clientTemplateInvalidations.add(id); + invalidations.add(id); + cache.clientTemplateInvalidation(id, invalidations); } @Override public void registerRoleInvalidation(String id) { - roleInvalidations.add(id); + invalidations.add(id); + cache.roleInvalidation(id, invalidations); } @Override public void registerGroupInvalidation(String id) { - groupInvalidations.add(id); - + invalidations.add(id); + cache.groupInvalidation(id, invalidations); } protected void runInvalidations() { - for (String id : realmInvalidations) { - cache.invalidateRealmById(id); - } - for (String id : roleInvalidations) { - cache.invalidateRoleById(id); - } - for (String id : groupInvalidations) { - cache.invalidateGroupById(id); - } - for (String id : appInvalidations) { - cache.invalidateClientById(id); - } - for (String id : clientTemplateInvalidations) { - cache.invalidateClientTemplateById(id); + for (String id : invalidations) { + cache.invalidateObject(id); } } @@ -162,27 +149,14 @@ public class LockingCacheRealmProvider implements CacheRealmProvider { @Override public void commit() { if (delegate == null) return; - List invalidates = new LinkedList<>(); - for (String id : realmInvalidations) { - invalidates.add(id); - } - for (String id : roleInvalidations) { - invalidates.add(id); - } - for (String id : groupInvalidations) { - invalidates.add(id); - } - for (String id : appInvalidations) { - invalidates.add(id); - } - for (String id : clientTemplateInvalidations) { - invalidates.add(id); - } + List locks = new LinkedList<>(); + locks.addAll(invalidations); - Collections.sort(invalidates); // lock ordering + Collections.sort(locks); // lock ordering cache.getRevisions().startBatch(); - for (String id : invalidates) { - cache.getRevisions().getAdvancedCache().lock(id); + //if (!invalidates.isEmpty()) cache.getRevisions().getAdvancedCache().lock(invalidates); + for (String lock : locks) { + boolean success = cache.getRevisions().getAdvancedCache().lock(lock); } } @@ -275,19 +249,18 @@ public class LockingCacheRealmProvider implements CacheRealmProvider { @Override public RealmModel getRealm(String id) { - CachedRealm cached = cache.getRealm(id); + RevisionedCachedRealm cached = cache.get(id, RevisionedCachedRealm.class); if (cached != null) { logger.tracev("by id cache hit: {0}", cached.getName()); } if (cached == null) { Long loaded = cache.getCurrentRevision(id); - if (loaded == null) loaded = UpdateCounter.current(); RealmModel model = getDelegate().getRealm(id); if (model == null) return null; - if (realmInvalidations.contains(id)) return model; - cached = new RevisionedCachedRealm(loaded, cache, this, model); - cache.addRealm(cached); - } else if (realmInvalidations.contains(id)) { + if (invalidations.contains(id)) return model; + cached = new RevisionedCachedRealm(loaded, null, this, model); + cache.addRevisioned(cached); + } else if (invalidations.contains(id)) { return getDelegate().getRealm(id); } else if (managedRealms.containsKey(id)) { return managedRealms.get(id); @@ -299,25 +272,28 @@ public class LockingCacheRealmProvider implements CacheRealmProvider { @Override public RealmModel getRealmByName(String name) { - CachedRealm cached = cache.getRealmByName(name); - if (cached != null) { - logger.tracev("by name cache hit: {0}", cached.getName()); + String cacheKey = "realm.query.by.name." + name; + RealmListQuery query = cache.get(cacheKey, RealmListQuery.class); + if (query != null) { + logger.tracev("realm by name cache hit: {0}", name); } - if (cached == null) { - Long loaded = UpdateCounter.current(); + if (query == null) { + Long loaded = cache.getCurrentRevision(cacheKey); RealmModel model = getDelegate().getRealmByName(name); if (model == null) return null; - if (realmInvalidations.contains(model.getId())) return model; - cached = new RevisionedCachedRealm(loaded, cache, this, model); - cache.addRealm(cached); - } else if (realmInvalidations.contains(cached.getId())) { + if (invalidations.contains(model.getId())) return model; + query = new RealmListQuery(loaded, cacheKey, model.getId()); + cache.addRevisioned(query); + return model; + } else if (invalidations.contains(cacheKey)) { return getDelegate().getRealmByName(name); - } else if (managedRealms.containsKey(cached.getId())) { - return managedRealms.get(cached.getId()); + } else { + String realmId = query.getRealms().iterator().next(); + if (invalidations.contains(realmId)) { + return getDelegate().getRealmByName(name); + } + return getRealm(realmId); } - RealmAdapter adapter = new RealmAdapter(cached, this); - managedRealms.put(cached.getId(), adapter); - return adapter; } @Override @@ -336,42 +312,87 @@ public class LockingCacheRealmProvider implements CacheRealmProvider { @Override public boolean removeRealm(String id) { - cache.invalidateRealmById(id); + if (getRealm(id) == null) return false; - RealmModel realm = getDelegate().getRealm(id); - Set realmRoles = null; - if (realm != null) { - realmRoles = realm.getRoles(); + invalidations.add(getRealmClientsQueryCacheKey(id)); + cache.invalidateObject(id); + cache.realmRemoval(id, invalidations); + return getDelegate().removeRealm(id); + } + + @Override + public ClientModel addClient(RealmModel realm, String clientId) { + ClientModel client = getDelegate().addClient(realm, clientId); + return addedClient(realm, client); + } + + @Override + public ClientModel addClient(RealmModel realm, String id, String clientId) { + ClientModel client = getDelegate().addClient(realm, id, clientId); + return addedClient(realm, client); + } + + private ClientModel addedClient(RealmModel realm, ClientModel client) { + logger.trace("added Client....."); + // need to invalidate realm client query cache every time as it may not be loaded on this node, but loaded on another + invalidations.add(getRealmClientsQueryCacheKey(realm.getId())); + invalidations.add(client.getId()); + cache.clientAdded(realm.getId(), client.getId(), invalidations); + clientListInvalidations.add(realm.getId()); + return client; + } + + private String getRealmClientsQueryCacheKey(String realm) { + return realm + REALM_CLIENTS_QUERY_SUFFIX; + } + + @Override + public List getClients(RealmModel realm) { + String cacheKey = getRealmClientsQueryCacheKey(realm.getId()); + boolean queryDB = invalidations.contains(cacheKey) || clientListInvalidations.contains(realm.getId()); + if (queryDB) { + return getDelegate().getClients(realm); } - boolean didIt = getDelegate().removeRealm(id); - realmInvalidations.add(id); + ClientListQuery query = cache.get(cacheKey, ClientListQuery.class); + if (query != null) { + logger.tracev("getClients cache hit: {0}", realm.getName()); + } - // TODO: Temporary workaround to invalidate cached realm roles - if (didIt && realmRoles != null) { - for (RoleModel role : realmRoles) { - roleInvalidations.add(role.getId()); + if (query == null) { + Long loaded = cache.getCurrentRevision(cacheKey); + List model = getDelegate().getClients(realm); + if (model == null) return null; + Set ids = new HashSet<>(); + for (ClientModel client : model) ids.add(client.getId()); + query = new ClientListQuery(loaded, cacheKey, realm, ids); + logger.tracev("adding realm clients cache miss: realm {0} key {1}", realm.getName(), cacheKey); + cache.addRevisioned(query); + return model; + } + List list = new LinkedList<>(); + for (String id : query.getClients()) { + ClientModel client = session.realms().getClientById(id, realm); + if (client == null) { + invalidations.add(cacheKey); + return getDelegate().getClients(realm); } + list.add(client); } - - return didIt; + return list; } @Override public boolean removeClient(String id, RealmModel realm) { ClientModel client = getClientById(id, realm); if (client == null) return false; - - registerApplicationInvalidation(id); - registerRealmInvalidation(realm.getId()); - cache.invalidateClientById(id); - cache.invalidateRealmById(realm.getId()); - - - - Set roles = client.getRoles(); - for (RoleModel role : roles) { - registerRoleInvalidation(role.getId()); + // need to invalidate realm client query cache every time client list is changed + invalidations.add(getRealmClientsQueryCacheKey(realm.getId())); + clientListInvalidations.add(realm.getId()); + registerClientInvalidation(id); + cache.clientRemoval(realm.getId(), id, invalidations); + for (RoleModel role : client.getRoles()) { + cache.roleInvalidation(role.getId(), invalidations); } return getDelegate().removeClient(id, realm); } @@ -383,51 +404,49 @@ public class LockingCacheRealmProvider implements CacheRealmProvider { @Override public RoleModel getRoleById(String id, RealmModel realm) { - CachedRole cached = cache.getRole(id); + CachedRole cached = cache.get(id, CachedRole.class); if (cached != null && !cached.getRealm().equals(realm.getId())) { cached = null; } if (cached == null) { Long loaded = cache.getCurrentRevision(id); - if (loaded == null) loaded = UpdateCounter.current(); RoleModel model = getDelegate().getRoleById(id, realm); if (model == null) return null; - if (roleInvalidations.contains(id)) return model; + if (invalidations.contains(id)) return model; if (model.getContainer() instanceof ClientModel) { cached = new RevisionedCachedClientRole(loaded, ((ClientModel) model.getContainer()).getId(), model, realm); } else { cached = new RevisionedCachedRealmRole(loaded, model, realm); } - cache.addRole(cached); + cache.addRevisioned((Revisioned)cached); - } else if (roleInvalidations.contains(id)) { + } else if (invalidations.contains(id)) { return getDelegate().getRoleById(id, realm); } else if (managedRoles.containsKey(id)) { return managedRoles.get(id); } - RoleAdapter adapter = new RoleAdapter(cached, cache, this, realm); + RoleAdapter adapter = new RoleAdapter(cached, null, this, realm); managedRoles.put(id, adapter); return adapter; } @Override public GroupModel getGroupById(String id, RealmModel realm) { - CachedGroup cached = cache.getGroup(id); + RevisionedCachedGroup cached = cache.get(id, RevisionedCachedGroup.class); if (cached != null && !cached.getRealm().equals(realm.getId())) { cached = null; } if (cached == null) { Long loaded = cache.getCurrentRevision(id); - if (loaded == null) loaded = UpdateCounter.current(); GroupModel model = getDelegate().getGroupById(id, realm); if (model == null) return null; - if (groupInvalidations.contains(id)) return model; + if (invalidations.contains(id)) return model; cached = new RevisionedCachedGroup(loaded, realm, model); - cache.addGroup(cached); + cache.addRevisioned(cached); - } else if (groupInvalidations.contains(id)) { + } else if (invalidations.contains(id)) { return getDelegate().getGroupById(id, realm); } else if (managedGroups.containsKey(id)) { return managedGroups.get(id); @@ -439,7 +458,7 @@ public class LockingCacheRealmProvider implements CacheRealmProvider { @Override public ClientModel getClientById(String id, RealmModel realm) { - CachedClient cached = cache.getClient(id); + RevisionedCachedClient cached = cache.get(id, RevisionedCachedClient.class); if (cached != null && !cached.getRealm().equals(realm.getId())) { cached = null; } @@ -449,73 +468,72 @@ public class LockingCacheRealmProvider implements CacheRealmProvider { if (cached == null) { Long loaded = cache.getCurrentRevision(id); - if (loaded == null) loaded = UpdateCounter.current(); ClientModel model = getDelegate().getClientById(id, realm); if (model == null) return null; - if (appInvalidations.contains(id)) return model; - cached = new RevisionedCachedClient(loaded, cache, getDelegate(), realm, model); + if (invalidations.contains(id)) return model; + cached = new RevisionedCachedClient(loaded, null, getDelegate(), realm, model); logger.tracev("adding client by id cache miss: {0}", cached.getClientId()); - cache.addClient(cached); - } else if (appInvalidations.contains(id)) { + cache.addRevisioned(cached); + } else if (invalidations.contains(id)) { return getDelegate().getClientById(id, realm); } else if (managedApplications.containsKey(id)) { return managedApplications.get(id); } - ClientAdapter adapter = new ClientAdapter(realm, cached, this, cache); + ClientAdapter adapter = new ClientAdapter(realm, cached, this, null); managedApplications.put(id, adapter); return adapter; } @Override public ClientModel getClientByClientId(String clientId, RealmModel realm) { - CachedClient cached = cache.getClientByClientId(realm, clientId); - if (cached != null && !cached.getRealm().equals(realm.getId())) { - cached = null; - } - if (cached != null) { - logger.tracev("client by name cache hit: {0}", cached.getClientId()); + String cacheKey = realm.getId() + ".client.query.by.clientId." + clientId; + ClientListQuery query = cache.get(cacheKey, ClientListQuery.class); + String id = null; + + if (query != null) { + logger.tracev("client by name cache hit: {0}", clientId); } - if (cached == null) { - Long loaded = UpdateCounter.current(); - if (loaded == null) loaded = UpdateCounter.current(); + if (query == null) { + Long loaded = cache.getCurrentRevision(cacheKey); ClientModel model = getDelegate().getClientByClientId(clientId, realm); if (model == null) return null; - if (appInvalidations.contains(model.getId())) return model; - cached = new RevisionedCachedClient(loaded, cache, getDelegate(), realm, model); - logger.tracev("adding client by name cache miss: {0}", cached.getClientId()); - cache.addClient(cached); - } else if (appInvalidations.contains(cached.getId())) { - return getDelegate().getClientById(cached.getId(), realm); - } else if (managedApplications.containsKey(cached.getId())) { - return managedApplications.get(cached.getId()); + if (invalidations.contains(model.getId())) return model; + id = model.getId(); + query = new ClientListQuery(loaded, cacheKey, realm, id); + logger.tracev("adding client by name cache miss: {0}", clientId); + cache.addRevisioned(query); + } else if (invalidations.contains(cacheKey)) { + return getDelegate().getClientByClientId(clientId, realm); + } else { + id = query.getClients().iterator().next(); + if (invalidations.contains(id)) { + return getDelegate().getClientByClientId(clientId, realm); + } } - ClientAdapter adapter = new ClientAdapter(realm, cached, this, cache); - managedApplications.put(cached.getId(), adapter); - return adapter; + return getClientById(id, realm); } @Override public ClientTemplateModel getClientTemplateById(String id, RealmModel realm) { - CachedClientTemplate cached = cache.getClientTemplate(id); + RevisionedCachedClientTemplate cached = cache.get(id, RevisionedCachedClientTemplate.class); if (cached != null && !cached.getRealm().equals(realm.getId())) { cached = null; } if (cached == null) { Long loaded = cache.getCurrentRevision(id); - if (loaded == null) loaded = UpdateCounter.current(); ClientTemplateModel model = getDelegate().getClientTemplateById(id, realm); if (model == null) return null; - if (clientTemplateInvalidations.contains(id)) return model; - cached = new RevisionedCachedClientTemplate(loaded, cache, getDelegate(), realm, model); - cache.addClientTemplate(cached); - } else if (clientTemplateInvalidations.contains(id)) { + if (invalidations.contains(id)) return model; + cached = new RevisionedCachedClientTemplate(loaded, null, getDelegate(), realm, model); + cache.addRevisioned(cached); + } else if (invalidations.contains(id)) { return getDelegate().getClientTemplateById(id, realm); } else if (managedClientTemplates.containsKey(id)) { return managedClientTemplates.get(id); } - ClientTemplateModel adapter = new ClientTemplateAdapter(realm, cached, this, cache); + ClientTemplateModel adapter = new ClientTemplateAdapter(realm, cached, this, null); managedClientTemplates.put(id, adapter); return adapter; } diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/StreamRealmCache.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/StreamRealmCache.java new file mode 100755 index 0000000000..9dd821bdff --- /dev/null +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/StreamRealmCache.java @@ -0,0 +1,314 @@ +/* + * Copyright 2016 Red Hat, Inc. and/or its affiliates + * and other contributors as indicated by the @author tags. + * + * Licensed 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.keycloak.models.cache.infinispan.stream; + +import org.infinispan.Cache; +import org.infinispan.notifications.Listener; +import org.infinispan.notifications.cachelistener.annotation.CacheEntriesEvicted; +import org.infinispan.notifications.cachelistener.annotation.CacheEntryInvalidated; +import org.infinispan.notifications.cachelistener.event.CacheEntriesEvictedEvent; +import org.infinispan.notifications.cachelistener.event.CacheEntryInvalidatedEvent; +import org.jboss.logging.Logger; +import org.keycloak.models.cache.entities.CachedClient; +import org.keycloak.models.cache.entities.CachedClientTemplate; +import org.keycloak.models.cache.entities.CachedGroup; +import org.keycloak.models.cache.entities.CachedRealm; +import org.keycloak.models.cache.entities.CachedRole; +import org.keycloak.models.cache.infinispan.stream.entities.Revisioned; + +import java.util.HashSet; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; +import java.util.function.Predicate; + +/** + * @author Stian Thorgersen + */ +@Listener +public class StreamRealmCache { + + protected static final Logger logger = Logger.getLogger(StreamRealmCache.class); + + protected final Cache revisions; + protected final Cache cache; + + public StreamRealmCache(Cache cache, Cache revisions) { + this.cache = cache; + this.cache.addListener(this); + this.revisions = revisions; + } + + public Cache getCache() { + return cache; + } + + public Cache getRevisions() { + return revisions; + } + + public Long getCurrentRevision(String id) { + Long revision = revisions.get(id); + if (revision == null) return UpdateCounter.current(); + return revision; + } + + public void endRevisionBatch() { + try { + revisions.endBatch(true); + } catch (Exception e) { + } + + } + + public T get(String id, Class type) { + Revisioned o = (Revisioned)cache.get(id); + if (o == null) { + return null; + } + Long rev = revisions.get(id); + if (rev == null) { + logger.tracev("get() missing rev"); + return null; + } + long oRev = o.getRevision() == null ? -1L : o.getRevision().longValue(); + if (rev > oRev) { + logger.tracev("get() rev: {0} o.rev: {1}", rev.longValue(), oRev); + return null; + } + return o != null && type.isInstance(o) ? type.cast(o) : null; + } + + public Object invalidateObject(String id) { + Revisioned removed = (Revisioned)cache.remove(id); + long next = UpdateCounter.next(); + Object rev = revisions.put(id, next); + return removed; + } + + public void addRevisioned(Revisioned object) { + //startRevisionBatch(); + String id = object.getId(); + try { + //revisions.getAdvancedCache().lock(id); + Long rev = revisions.get(id); + if (rev == null) { + if (id.endsWith("realm.clients")) logger.trace("addRevisioned rev == null realm.clients"); + rev = UpdateCounter.current(); + revisions.put(id, rev); + } + revisions.startBatch(); + if (!revisions.getAdvancedCache().lock(id)) { + logger.trace("Could not obtain version lock"); + } + rev = revisions.get(id); + if (rev == null) { + if (id.endsWith("realm.clients")) logger.trace("addRevisioned rev2 == null realm.clients"); + return; + } + if (rev.equals(object.getRevision())) { + if (id.endsWith("realm.clients")) logger.tracev("adding Object.revision {0} rev {1}", object.getRevision(), rev); + cache.putForExternalRead(id, object); + return; + } + if (rev > object.getRevision()) { // revision is ahead, don't cache + if (id.endsWith("realm.clients")) logger.trace("addRevisioned revision is ahead realm.clients"); + return; + } + // revisions cache has a lower value than the object.revision, so update revision and add it to cache + if (id.endsWith("realm.clients")) logger.tracev("adding Object.revision {0} rev {1}", object.getRevision(), rev); + revisions.put(id, object.getRevision()); + cache.putForExternalRead(id, object); + } finally { + endRevisionBatch(); + } + + } + public void clear() { + cache.clear(); + } + + public void realmInvalidation(String id, Set invalidations) { + Predicate> predicate = getRealmInvalidationPredicate(id); + addInvalidations(predicate, invalidations); + } + + public Predicate> getRealmInvalidationPredicate(String id) { + return RealmQueryPredicate.create().realm(id); + } + + public void clientInvalidation(String id, Set invalidations) { + addInvalidations(getClientInvalidationPredicate(id), invalidations); + } + + public Predicate> getClientInvalidationPredicate(String id) { + return ClientQueryPredicate.create().client(id); + } + + public void roleInvalidation(String id, Set invalidations) { + addInvalidations(getRoleInvalidationPredicate(id), invalidations); + + } + + public Predicate> getRoleInvalidationPredicate(String id) { + return HasRolePredicate.create().role(id); + } + + public void groupInvalidation(String id, Set invalidations) { + addInvalidations(getGroupInvalidationPredicate(id), invalidations); + + } + + public Predicate> getGroupInvalidationPredicate(String id) { + return GroupQueryPredicate.create().group(id); + } + + public void clientTemplateInvalidation(String id, Set invalidations) { + addInvalidations(getClientTemplateInvalidationPredicate(id), invalidations); + + } + + public Predicate> getClientTemplateInvalidationPredicate(String id) { + return ClientTemplateQueryPredicate.create().template(id); + } + + public void realmRemoval(String id, Set invalidations) { + Predicate> predicate = getRealmRemovalPredicate(id); + addInvalidations(predicate, invalidations); + } + + public Predicate> getRealmRemovalPredicate(String id) { + Predicate> predicate = null; + predicate = RealmQueryPredicate.create().realm(id) + .or(InRealmPredicate.create().realm(id)); + return predicate; + } + + public void clientAdded(String realmId, String id, Set invalidations) { + addInvalidations(getClientAddedPredicate(realmId), invalidations); + } + + public Predicate> getClientAddedPredicate(String realmId) { + return ClientQueryPredicate.create().inRealm(realmId); + } + + public void clientRemoval(String realmId, String id, Set invalidations) { + Predicate> predicate = null; + predicate = getClientRemovalPredicate(realmId, id); + addInvalidations(predicate, invalidations); + } + + public Predicate> getClientRemovalPredicate(String realmId, String id) { + Predicate> predicate; + predicate = ClientQueryPredicate.create().inRealm(realmId) + .or(ClientQueryPredicate.create().client(id)) + .or(InClientPredicate.create().client(id)); + return predicate; + } + + public void roleRemoval(String id, Set invalidations) { + addInvalidations(getRoleRemovalPredicate(id), invalidations); + + } + + public Predicate> getRoleRemovalPredicate(String id) { + return getRoleInvalidationPredicate(id); + } + + public void addInvalidations(Predicate> predicate, Set invalidations) { + Iterator> it = getEntryIterator(predicate); + while (it.hasNext()) { + invalidations.add(it.next().getKey()); + } + } + + private Iterator> getEntryIterator(Predicate> predicate) { + return cache + .entrySet() + .stream() + .filter(predicate).iterator(); + } + + @CacheEntryInvalidated + public void cacheInvalidated(CacheEntryInvalidatedEvent event) { + if (event.isPre()) { + Object object = event.getValue(); + if (object != null) { + Predicate> predicate = getInvalidationPredicate(object); + if (predicate != null) runEvictions(predicate); + } + } + } + + @CacheEntriesEvicted + public void cacheEvicted(CacheEntriesEvictedEvent event) { + for (Object object : event.getEntries().values()) { + Predicate> predicate = getEvictionPredicate(object); + if (predicate != null) runEvictions(predicate); + } + } + + public void runEvictions(Predicate> current) { + Set evictions = new HashSet<>(); + addInvalidations(current, evictions); + for (String key : evictions) cache.evict(key); + } + + protected Predicate> getEvictionPredicate(Object object) { + if (object instanceof CachedRealm) { + CachedRealm cached = (CachedRealm)object; + return getRealmInvalidationPredicate(cached.getId()); + } else if (object instanceof CachedClient) { + CachedClient cached = (CachedClient)object; + return getClientInvalidationPredicate(cached.getId()); + } else if (object instanceof CachedRole) { + CachedRole cached = (CachedRole)object; + return getRoleInvalidationPredicate(cached.getId()); + } else if (object instanceof CachedGroup) { + CachedGroup cached = (CachedGroup)object; + return getGroupInvalidationPredicate(cached.getId()); + } else if (object instanceof CachedClientTemplate) { + CachedClientTemplate cached = (CachedClientTemplate)object; + return getClientTemplateInvalidationPredicate(cached.getId()); + } + return null; + } + protected Predicate> getInvalidationPredicate(Object object) { + if (object instanceof CachedRealm) { + CachedRealm cached = (CachedRealm)object; + return getRealmRemovalPredicate(cached.getId()); + } else if (object instanceof CachedClient) { + CachedClient cached = (CachedClient)object; + Predicate> predicate = getClientRemovalPredicate(cached.getRealm(), cached.getId()); + for (String roleId : cached.getRoles().values()) { + predicate.or(getRoleRemovalPredicate(roleId)); + } + return predicate; + } else if (object instanceof CachedRole) { + CachedRole cached = (CachedRole)object; + return getRoleRemovalPredicate(cached.getId()); + } else if (object instanceof CachedGroup) { + CachedGroup cached = (CachedGroup)object; + return getGroupInvalidationPredicate(cached.getId()); + } else if (object instanceof CachedClientTemplate) { + CachedClientTemplate cached = (CachedClientTemplate)object; + return getClientTemplateInvalidationPredicate(cached.getId()); + } + return null; + } +} diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/locking/UpdateCounter.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/UpdateCounter.java similarity index 87% rename from model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/locking/UpdateCounter.java rename to model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/UpdateCounter.java index 8e8b5c5ba8..ea086415c9 100755 --- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/locking/UpdateCounter.java +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/UpdateCounter.java @@ -1,4 +1,4 @@ -package org.keycloak.models.cache.infinispan.locking; +package org.keycloak.models.cache.infinispan.stream; import java.util.concurrent.atomic.AtomicLong; diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/entities/AbstractRevisioned.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/entities/AbstractRevisioned.java new file mode 100755 index 0000000000..dfea429fe9 --- /dev/null +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/entities/AbstractRevisioned.java @@ -0,0 +1,31 @@ +package org.keycloak.models.cache.infinispan.stream.entities; + +/** + * @author Bill Burke + * @version $Revision: 1 $ + */ +public class AbstractRevisioned implements Revisioned { + private String id; + private Long revision; + + public AbstractRevisioned(Long revision, String id) { + this.revision = revision; + this.id = id; + } + + @Override + public String getId() { + return id; + } + + @Override + public Long getRevision() { + return revision; + } + + @Override + public void setRevision(Long revision) { + this.revision = revision; + } + +} diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/entities/InClient.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/entities/InClient.java new file mode 100755 index 0000000000..3951c7f5c2 --- /dev/null +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/entities/InClient.java @@ -0,0 +1,9 @@ +package org.keycloak.models.cache.infinispan.stream.entities; + +/** + * @author Bill Burke + * @version $Revision: 1 $ + */ +public interface InClient extends InRealm { + String getClientId(); +} diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/entities/InRealm.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/entities/InRealm.java new file mode 100755 index 0000000000..6b550911aa --- /dev/null +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/entities/InRealm.java @@ -0,0 +1,9 @@ +package org.keycloak.models.cache.infinispan.stream.entities; + +/** + * @author Bill Burke + * @version $Revision: 1 $ + */ +public interface InRealm extends Revisioned { + String getRealm(); +} diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/locking/Revisioned.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/entities/Revisioned.java similarity index 70% rename from model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/locking/Revisioned.java rename to model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/entities/Revisioned.java index 7af8d0f073..c0b136f78e 100755 --- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/locking/Revisioned.java +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/entities/Revisioned.java @@ -1,10 +1,11 @@ -package org.keycloak.models.cache.infinispan.locking; +package org.keycloak.models.cache.infinispan.stream.entities; /** * @author Bill Burke * @version $Revision: 1 $ */ public interface Revisioned { + String getId(); Long getRevision(); void setRevision(Long revision); } diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/locking/entities/RevisionedCachedClient.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/entities/RevisionedCachedClient.java similarity index 88% rename from model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/locking/entities/RevisionedCachedClient.java rename to model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/entities/RevisionedCachedClient.java index 4feeffae2f..f2ee892809 100755 --- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/locking/entities/RevisionedCachedClient.java +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/entities/RevisionedCachedClient.java @@ -1,4 +1,4 @@ -package org.keycloak.models.cache.infinispan.locking.entities; +package org.keycloak.models.cache.infinispan.stream.entities; import org.keycloak.models.ClientModel; import org.keycloak.models.RealmModel; @@ -6,13 +6,12 @@ import org.keycloak.models.RealmProvider; import org.keycloak.models.RoleModel; import org.keycloak.models.cache.RealmCache; import org.keycloak.models.cache.entities.CachedClient; -import org.keycloak.models.cache.infinispan.locking.Revisioned; /** * @author Bill Burke * @version $Revision: 1 $ */ -public class RevisionedCachedClient extends CachedClient implements Revisioned { +public class RevisionedCachedClient extends CachedClient implements Revisioned, InRealm { public RevisionedCachedClient(Long revision, RealmCache cache, RealmProvider delegate, RealmModel realm, ClientModel model) { super(cache, delegate, realm, model); diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/locking/entities/RevisionedCachedClientRole.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/entities/RevisionedCachedClientRole.java similarity index 82% rename from model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/locking/entities/RevisionedCachedClientRole.java rename to model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/entities/RevisionedCachedClientRole.java index c3554f64ae..bad2ffec37 100755 --- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/locking/entities/RevisionedCachedClientRole.java +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/entities/RevisionedCachedClientRole.java @@ -1,15 +1,14 @@ -package org.keycloak.models.cache.infinispan.locking.entities; +package org.keycloak.models.cache.infinispan.stream.entities; import org.keycloak.models.RealmModel; import org.keycloak.models.RoleModel; import org.keycloak.models.cache.entities.CachedClientRole; -import org.keycloak.models.cache.infinispan.locking.Revisioned; /** * @author Bill Burke * @version $Revision: 1 $ */ -public class RevisionedCachedClientRole extends CachedClientRole implements Revisioned { +public class RevisionedCachedClientRole extends CachedClientRole implements Revisioned, InClient { public RevisionedCachedClientRole(Long revision, String idClient, RoleModel model, RealmModel realm) { super(idClient, model, realm); diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/locking/entities/RevisionedCachedClientTemplate.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/entities/RevisionedCachedClientTemplate.java similarity index 84% rename from model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/locking/entities/RevisionedCachedClientTemplate.java rename to model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/entities/RevisionedCachedClientTemplate.java index 44720d3385..ad3ac44e1d 100755 --- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/locking/entities/RevisionedCachedClientTemplate.java +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/entities/RevisionedCachedClientTemplate.java @@ -1,17 +1,16 @@ -package org.keycloak.models.cache.infinispan.locking.entities; +package org.keycloak.models.cache.infinispan.stream.entities; import org.keycloak.models.ClientTemplateModel; import org.keycloak.models.RealmModel; import org.keycloak.models.RealmProvider; import org.keycloak.models.cache.RealmCache; import org.keycloak.models.cache.entities.CachedClientTemplate; -import org.keycloak.models.cache.infinispan.locking.Revisioned; /** * @author Bill Burke * @version $Revision: 1 $ */ -public class RevisionedCachedClientTemplate extends CachedClientTemplate implements Revisioned { +public class RevisionedCachedClientTemplate extends CachedClientTemplate implements Revisioned, InRealm { public RevisionedCachedClientTemplate(Long revision, RealmCache cache, RealmProvider delegate, RealmModel realm, ClientTemplateModel model) { super(cache, delegate, realm, model); diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/locking/entities/RevisionedCachedGroup.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/entities/RevisionedCachedGroup.java similarity index 82% rename from model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/locking/entities/RevisionedCachedGroup.java rename to model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/entities/RevisionedCachedGroup.java index 09c7f0f659..98ba32f20e 100755 --- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/locking/entities/RevisionedCachedGroup.java +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/entities/RevisionedCachedGroup.java @@ -1,15 +1,14 @@ -package org.keycloak.models.cache.infinispan.locking.entities; +package org.keycloak.models.cache.infinispan.stream.entities; import org.keycloak.models.GroupModel; import org.keycloak.models.RealmModel; import org.keycloak.models.cache.entities.CachedGroup; -import org.keycloak.models.cache.infinispan.locking.Revisioned; /** * @author Bill Burke * @version $Revision: 1 $ */ -public class RevisionedCachedGroup extends CachedGroup implements Revisioned { +public class RevisionedCachedGroup extends CachedGroup implements Revisioned, InRealm { public RevisionedCachedGroup(Long revision, RealmModel realm, GroupModel group) { super(realm, group); this.revision = revision; diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/locking/entities/RevisionedCachedRealm.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/entities/RevisionedCachedRealm.java similarity index 92% rename from model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/locking/entities/RevisionedCachedRealm.java rename to model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/entities/RevisionedCachedRealm.java index c4fd4870dd..c1f91ac1f5 100755 --- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/locking/entities/RevisionedCachedRealm.java +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/entities/RevisionedCachedRealm.java @@ -1,4 +1,4 @@ -package org.keycloak.models.cache.infinispan.locking.entities; +package org.keycloak.models.cache.infinispan.stream.entities; import org.keycloak.models.ClientModel; import org.keycloak.models.ClientTemplateModel; @@ -7,7 +7,6 @@ import org.keycloak.models.RealmProvider; import org.keycloak.models.RoleModel; import org.keycloak.models.cache.RealmCache; import org.keycloak.models.cache.entities.CachedRealm; -import org.keycloak.models.cache.infinispan.locking.Revisioned; /** * @author Bill Burke diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/locking/entities/RevisionedCachedRealmRole.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/entities/RevisionedCachedRealmRole.java similarity index 81% rename from model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/locking/entities/RevisionedCachedRealmRole.java rename to model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/entities/RevisionedCachedRealmRole.java index 3899bd8b58..6685a3ea74 100755 --- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/locking/entities/RevisionedCachedRealmRole.java +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/entities/RevisionedCachedRealmRole.java @@ -1,15 +1,14 @@ -package org.keycloak.models.cache.infinispan.locking.entities; +package org.keycloak.models.cache.infinispan.stream.entities; import org.keycloak.models.RealmModel; import org.keycloak.models.RoleModel; import org.keycloak.models.cache.entities.CachedRealmRole; -import org.keycloak.models.cache.infinispan.locking.Revisioned; /** * @author Bill Burke * @version $Revision: 1 $ */ -public class RevisionedCachedRealmRole extends CachedRealmRole implements Revisioned { +public class RevisionedCachedRealmRole extends CachedRealmRole implements Revisioned, InRealm { public RevisionedCachedRealmRole(Long revision, RoleModel model, RealmModel realm) { super(model, realm); diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/locking/entities/RevisionedCachedUser.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/entities/RevisionedCachedUser.java similarity index 82% rename from model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/locking/entities/RevisionedCachedUser.java rename to model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/entities/RevisionedCachedUser.java index c276a371e6..e6135e9bd7 100755 --- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/locking/entities/RevisionedCachedUser.java +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/entities/RevisionedCachedUser.java @@ -1,15 +1,14 @@ -package org.keycloak.models.cache.infinispan.locking.entities; +package org.keycloak.models.cache.infinispan.stream.entities; import org.keycloak.models.RealmModel; import org.keycloak.models.UserModel; import org.keycloak.models.cache.entities.CachedUser; -import org.keycloak.models.cache.infinispan.locking.Revisioned; /** * @author Bill Burke * @version $Revision: 1 $ */ -public class RevisionedCachedUser extends CachedUser implements Revisioned { +public class RevisionedCachedUser extends CachedUser implements Revisioned, InRealm { public RevisionedCachedUser(Long revision, RealmModel realm, UserModel user) { super(realm, user); this.revision = revision; diff --git a/model/infinispan/src/main/resources/META-INF/services/org.keycloak.connections.infinispan.InfinispanConnectionProviderFactory b/model/infinispan/src/main/resources/META-INF/services/org.keycloak.connections.infinispan.InfinispanConnectionProviderFactory index 299da00ff3..1fe494543e 100755 --- a/model/infinispan/src/main/resources/META-INF/services/org.keycloak.connections.infinispan.InfinispanConnectionProviderFactory +++ b/model/infinispan/src/main/resources/META-INF/services/org.keycloak.connections.infinispan.InfinispanConnectionProviderFactory @@ -16,4 +16,3 @@ # org.keycloak.connections.infinispan.DefaultInfinispanConnectionProviderFactory -org.keycloak.models.cache.infinispan.locking.LockingConnectionProviderFactory \ No newline at end of file diff --git a/model/infinispan/src/main/resources/META-INF/services/org.keycloak.models.cache.CacheRealmProviderFactory b/model/infinispan/src/main/resources/META-INF/services/org.keycloak.models.cache.CacheRealmProviderFactory index 40ced18500..a2b04e7002 100755 --- a/model/infinispan/src/main/resources/META-INF/services/org.keycloak.models.cache.CacheRealmProviderFactory +++ b/model/infinispan/src/main/resources/META-INF/services/org.keycloak.models.cache.CacheRealmProviderFactory @@ -16,4 +16,3 @@ # org.keycloak.models.cache.infinispan.InfinispanCacheRealmProviderFactory -org.keycloak.models.cache.infinispan.locking.LockingCacheRealmProviderFactory \ No newline at end of file diff --git a/model/infinispan/src/test/java/org/keycloak/models/sessions/infinispan/initializer/ClusteredCacheBehaviorTest.java b/model/infinispan/src/test/java/org/keycloak/models/sessions/infinispan/initializer/ClusteredCacheBehaviorTest.java new file mode 100755 index 0000000000..e83a8b1116 --- /dev/null +++ b/model/infinispan/src/test/java/org/keycloak/models/sessions/infinispan/initializer/ClusteredCacheBehaviorTest.java @@ -0,0 +1,117 @@ +package org.keycloak.models.sessions.infinispan.initializer; + +import org.infinispan.Cache; +import org.infinispan.configuration.cache.CacheMode; +import org.infinispan.configuration.cache.Configuration; +import org.infinispan.configuration.cache.ConfigurationBuilder; +import org.infinispan.configuration.global.GlobalConfigurationBuilder; +import org.infinispan.manager.DefaultCacheManager; +import org.infinispan.manager.EmbeddedCacheManager; +import org.infinispan.notifications.Listener; +import org.infinispan.notifications.cachelistener.annotation.CacheEntriesEvicted; +import org.infinispan.notifications.cachelistener.annotation.CacheEntryInvalidated; +import org.infinispan.notifications.cachelistener.annotation.CacheEntryRemoved; +import org.infinispan.notifications.cachelistener.event.CacheEntriesEvictedEvent; +import org.infinispan.notifications.cachelistener.event.CacheEntryInvalidatedEvent; +import org.infinispan.notifications.cachelistener.event.CacheEntryRemovedEvent; +import org.junit.Ignore; +import org.junit.Test; +import org.keycloak.connections.infinispan.InfinispanConnectionProvider; + +/** + * Just a simple test to see how distributed caches work + * + * @author Bill Burke + * @version $Revision: 1 $ + */ +@Ignore +public class ClusteredCacheBehaviorTest { + public EmbeddedCacheManager createManager() { + GlobalConfigurationBuilder gcb = new GlobalConfigurationBuilder(); + + boolean clustered = true; + boolean async = false; + boolean allowDuplicateJMXDomains = true; + + if (clustered) { + gcb.transport().defaultTransport(); + } + gcb.globalJmxStatistics().allowDuplicateDomains(allowDuplicateJMXDomains); + + EmbeddedCacheManager cacheManager = new DefaultCacheManager(gcb.build()); + + + ConfigurationBuilder invalidationConfigBuilder = new ConfigurationBuilder(); + if (clustered) { + invalidationConfigBuilder.clustering().cacheMode(async ? CacheMode.INVALIDATION_ASYNC : CacheMode.INVALIDATION_SYNC); + } + Configuration invalidationCacheConfiguration = invalidationConfigBuilder.build(); + + cacheManager.defineConfiguration(InfinispanConnectionProvider.REALM_CACHE_NAME, invalidationCacheConfiguration); + return cacheManager; + + } + + @Listener + public static class CacheListener { + String name; + + public CacheListener(String name) { + this.name = name; + } + + + + @CacheEntryRemoved + public void removed(CacheEntryRemovedEvent event) { + if (event.isPre()) { + System.out.println("Listener '" + name + "' entry removed"); + } + } + + @CacheEntryInvalidated + public void removed(CacheEntryInvalidatedEvent event) { + if (event.isPre()) { + System.out.println("Listener '" + name + "' entry invalidated"); + + } + } + + @CacheEntriesEvicted + public void evicted(CacheEntriesEvictedEvent event) { + System.out.println("Listener '" + name + "' entry evicted"); + + } + + } + + @Test + public void testListener() throws Exception { + EmbeddedCacheManager node1 = createManager(); + EmbeddedCacheManager node2 = createManager(); + Cache node1Cache = node1.getCache(InfinispanConnectionProvider.REALM_CACHE_NAME); + node1Cache.addListener(new CacheListener("node1")); + Cache node2Cache = node2.getCache(InfinispanConnectionProvider.REALM_CACHE_NAME); + node2Cache.addListener(new CacheListener("node2")); + + System.out.println("node1 create entry"); + node1Cache.put("key", "node1"); + System.out.println("node2 create entry"); + node2Cache.put("key", "node2"); + System.out.println("node1 remove entry"); + node1Cache.remove("key"); + System.out.println("node2 remove entry"); + node2Cache.remove("key"); + System.out.println("node2 put entry"); + node2Cache.put("key", "node2"); + System.out.println("node2 evict entry"); + node2Cache.evict("key"); + System.out.println("node1/node2 putExternal entry"); + node1Cache.putForExternalRead("key", "common"); + node2Cache.putForExternalRead("key", "common"); + System.out.println("node2 remove entry"); + node2Cache.remove("key"); + + + } +} diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/ClientAdapter.java b/model/jpa/src/main/java/org/keycloak/models/jpa/ClientAdapter.java index 311540b5c9..8affd11629 100755 --- a/model/jpa/src/main/java/org/keycloak/models/jpa/ClientAdapter.java +++ b/model/jpa/src/main/java/org/keycloak/models/jpa/ClientAdapter.java @@ -612,12 +612,12 @@ public class ClientAdapter implements ClientModel { @Override public RoleModel getRole(String name) { - TypedQuery query = em.createNamedQuery("getClientRoleByName", RoleEntity.class); + TypedQuery query = em.createNamedQuery("getClientRoleIdByName", String.class); query.setParameter("name", name); - query.setParameter("client", entity); - List roles = query.getResultList(); + query.setParameter("client", entity.getId()); + List roles = query.getResultList(); if (roles.size() == 0) return null; - return new RoleAdapter(realm, em, roles.get(0)); + return session.realms().getRoleById(roles.get(0), realm); } @Override @@ -636,7 +636,7 @@ public class ClientAdapter implements ClientModel { entity.getRoles().add(roleEntity); em.persist(roleEntity); em.flush(); - return new RoleAdapter(realm, em, roleEntity); + return new RoleAdapter(session, realm, em, roleEntity); } @Override @@ -667,19 +667,21 @@ public class ClientAdapter implements ClientModel { @Override public Set getRoles() { Set list = new HashSet(); - /* - Collection roles = entity.getRoles(); - if (roles == null) return list; - for (RoleEntity entity : roles) { - list.add(new RoleAdapter(realm, em, entity)); - } - */ TypedQuery query = em.createNamedQuery("getClientRoles", RoleEntity.class); query.setParameter("client", entity); List roles = query.getResultList(); for (RoleEntity roleEntity : roles) { - list.add(new RoleAdapter(realm, em, roleEntity)); + list.add(new RoleAdapter(session, realm, em, roleEntity)); } + + /* + TypedQuery query = em.createNamedQuery("getClientRoleIds", String.class); + query.setParameter("client", entity.getId()); + List roles = query.getResultList(); + for (String id : roles) { + list.add(session.realms().getRoleById(id, realm)); + } + */ return list; } diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/JpaRealmProvider.java b/model/jpa/src/main/java/org/keycloak/models/jpa/JpaRealmProvider.java index ce245de661..6c2ae6b84c 100755 --- a/model/jpa/src/main/java/org/keycloak/models/jpa/JpaRealmProvider.java +++ b/model/jpa/src/main/java/org/keycloak/models/jpa/JpaRealmProvider.java @@ -36,6 +36,7 @@ import org.keycloak.models.utils.KeycloakModelUtils; import javax.persistence.EntityManager; import javax.persistence.TypedQuery; import java.util.ArrayList; +import java.util.Collections; import java.util.LinkedList; import java.util.List; @@ -90,25 +91,27 @@ public class JpaRealmProvider implements RealmProvider { @Override public List getRealms() { - TypedQuery query = em.createNamedQuery("getAllRealms", RealmEntity.class); - List entities = query.getResultList(); + TypedQuery query = em.createNamedQuery("getAllRealmIds", String.class); + List entities = query.getResultList(); List realms = new ArrayList(); - for (RealmEntity entity : entities) { - realms.add(new RealmAdapter(session, em, entity)); + for (String id : entities) { + RealmModel realm = session.realms().getRealm(id); + if (realm != null) realms.add(realm); + } return realms; } @Override public RealmModel getRealmByName(String name) { - TypedQuery query = em.createNamedQuery("getRealmByName", RealmEntity.class); + TypedQuery query = em.createNamedQuery("getRealmIdByName", String.class); query.setParameter("name", name); - List entities = query.getResultList(); + List entities = query.getResultList(); if (entities.size() == 0) return null; if (entities.size() > 1) throw new IllegalStateException("Should not be more than one realm with same name"); - RealmEntity realm = query.getResultList().get(0); - if (realm == null) return null; - return new RealmAdapter(session, em, realm); + String id = query.getResultList().get(0); + + return session.realms().getRealm(id); } @Override @@ -126,11 +129,11 @@ public class JpaRealmProvider implements RealmProvider { num = em.createNamedQuery("deleteGroupsByRealm") .setParameter("realm", realm).executeUpdate(); - TypedQuery query = em.createNamedQuery("getClientsByRealm", ClientEntity.class); - query.setParameter("realm", realm); - List clients = query.getResultList(); - for (ClientEntity a : clients) { - adapter.removeClient(a.getId()); + TypedQuery query = em.createNamedQuery("getClientIdsByRealm", String.class); + query.setParameter("realm", realm.getId()); + List clients = query.getResultList(); + for (String client : clients) { + session.realms().removeClient(client, adapter); } /* for (ClientEntity a : new LinkedList<>(realm.getClients())) { @@ -145,11 +148,6 @@ public class JpaRealmProvider implements RealmProvider { em.flush(); em.clear(); - realm = em.find(RealmEntity.class, id); - if (realm != null) { - logger.error("WTF is the realm still there after a removal????????"); - } - return true; } @@ -162,7 +160,7 @@ public class JpaRealmProvider implements RealmProvider { RoleEntity entity = em.find(RoleEntity.class, id); if (entity == null) return null; if (!realm.getId().equals(entity.getRealmId())) return null; - return new RoleAdapter(realm, em, entity); + return new RoleAdapter(session, realm, em, entity); } @Override @@ -173,6 +171,52 @@ public class JpaRealmProvider implements RealmProvider { return new GroupAdapter(realm, em, groupEntity); } + @Override + public ClientModel addClient(RealmModel realm, String clientId) { + return addClient(realm, KeycloakModelUtils.generateId(), clientId); + } + + @Override + public ClientModel addClient(RealmModel realm, String id, String clientId) { + if (clientId == null) { + clientId = id; + } + ClientEntity entity = new ClientEntity(); + entity.setId(id); + entity.setClientId(clientId); + entity.setEnabled(true); + entity.setStandardFlowEnabled(true); + RealmEntity realmRef = em.getReference(RealmEntity.class, realm.getId()); + entity.setRealm(realmRef); + em.persist(entity); + em.flush(); + final ClientModel resource = new ClientAdapter(realm, em, session, entity); + em.flush(); + session.getKeycloakSessionFactory().publish(new RealmModel.ClientCreationEvent() { + @Override + public ClientModel getCreatedClient() { + return resource; + } + }); + return resource; + } + + @Override + public List getClients(RealmModel realm) { + TypedQuery query = em.createNamedQuery("getClientIdsByRealm", String.class); + query.setParameter("realm", realm.getId()); + List clients = query.getResultList(); + if (clients.isEmpty()) return Collections.EMPTY_LIST; + List list = new LinkedList<>(); + for (String id : clients) { + ClientModel client = session.realms().getClientById(id, realm); + if (client != null) list.add(client); + } + return Collections.unmodifiableList(list); + + } + + @Override public ClientModel getClientById(String id, RealmModel realm) { ClientEntity app = em.find(ClientEntity.class, id); @@ -184,13 +228,13 @@ public class JpaRealmProvider implements RealmProvider { @Override public ClientModel getClientByClientId(String clientId, RealmModel realm) { - TypedQuery query = em.createNamedQuery("findClientByClientId", ClientEntity.class); + TypedQuery query = em.createNamedQuery("findClientIdByClientId", String.class); query.setParameter("clientId", clientId); query.setParameter("realm", realm.getId()); - List results = query.getResultList(); + List results = query.getResultList(); if (results.isEmpty()) return null; - ClientEntity entity = results.get(0); - return new ClientAdapter(realm, em, session, entity); + String id = results.get(0); + return session.realms().getClientById(id, realm); } @Override diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/RealmAdapter.java b/model/jpa/src/main/java/org/keycloak/models/jpa/RealmAdapter.java index 65d3b1b854..ad2024b940 100755 --- a/model/jpa/src/main/java/org/keycloak/models/jpa/RealmAdapter.java +++ b/model/jpa/src/main/java/org/keycloak/models/jpa/RealmAdapter.java @@ -723,45 +723,17 @@ public class RealmAdapter implements RealmModel { @Override public List getClients() { - TypedQuery query = em.createNamedQuery("getClientsByRealm", ClientEntity.class); - query.setParameter("realm", realm); - List clients = query.getResultList(); - if (clients.isEmpty()) return Collections.EMPTY_LIST; - List list = new LinkedList<>(); - for (ClientEntity entity : clients) { - list.add(new ClientAdapter(this, em, session, entity)); - } - return Collections.unmodifiableList(list); + return session.realms().getClients(this); } @Override public ClientModel addClient(String name) { - return this.addClient(KeycloakModelUtils.generateId(), name); + return session.realms().addClient(this, name); } @Override public ClientModel addClient(String id, String clientId) { - if (clientId == null) { - clientId = id; - } - ClientEntity entity = new ClientEntity(); - entity.setId(id); - entity.setClientId(clientId); - entity.setEnabled(true); - entity.setStandardFlowEnabled(true); - entity.setRealm(realm); - realm.getClients().add(entity); - em.persist(entity); - em.flush(); - final ClientModel resource = new ClientAdapter(this, em, session, entity); - em.flush(); - session.getKeycloakSessionFactory().publish(new ClientCreationEvent() { - @Override - public ClientModel getCreatedClient() { - return resource; - } - }); - return resource; + return session.realms().addClient(this, id, clientId); } @Override @@ -956,7 +928,7 @@ public class RealmAdapter implements RealmModel { em.remove(entity); } - List add = new LinkedList(); + List add = new LinkedList<>(); for (UserFederationProviderModel model : providers) { boolean found = false; for (UserFederationProviderEntity entity : realm.getUserFederationProviders()) { @@ -1008,12 +980,12 @@ public class RealmAdapter implements RealmModel { @Override public RoleModel getRole(String name) { - TypedQuery query = em.createNamedQuery("getRealmRoleByName", RoleEntity.class); + TypedQuery query = em.createNamedQuery("getRealmRoleIdByName", String.class); query.setParameter("name", name); - query.setParameter("realm", realm); - List roles = query.getResultList(); + query.setParameter("realm", realm.getId()); + List roles = query.getResultList(); if (roles.size() == 0) return null; - return new RoleAdapter(this, em, roles.get(0)); + return session.realms().getRoleById(roles.get(0), this); } @Override @@ -1031,7 +1003,7 @@ public class RealmAdapter implements RealmModel { realm.getRoles().add(entity); em.persist(entity); em.flush(); - return new RoleAdapter(this, em, entity); + return new RoleAdapter(session, this, em, entity); } @Override @@ -1063,7 +1035,9 @@ public class RealmAdapter implements RealmModel { if (roles == null) return Collections.EMPTY_SET; Set list = new HashSet(); for (RoleEntity entity : roles) { - list.add(new RoleAdapter(this, em, entity)); + list.add(new RoleAdapter(session, this, em, entity)); + // can't get it from cache cuz of stack overflow + // list.add(session.realms().getRoleById(entity.getId(), this)); } return Collections.unmodifiableSet(list); } @@ -1259,9 +1233,14 @@ public class RealmAdapter implements RealmModel { if (masterAdminClient == null) { return null; } - - RealmAdapter masterRealm = new RealmAdapter(session, em, masterAdminClient.getRealm()); - return new ClientAdapter(masterRealm, em, session, masterAdminClient); + RealmModel masterRealm = null; + String masterAdminClientRealmId = masterAdminClient.getRealm().getId(); + if (masterAdminClientRealmId.equals(getId())) { + masterRealm = this; + } else { + masterRealm = session.realms().getRealm(masterAdminClientRealmId); + } + return session.realms().getClientById(masterAdminClient.getId(), masterRealm); } @Override @@ -2052,11 +2031,12 @@ public class RealmAdapter implements RealmModel { @Override public List getGroups() { - List groups = em.createNamedQuery("getAllGroupsByRealm").setParameter("realm", realm).getResultList(); + List groups = em.createNamedQuery("getAllGroupIdsByRealm", String.class) + .setParameter("realm", realm.getId()).getResultList(); if (groups == null) return Collections.EMPTY_LIST; List list = new LinkedList<>(); - for (GroupEntity entity : groups) { - list.add(new GroupAdapter(this, em, entity)); + for (String id : groups) { + list.add(session.realms().getGroupById(id, this)); } return Collections.unmodifiableList(list); } @@ -2128,7 +2108,7 @@ public class RealmAdapter implements RealmModel { if (entities == null || entities.isEmpty()) return Collections.EMPTY_LIST; List list = new LinkedList<>(); for (ClientTemplateEntity entity : entities) { - list.add(new ClientTemplateAdapter(this, em, session, entity)); + list.add(session.realms().getClientTemplateById(entity.getId(), this)); } return Collections.unmodifiableList(list); } diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/RoleAdapter.java b/model/jpa/src/main/java/org/keycloak/models/jpa/RoleAdapter.java index 21103d7a37..0ac1be9e8d 100755 --- a/model/jpa/src/main/java/org/keycloak/models/jpa/RoleAdapter.java +++ b/model/jpa/src/main/java/org/keycloak/models/jpa/RoleAdapter.java @@ -17,6 +17,7 @@ package org.keycloak.models.jpa; +import org.keycloak.models.KeycloakSession; import org.keycloak.models.RealmModel; import org.keycloak.models.RoleContainerModel; import org.keycloak.models.RoleModel; @@ -36,11 +37,13 @@ public class RoleAdapter implements RoleModel { protected RoleEntity role; protected EntityManager em; protected RealmModel realm; + protected KeycloakSession session; - public RoleAdapter(RealmModel realm, EntityManager em, RoleEntity role) { + public RoleAdapter(KeycloakSession session, RealmModel realm, EntityManager em, RoleEntity role) { this.em = em; this.realm = realm; this.role = role; + this.session = session; } public RoleEntity getRole() { @@ -115,7 +118,10 @@ public class RoleAdapter implements RoleModel { Set set = new HashSet(); for (RoleEntity composite : getRole().getCompositeRoles()) { - set.add(new RoleAdapter(realm, em, composite)); + set.add(new RoleAdapter(session, realm, em, composite)); + + // todo I want to do this, but can't as you get stack overflow + // set.add(session.realms().getRoleById(composite.getId(), realm)); } return set; } diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/ClientEntity.java b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/ClientEntity.java index 5466a7773f..fd4e0a5323 100755 --- a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/ClientEntity.java +++ b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/ClientEntity.java @@ -50,6 +50,7 @@ import java.util.Set; @Table(name="CLIENT", uniqueConstraints = {@UniqueConstraint(columnNames = {"REALM_ID", "CLIENT_ID"})}) @NamedQueries({ @NamedQuery(name="getClientsByRealm", query="select client from ClientEntity client where client.realm = :realm"), + @NamedQuery(name="getClientIdsByRealm", query="select client.id from ClientEntity client where client.realm.id = :realm"), @NamedQuery(name="findClientIdByClientId", query="select client.id from ClientEntity client where client.clientId = :clientId and client.realm.id = :realm"), @NamedQuery(name="findClientByClientId", query="select client from ClientEntity client where client.clientId = :clientId and client.realm.id = :realm"), }) diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/GroupEntity.java b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/GroupEntity.java index 9eadbc8990..0b89c87496 100755 --- a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/GroupEntity.java +++ b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/GroupEntity.java @@ -39,6 +39,7 @@ import java.util.Collection; */ @NamedQueries({ @NamedQuery(name="getAllGroupsByRealm", query="select u from GroupEntity u where u.realm = :realm order by u.name"), + @NamedQuery(name="getAllGroupIdsByRealm", query="select u.id from GroupEntity u where u.realm.id = :realm order by u.name"), @NamedQuery(name="getGroupById", query="select u from GroupEntity u where u.id = :id and u.realm = :realm"), @NamedQuery(name="getGroupIdsByParent", query="select u.id from GroupEntity u where u.parent = :parent"), @NamedQuery(name="getGroupCount", query="select count(u) from GroupEntity u where u.realm = :realm"), diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/RealmEntity.java b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/RealmEntity.java index 684d102b2b..f33aa211ce 100755 --- a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/RealmEntity.java +++ b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/RealmEntity.java @@ -49,8 +49,8 @@ import java.util.Set; @Table(name="REALM") @Entity @NamedQueries({ - @NamedQuery(name="getAllRealms", query="select realm from RealmEntity realm"), - @NamedQuery(name="getRealmByName", query="select realm from RealmEntity realm where realm.name = :name"), + @NamedQuery(name="getAllRealmIds", query="select realm.id from RealmEntity realm"), + @NamedQuery(name="getRealmIdByName", query="select realm.id from RealmEntity realm where realm.name = :name"), }) public class RealmEntity { @Id @@ -147,9 +147,6 @@ public class RealmEntity { @OneToMany(cascade ={CascadeType.REMOVE}, orphanRemoval = true, mappedBy = "realm") Collection userFederationMappers = new ArrayList(); - @OneToMany(fetch = FetchType.LAZY, cascade ={CascadeType.REMOVE}, orphanRemoval = true, mappedBy="realm") - Collection clients = new ArrayList<>(); - @OneToMany(fetch = FetchType.LAZY, cascade ={CascadeType.REMOVE}, orphanRemoval = true, mappedBy = "realm") Collection clientTemplates = new ArrayList<>(); @@ -421,14 +418,6 @@ public class RealmEntity { public void setRequiredCredentials(Collection requiredCredentials) { this.requiredCredentials = requiredCredentials; } - public Collection getClients() { - return clients; - } - - public void setClients(Collection clients) { - this.clients = clients; - } - public Collection getRoles() { return roles; } diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/RoleEntity.java b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/RoleEntity.java index b94a7439aa..5c02336621 100755 --- a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/RoleEntity.java +++ b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/RoleEntity.java @@ -49,8 +49,11 @@ import java.util.Collection; }) @NamedQueries({ @NamedQuery(name="getClientRoles", query="select role from RoleEntity role where role.client = :client"), + @NamedQuery(name="getClientRoleIds", query="select role.id from RoleEntity role where role.client.id = :client"), @NamedQuery(name="getClientRoleByName", query="select role from RoleEntity role where role.name = :name and role.client = :client"), - @NamedQuery(name="getRealmRoleByName", query="select role from RoleEntity role where role.clientRole = false and role.name = :name and role.realm = :realm") + @NamedQuery(name="getClientRoleIdByName", query="select role.id from RoleEntity role where role.name = :name and role.client.id = :client"), + @NamedQuery(name="getRealmRoleByName", query="select role from RoleEntity role where role.clientRole = false and role.name = :name and role.realm = :realm"), + @NamedQuery(name="getRealmRoleIdByName", query="select role.id from RoleEntity role where role.clientRole = false and role.name = :name and role.realm.id = :realm") }) public class RoleEntity { diff --git a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/MongoRealmProvider.java b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/MongoRealmProvider.java index c5d70fb8b7..1c4036b3c7 100755 --- a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/MongoRealmProvider.java +++ b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/MongoRealmProvider.java @@ -39,6 +39,7 @@ import org.keycloak.models.mongo.keycloak.entities.MongoRoleEntity; import org.keycloak.models.utils.KeycloakModelUtils; import java.util.ArrayList; +import java.util.Collections; import java.util.List; /** @@ -105,7 +106,8 @@ public class MongoRealmProvider implements RealmProvider { List results = new ArrayList(); for (MongoRealmEntity realmEntity : realms) { - results.add(new RealmAdapter(session, realmEntity, invocationContext)); + RealmModel realm = session.realms().getRealm(realmEntity.getId()); + if (realm != null) results.add(realm); } return results; } @@ -118,7 +120,7 @@ public class MongoRealmProvider implements RealmProvider { MongoRealmEntity realm = getMongoStore().loadSingleEntity(MongoRealmEntity.class, query, invocationContext); if (realm == null) return null; - return new RealmAdapter(session, realm, invocationContext); + return session.realms().getRealm(realm.getId()); } @Override @@ -162,6 +164,51 @@ public class MongoRealmProvider implements RealmProvider { return new ClientAdapter(session, realm, appData, invocationContext); } + @Override + public ClientModel addClient(RealmModel realm, String clientId) { + return addClient(realm, KeycloakModelUtils.generateId(), clientId); + } + + @Override + public ClientModel addClient(RealmModel realm, String id, String clientId) { + MongoClientEntity clientEntity = new MongoClientEntity(); + clientEntity.setId(id); + clientEntity.setClientId(clientId); + clientEntity.setRealmId(realm.getId()); + clientEntity.setEnabled(true); + clientEntity.setStandardFlowEnabled(true); + getMongoStore().insertEntity(clientEntity, invocationContext); + + if (clientId == null) { + clientEntity.setClientId(clientEntity.getId()); + getMongoStore().updateEntity(clientEntity, invocationContext); + } + + final ClientModel model = new ClientAdapter(session, realm, clientEntity, invocationContext); + session.getKeycloakSessionFactory().publish(new RealmModel.ClientCreationEvent() { + @Override + public ClientModel getCreatedClient() { + return model; + } + }); + return model; + } + + @Override + public List getClients(RealmModel realm) { + DBObject query = new QueryBuilder() + .and("realmId").is(realm.getId()) + .get(); + List clientEntities = getMongoStore().loadEntities(MongoClientEntity.class, query, invocationContext); + + if (clientEntities.isEmpty()) return Collections.EMPTY_LIST; + List result = new ArrayList(); + for (MongoClientEntity clientEntity : clientEntities) { + result.add(session.realms().getClientById(clientEntity.getId(), realm)); + } + return Collections.unmodifiableList(result); + } + @Override public boolean removeClient(String id, RealmModel realm) { if (id == null) return false; @@ -180,7 +227,8 @@ public class MongoRealmProvider implements RealmProvider { .and("clientId").is(clientId) .get(); MongoClientEntity appEntity = getMongoStore().loadSingleEntity(MongoClientEntity.class, query, invocationContext); - return appEntity == null ? null : new ClientAdapter(session, realm, appEntity, invocationContext); + if (appEntity == null) return null; + return session.realms().getClientById(appEntity.getId(), realm); } diff --git a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/RealmAdapter.java b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/RealmAdapter.java index 48978ffe12..edb57d2156 100755 --- a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/RealmAdapter.java +++ b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/RealmAdapter.java @@ -815,47 +815,18 @@ public class RealmAdapter extends AbstractMongoAdapter impleme @Override public List getClients() { - DBObject query = new QueryBuilder() - .and("realmId").is(getId()) - .get(); - List clientEntities = getMongoStore().loadEntities(MongoClientEntity.class, query, invocationContext); - - if (clientEntities.isEmpty()) return Collections.EMPTY_LIST; - List result = new ArrayList(); - for (MongoClientEntity clientEntity : clientEntities) { - result.add(new ClientAdapter(session, this, clientEntity, invocationContext)); - } - return Collections.unmodifiableList(result); + return session.realms().getClients(this); } @Override public ClientModel addClient(String name) { - return this.addClient(null, name); + return session.realms().addClient(this, name); } @Override public ClientModel addClient(String id, String clientId) { - MongoClientEntity clientEntity = new MongoClientEntity(); - clientEntity.setId(id); - clientEntity.setClientId(clientId); - clientEntity.setRealmId(getId()); - clientEntity.setEnabled(true); - clientEntity.setStandardFlowEnabled(true); - getMongoStore().insertEntity(clientEntity, invocationContext); + return session.realms().addClient(this, id, clientId); - if (clientId == null) { - clientEntity.setClientId(clientEntity.getId()); - getMongoStore().updateEntity(clientEntity, invocationContext); - } - - final ClientModel model = new ClientAdapter(session, this, clientEntity, invocationContext); - session.getKeycloakSessionFactory().publish(new ClientCreationEvent() { - @Override - public ClientModel getCreatedClient() { - return model; - } - }); - return model; } @Override diff --git a/server-spi/src/main/java/org/keycloak/models/RealmProvider.java b/server-spi/src/main/java/org/keycloak/models/RealmProvider.java index 2b3f5fab3c..a101ce4919 100755 --- a/server-spi/src/main/java/org/keycloak/models/RealmProvider.java +++ b/server-spi/src/main/java/org/keycloak/models/RealmProvider.java @@ -35,6 +35,12 @@ public interface RealmProvider extends Provider { RealmModel getRealm(String id); RealmModel getRealmByName(String name); + ClientModel addClient(RealmModel realm, String clientId); + + ClientModel addClient(RealmModel realm, String id, String clientId); + + List getClients(RealmModel realm); + ClientModel getClientById(String id, RealmModel realm); ClientModel getClientByClientId(String clientId, RealmModel realm); diff --git a/server-spi/src/main/java/org/keycloak/models/cache/CacheRealmProvider.java b/server-spi/src/main/java/org/keycloak/models/cache/CacheRealmProvider.java index 0f90b1d363..7bc1299764 100755 --- a/server-spi/src/main/java/org/keycloak/models/cache/CacheRealmProvider.java +++ b/server-spi/src/main/java/org/keycloak/models/cache/CacheRealmProvider.java @@ -29,7 +29,7 @@ public interface CacheRealmProvider extends RealmProvider { void registerRealmInvalidation(String id); - void registerApplicationInvalidation(String id); + void registerClientInvalidation(String id); void registerClientTemplateInvalidation(String id); void registerRoleInvalidation(String id); diff --git a/server-spi/src/main/java/org/keycloak/models/cache/entities/CachedClientRole.java b/server-spi/src/main/java/org/keycloak/models/cache/entities/CachedClientRole.java index 0109d6a1d5..3cbfa304e0 100755 --- a/server-spi/src/main/java/org/keycloak/models/cache/entities/CachedClientRole.java +++ b/server-spi/src/main/java/org/keycloak/models/cache/entities/CachedClientRole.java @@ -26,15 +26,15 @@ import org.keycloak.models.RoleModel; */ public class CachedClientRole extends CachedRole { - private final String idClient; + private final String clientId; - public CachedClientRole(String idClient, RoleModel model, RealmModel realm) { + public CachedClientRole(String clientId, RoleModel model, RealmModel realm) { super(model, realm); - this.idClient = idClient; + this.clientId = clientId; } - public String getIdClient() { - return idClient; + public String getClientId() { + return clientId; } } diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/META-INF/keycloak-server.json b/testsuite/integration-arquillian/tests/base/src/test/resources/META-INF/keycloak-server.json index e26f6107dc..ae0f5f9a07 100755 --- a/testsuite/integration-arquillian/tests/base/src/test/resources/META-INF/keycloak-server.json +++ b/testsuite/integration-arquillian/tests/base/src/test/resources/META-INF/keycloak-server.json @@ -27,7 +27,10 @@ }, "userCache": { - "provider": "${keycloak.user.cache.provider:infinispan}", + "provider": "${keycloak.user.cache.provider:default}", + "default" : { + "enabled": true + }, "mem": { "maxSize": 20000 } @@ -95,15 +98,14 @@ }, "realmCache": { - "provider": "infinispan-locking", - "infinispan-locking" : { + "provider": "${keycloak.realm.cache.provider:default}", + "default" : { "enabled": true } }, "connectionsInfinispan": { - "provider": "locking", - "locking": { + "default": { "clustered": "${keycloak.connectionsInfinispan.clustered:false}", "async": "${keycloak.connectionsInfinispan.async:true}", "sessionsOwners": "${keycloak.connectionsInfinispan.sessionsOwners:2}" diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/ConcurrencyTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/ConcurrencyTest.java index 7984fae9d3..9adebd3fc2 100755 --- a/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/ConcurrencyTest.java +++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/ConcurrencyTest.java @@ -27,6 +27,7 @@ import org.keycloak.admin.client.resource.RealmResource; import org.keycloak.representations.idm.ClientRepresentation; import org.keycloak.representations.idm.RoleRepresentation; +import javax.ws.rs.NotFoundException; import javax.ws.rs.core.Response; import java.util.LinkedList; import java.util.List; @@ -90,6 +91,7 @@ public class ConcurrencyTest extends AbstractClientTest { @Test public void createClient() throws Throwable { + System.out.println("***************************"); long start = System.currentTimeMillis(); run(new KeycloakRunnable() { @Override @@ -101,7 +103,8 @@ public class ConcurrencyTest extends AbstractClientTest { String id = ApiUtil.getCreatedId(response); response.close(); - assertNotNull(realm.clients().get(id)); + c = realm.clients().get(id).toRepresentation(); + assertNotNull(c); boolean found = false; for (ClientRepresentation r : realm.clients().findAll()) { if (r.getClientId().equals(name)) { @@ -119,6 +122,58 @@ public class ConcurrencyTest extends AbstractClientTest { } + @Test + @Ignore + public void createRemoveClient() throws Throwable { + // FYI< this will fail as HSQL seems to be trying to perform table locks. + System.out.println("***************************"); + long start = System.currentTimeMillis(); + run(new KeycloakRunnable() { + @Override + public void run(Keycloak keycloak, RealmResource realm, int threadNum, int iterationNum) { + String name = "c-" + threadNum + "-" + iterationNum; + ClientRepresentation c = new ClientRepresentation(); + c.setClientId(name); + Response response = realm.clients().create(c); + String id = ApiUtil.getCreatedId(response); + response.close(); + + c = realm.clients().get(id).toRepresentation(); + assertNotNull(c); + boolean found = false; + for (ClientRepresentation r : realm.clients().findAll()) { + if (r.getClientId().equals(name)) { + found = true; + break; + } + } + if (!found) { + fail("Client " + name + " not found in client list"); + } + realm.clients().get(id).remove(); + try { + c = realm.clients().get(id).toRepresentation(); + fail("Client " + name + " should not be found. Should throw a 404"); + } catch (NotFoundException e) { + + } + found = false; + for (ClientRepresentation r : realm.clients().findAll()) { + if (r.getClientId().equals(name)) { + found = true; + break; + } + } + Assert.assertFalse("Client " + name + " should not be in client list", found); + + } + }); + long end = System.currentTimeMillis() - start; + System.out.println("createClient took " + end); + + } + + @Test public void createRole() throws Throwable { long start = System.currentTimeMillis(); diff --git a/testsuite/integration/src/test/resources/META-INF/keycloak-server.json b/testsuite/integration/src/test/resources/META-INF/keycloak-server.json index 9329cde8d0..950fd224ad 100755 --- a/testsuite/integration/src/test/resources/META-INF/keycloak-server.json +++ b/testsuite/integration/src/test/resources/META-INF/keycloak-server.json @@ -27,7 +27,7 @@ }, "userCache": { - "infinispan" : { + "default" : { "enabled": true } }, @@ -78,15 +78,13 @@ }, "realmCache": { - "provider": "infinispan-locking", - "infinispan-locking" : { + "default" : { "enabled": true } }, "connectionsInfinispan": { - "provider": "locking", - "locking": { + "default": { "clustered": "${keycloak.connectionsInfinispan.clustered:false}", "async": "${keycloak.connectionsInfinispan.async:true}", "sessionsOwners": "${keycloak.connectionsInfinispan.sessionsOwners:2}" diff --git a/testsuite/integration/src/test/resources/log4j.properties b/testsuite/integration/src/test/resources/log4j.properties index 91c9646a80..a199a4174d 100755 --- a/testsuite/integration/src/test/resources/log4j.properties +++ b/testsuite/integration/src/test/resources/log4j.properties @@ -19,7 +19,7 @@ log4j.rootLogger=info, stdout log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.layout=org.apache.log4j.PatternLayout -log4j.appender.stdout.layout.ConversionPattern=%d{HH:mm:ss,SSS} %-5p [%c] %m%n +log4j.appender.stdout.layout.ConversionPattern=%d{HH:mm:ss,SSS} %-5p %t [%c] %m%n log4j.logger.org.keycloak=info From 2e64d0125149634c974fe53fdcd6f08abf963ed5 Mon Sep 17 00:00:00 2001 From: Bill Burke Date: Fri, 19 Feb 2016 16:38:31 -0500 Subject: [PATCH 2/5] reorg caching --- .../cache/infinispan/ClientAdapter.java | 3 +- .../infinispan/ClientTemplateAdapter.java | 7 +- .../infinispan/DefaultCacheUserProvider.java | 3 +- .../models/cache/infinispan/GroupAdapter.java | 2 +- .../InfinispanCacheRealmProviderFactory.java | 18 +---- .../InfinispanCacheUserProviderFactory.java | 2 +- .../cache/infinispan/InfinispanUserCache.java | 3 +- .../models/cache/infinispan/RealmAdapter.java | 3 +- .../models/cache/infinispan}/RealmCache.java | 12 +-- .../models/cache/infinispan/RoleAdapter.java | 11 +-- .../StreamCacheRealmProvider.java | 51 ++++++------- .../{stream => }/StreamRealmCache.java | 73 ++++++++++--------- .../{stream => }/UpdateCounter.java | 2 +- .../models/cache/infinispan/UserAdapter.java | 2 +- .../models/cache/infinispan}/UserCache.java | 4 +- .../entities/AbstractRevisioned.java | 6 +- .../infinispan}/entities/CachedClient.java | 23 ++---- .../entities/CachedClientRole.java | 8 +- .../entities/CachedClientTemplate.java | 19 ++--- .../infinispan}/entities/CachedGroup.java | 13 +--- .../infinispan}/entities/CachedRealm.java | 36 +++------ .../infinispan}/entities/CachedRealmRole.java | 6 +- .../infinispan}/entities/CachedRole.java | 13 +--- .../infinispan}/entities/CachedUser.java | 2 +- .../{stream => entities}/ClientListQuery.java | 3 +- .../{stream => entities}/ClientQuery.java | 5 +- .../ClientTemplateQuery.java | 4 +- .../{stream => entities}/GroupQuery.java | 4 +- .../{stream => }/entities/InClient.java | 2 +- .../{stream => }/entities/InRealm.java | 2 +- .../{stream => entities}/RealmListQuery.java | 4 +- .../{stream => entities}/RealmQuery.java | 4 +- .../{stream => }/entities/Revisioned.java | 2 +- .../{stream => entities}/RoleQuery.java | 4 +- .../stream/ClientQueryPredicate.java | 6 +- .../stream/ClientTemplateQueryPredicate.java | 7 +- .../stream/GroupQueryPredicate.java | 7 +- .../infinispan/stream/HasRolePredicate.java | 9 ++- .../infinispan/stream/InClientPredicate.java | 8 +- .../infinispan/stream/InRealmPredicate.java | 7 +- .../stream/RealmQueryPredicate.java | 7 +- .../infinispan/stream/RoleQueryPredicate.java | 7 +- .../entities/RevisionedCachedClient.java | 39 ---------- .../entities/RevisionedCachedClientRole.java | 31 -------- .../RevisionedCachedClientTemplate.java | 33 --------- .../entities/RevisionedCachedGroup.java | 30 -------- .../entities/RevisionedCachedRealm.java | 54 -------------- .../entities/RevisionedCachedRealmRole.java | 30 -------- .../stream/entities/RevisionedCachedUser.java | 29 -------- 49 files changed, 185 insertions(+), 475 deletions(-) rename {server-spi/src/main/java/org/keycloak/models/cache => model/infinispan/src/main/java/org/keycloak/models/cache/infinispan}/RealmCache.java (82%) rename model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/{stream => }/StreamCacheRealmProvider.java (90%) rename model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/{stream => }/StreamRealmCache.java (75%) rename model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/{stream => }/UpdateCounter.java (87%) rename {server-spi/src/main/java/org/keycloak/models/cache => model/infinispan/src/main/java/org/keycloak/models/cache/infinispan}/UserCache.java (91%) rename model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/{stream => }/entities/AbstractRevisioned.java (77%) rename {server-spi/src/main/java/org/keycloak/models/cache => model/infinispan/src/main/java/org/keycloak/models/cache/infinispan}/entities/CachedClient.java (92%) rename {server-spi/src/main/java/org/keycloak/models/cache => model/infinispan/src/main/java/org/keycloak/models/cache/infinispan}/entities/CachedClientRole.java (79%) rename {server-spi/src/main/java/org/keycloak/models/cache => model/infinispan/src/main/java/org/keycloak/models/cache/infinispan}/entities/CachedClientTemplate.java (88%) rename {server-spi/src/main/java/org/keycloak/models/cache => model/infinispan/src/main/java/org/keycloak/models/cache/infinispan}/entities/CachedGroup.java (89%) rename {server-spi/src/main/java/org/keycloak/models/cache => model/infinispan/src/main/java/org/keycloak/models/cache/infinispan}/entities/CachedRealm.java (94%) rename {server-spi/src/main/java/org/keycloak/models/cache => model/infinispan/src/main/java/org/keycloak/models/cache/infinispan}/entities/CachedRealmRole.java (84%) rename {server-spi/src/main/java/org/keycloak/models/cache => model/infinispan/src/main/java/org/keycloak/models/cache/infinispan}/entities/CachedRole.java (88%) rename {server-spi/src/main/java/org/keycloak/models/cache => model/infinispan/src/main/java/org/keycloak/models/cache/infinispan}/entities/CachedUser.java (98%) rename model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/{stream => entities}/ClientListQuery.java (90%) rename model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/{stream => entities}/ClientQuery.java (58%) rename model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/{stream => entities}/ClientTemplateQuery.java (63%) rename model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/{stream => entities}/GroupQuery.java (62%) rename model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/{stream => }/entities/InClient.java (73%) rename model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/{stream => }/entities/InRealm.java (73%) rename model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/{stream => entities}/RealmListQuery.java (82%) rename model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/{stream => entities}/RealmQuery.java (60%) rename model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/{stream => }/entities/Revisioned.java (77%) rename model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/{stream => entities}/RoleQuery.java (62%) delete mode 100755 model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/entities/RevisionedCachedClient.java delete mode 100755 model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/entities/RevisionedCachedClientRole.java delete mode 100755 model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/entities/RevisionedCachedClientTemplate.java delete mode 100755 model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/entities/RevisionedCachedGroup.java delete mode 100755 model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/entities/RevisionedCachedRealm.java delete mode 100755 model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/entities/RevisionedCachedRealmRole.java delete mode 100755 model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/entities/RevisionedCachedUser.java diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/ClientAdapter.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/ClientAdapter.java index cdaa2e7537..e636f5a9bb 100755 --- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/ClientAdapter.java +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/ClientAdapter.java @@ -19,8 +19,7 @@ package org.keycloak.models.cache.infinispan; import org.keycloak.models.*; import org.keycloak.models.cache.CacheRealmProvider; -import org.keycloak.models.cache.RealmCache; -import org.keycloak.models.cache.entities.CachedClient; +import org.keycloak.models.cache.infinispan.entities.CachedClient; import java.util.*; diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/ClientTemplateAdapter.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/ClientTemplateAdapter.java index ce4095e9e2..b54738ad9f 100755 --- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/ClientTemplateAdapter.java +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/ClientTemplateAdapter.java @@ -24,8 +24,7 @@ import org.keycloak.models.RealmModel; import org.keycloak.models.RoleContainerModel; import org.keycloak.models.RoleModel; import org.keycloak.models.cache.CacheRealmProvider; -import org.keycloak.models.cache.RealmCache; -import org.keycloak.models.cache.entities.CachedClientTemplate; +import org.keycloak.models.cache.infinispan.entities.CachedClientTemplate; import java.util.HashMap; import java.util.HashSet; @@ -39,14 +38,12 @@ import java.util.Set; public class ClientTemplateAdapter implements ClientTemplateModel { protected CacheRealmProvider cacheSession; protected RealmModel cachedRealm; - protected RealmCache cache; protected ClientTemplateModel updated; protected CachedClientTemplate cached; - public ClientTemplateAdapter(RealmModel cachedRealm, CachedClientTemplate cached, CacheRealmProvider cacheSession, RealmCache cache) { + public ClientTemplateAdapter(RealmModel cachedRealm, CachedClientTemplate cached, CacheRealmProvider cacheSession) { this.cachedRealm = cachedRealm; - this.cache = cache; this.cacheSession = cacheSession; this.cached = cached; } diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/DefaultCacheUserProvider.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/DefaultCacheUserProvider.java index 3726edbaec..e8f74bc9b8 100755 --- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/DefaultCacheUserProvider.java +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/DefaultCacheUserProvider.java @@ -19,8 +19,7 @@ package org.keycloak.models.cache.infinispan; import org.keycloak.models.*; import org.keycloak.models.cache.CacheUserProvider; -import org.keycloak.models.cache.UserCache; -import org.keycloak.models.cache.entities.CachedUser; +import org.keycloak.models.cache.infinispan.entities.CachedUser; import java.util.*; diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/GroupAdapter.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/GroupAdapter.java index af704ecd7d..1810a34990 100755 --- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/GroupAdapter.java +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/GroupAdapter.java @@ -24,7 +24,7 @@ import org.keycloak.models.RealmModel; import org.keycloak.models.RoleContainerModel; import org.keycloak.models.RoleModel; import org.keycloak.models.cache.CacheRealmProvider; -import org.keycloak.models.cache.entities.CachedGroup; +import org.keycloak.models.cache.infinispan.entities.CachedGroup; import java.util.HashSet; import java.util.List; diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/InfinispanCacheRealmProviderFactory.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/InfinispanCacheRealmProviderFactory.java index 39bc4938e4..fb9946b28e 100755 --- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/InfinispanCacheRealmProviderFactory.java +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/InfinispanCacheRealmProviderFactory.java @@ -18,15 +18,6 @@ package org.keycloak.models.cache.infinispan; import org.infinispan.Cache; -import org.infinispan.notifications.Listener; -import org.infinispan.notifications.cachelistener.annotation.CacheEntriesEvicted; -import org.infinispan.notifications.cachelistener.annotation.CacheEntryCreated; -import org.infinispan.notifications.cachelistener.annotation.CacheEntryInvalidated; -import org.infinispan.notifications.cachelistener.annotation.CacheEntryRemoved; -import org.infinispan.notifications.cachelistener.event.CacheEntriesEvictedEvent; -import org.infinispan.notifications.cachelistener.event.CacheEntryCreatedEvent; -import org.infinispan.notifications.cachelistener.event.CacheEntryInvalidatedEvent; -import org.infinispan.notifications.cachelistener.event.CacheEntryRemovedEvent; import org.jboss.logging.Logger; import org.keycloak.Config; import org.keycloak.connections.infinispan.InfinispanConnectionProvider; @@ -34,12 +25,7 @@ import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSessionFactory; import org.keycloak.models.cache.CacheRealmProvider; import org.keycloak.models.cache.CacheRealmProviderFactory; -import org.keycloak.models.cache.entities.CachedClient; -import org.keycloak.models.cache.entities.CachedRealm; -import org.keycloak.models.cache.infinispan.stream.StreamCacheRealmProvider; -import org.keycloak.models.cache.infinispan.stream.StreamRealmCache; - -import java.util.concurrent.ConcurrentHashMap; +import org.keycloak.models.cache.infinispan.entities.Revisioned; /** * @author Bill Burke @@ -61,7 +47,7 @@ public class InfinispanCacheRealmProviderFactory implements CacheRealmProviderFa if (realmCache == null) { synchronized (this) { if (realmCache == null) { - Cache cache = session.getProvider(InfinispanConnectionProvider.class).getCache(InfinispanConnectionProvider.REALM_CACHE_NAME); + Cache cache = session.getProvider(InfinispanConnectionProvider.class).getCache(InfinispanConnectionProvider.REALM_CACHE_NAME); Cache revisions = session.getProvider(InfinispanConnectionProvider.class).getCache(InfinispanConnectionProvider.VERSION_CACHE_NAME); realmCache = new StreamRealmCache(cache, revisions); } diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/InfinispanCacheUserProviderFactory.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/InfinispanCacheUserProviderFactory.java index b473d60e9f..e8657ff579 100755 --- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/InfinispanCacheUserProviderFactory.java +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/InfinispanCacheUserProviderFactory.java @@ -28,7 +28,7 @@ import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSessionFactory; import org.keycloak.models.cache.CacheUserProvider; import org.keycloak.models.cache.CacheUserProviderFactory; -import org.keycloak.models.cache.entities.CachedUser; +import org.keycloak.models.cache.infinispan.entities.CachedUser; import java.util.concurrent.ConcurrentHashMap; diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/InfinispanUserCache.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/InfinispanUserCache.java index de83e6ac71..bb7196e779 100755 --- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/InfinispanUserCache.java +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/InfinispanUserCache.java @@ -19,8 +19,7 @@ package org.keycloak.models.cache.infinispan; import org.infinispan.Cache; import org.jboss.logging.Logger; -import org.keycloak.models.cache.UserCache; -import org.keycloak.models.cache.entities.CachedUser; +import org.keycloak.models.cache.infinispan.entities.CachedUser; /** * @author Stian Thorgersen diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/RealmAdapter.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/RealmAdapter.java index 39564ef434..bc39f320d0 100755 --- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/RealmAdapter.java +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/RealmAdapter.java @@ -21,8 +21,7 @@ import org.keycloak.Config; import org.keycloak.common.enums.SslRequired; import org.keycloak.models.*; import org.keycloak.models.cache.CacheRealmProvider; -import org.keycloak.models.cache.RealmCache; -import org.keycloak.models.cache.entities.CachedRealm; +import org.keycloak.models.cache.infinispan.entities.CachedRealm; import org.keycloak.models.utils.KeycloakModelUtils; import java.security.Key; diff --git a/server-spi/src/main/java/org/keycloak/models/cache/RealmCache.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/RealmCache.java similarity index 82% rename from server-spi/src/main/java/org/keycloak/models/cache/RealmCache.java rename to model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/RealmCache.java index 2b7b339daf..d683bb015b 100755 --- a/server-spi/src/main/java/org/keycloak/models/cache/RealmCache.java +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/RealmCache.java @@ -15,13 +15,13 @@ * limitations under the License. */ -package org.keycloak.models.cache; +package org.keycloak.models.cache.infinispan; -import org.keycloak.models.cache.entities.CachedClient; -import org.keycloak.models.cache.entities.CachedClientTemplate; -import org.keycloak.models.cache.entities.CachedGroup; -import org.keycloak.models.cache.entities.CachedRealm; -import org.keycloak.models.cache.entities.CachedRole; +import org.keycloak.models.cache.infinispan.entities.CachedClient; +import org.keycloak.models.cache.infinispan.entities.CachedClientTemplate; +import org.keycloak.models.cache.infinispan.entities.CachedGroup; +import org.keycloak.models.cache.infinispan.entities.CachedRealm; +import org.keycloak.models.cache.infinispan.entities.CachedRole; /** * @author Bill Burke diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/RoleAdapter.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/RoleAdapter.java index c7ebc44cfb..0b0c3a6cfe 100755 --- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/RoleAdapter.java +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/RoleAdapter.java @@ -21,10 +21,9 @@ import org.keycloak.models.RealmModel; import org.keycloak.models.RoleContainerModel; import org.keycloak.models.RoleModel; import org.keycloak.models.cache.CacheRealmProvider; -import org.keycloak.models.cache.RealmCache; -import org.keycloak.models.cache.entities.CachedClientRole; -import org.keycloak.models.cache.entities.CachedRealmRole; -import org.keycloak.models.cache.entities.CachedRole; +import org.keycloak.models.cache.infinispan.entities.CachedClientRole; +import org.keycloak.models.cache.infinispan.entities.CachedRealmRole; +import org.keycloak.models.cache.infinispan.entities.CachedRole; import org.keycloak.models.utils.KeycloakModelUtils; import java.util.HashSet; @@ -38,13 +37,11 @@ public class RoleAdapter implements RoleModel { protected RoleModel updated; protected CachedRole cached; - protected RealmCache cache; protected CacheRealmProvider cacheSession; protected RealmModel realm; - public RoleAdapter(CachedRole cached, RealmCache cache, CacheRealmProvider session, RealmModel realm) { + public RoleAdapter(CachedRole cached, CacheRealmProvider session, RealmModel realm) { this.cached = cached; - this.cache = cache; this.cacheSession = session; this.realm = realm; } diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/StreamCacheRealmProvider.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/StreamCacheRealmProvider.java similarity index 90% rename from model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/StreamCacheRealmProvider.java rename to model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/StreamCacheRealmProvider.java index d68f50c125..d21599c196 100755 --- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/StreamCacheRealmProvider.java +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/StreamCacheRealmProvider.java @@ -15,7 +15,7 @@ * limitations under the License. */ -package org.keycloak.models.cache.infinispan.stream; +package org.keycloak.models.cache.infinispan; import org.jboss.logging.Logger; import org.keycloak.migration.MigrationModel; @@ -28,19 +28,16 @@ import org.keycloak.models.RealmModel; import org.keycloak.models.RealmProvider; import org.keycloak.models.RoleModel; import org.keycloak.models.cache.CacheRealmProvider; -import org.keycloak.models.cache.entities.CachedRole; -import org.keycloak.models.cache.infinispan.ClientAdapter; -import org.keycloak.models.cache.infinispan.ClientTemplateAdapter; -import org.keycloak.models.cache.infinispan.GroupAdapter; -import org.keycloak.models.cache.infinispan.RealmAdapter; -import org.keycloak.models.cache.infinispan.RoleAdapter; -import org.keycloak.models.cache.infinispan.stream.entities.Revisioned; -import org.keycloak.models.cache.infinispan.stream.entities.RevisionedCachedClient; -import org.keycloak.models.cache.infinispan.stream.entities.RevisionedCachedClientRole; -import org.keycloak.models.cache.infinispan.stream.entities.RevisionedCachedClientTemplate; -import org.keycloak.models.cache.infinispan.stream.entities.RevisionedCachedGroup; -import org.keycloak.models.cache.infinispan.stream.entities.RevisionedCachedRealm; -import org.keycloak.models.cache.infinispan.stream.entities.RevisionedCachedRealmRole; +import org.keycloak.models.cache.infinispan.entities.CachedClient; +import org.keycloak.models.cache.infinispan.entities.CachedClientRole; +import org.keycloak.models.cache.infinispan.entities.CachedClientTemplate; +import org.keycloak.models.cache.infinispan.entities.CachedGroup; +import org.keycloak.models.cache.infinispan.entities.CachedRealm; +import org.keycloak.models.cache.infinispan.entities.CachedRealmRole; +import org.keycloak.models.cache.infinispan.entities.CachedRole; +import org.keycloak.models.cache.infinispan.entities.ClientListQuery; +import org.keycloak.models.cache.infinispan.entities.RealmListQuery; +import org.keycloak.models.cache.infinispan.entities.Revisioned; import java.util.Collections; import java.util.HashMap; @@ -249,7 +246,7 @@ public class StreamCacheRealmProvider implements CacheRealmProvider { @Override public RealmModel getRealm(String id) { - RevisionedCachedRealm cached = cache.get(id, RevisionedCachedRealm.class); + CachedRealm cached = cache.get(id, CachedRealm.class); if (cached != null) { logger.tracev("by id cache hit: {0}", cached.getName()); } @@ -258,7 +255,7 @@ public class StreamCacheRealmProvider implements CacheRealmProvider { RealmModel model = getDelegate().getRealm(id); if (model == null) return null; if (invalidations.contains(id)) return model; - cached = new RevisionedCachedRealm(loaded, null, this, model); + cached = new CachedRealm(loaded, model); cache.addRevisioned(cached); } else if (invalidations.contains(id)) { return getDelegate().getRealm(id); @@ -415,25 +412,25 @@ public class StreamCacheRealmProvider implements CacheRealmProvider { if (model == null) return null; if (invalidations.contains(id)) return model; if (model.getContainer() instanceof ClientModel) { - cached = new RevisionedCachedClientRole(loaded, ((ClientModel) model.getContainer()).getId(), model, realm); + cached = new CachedClientRole(loaded, ((ClientModel) model.getContainer()).getId(), model, realm); } else { - cached = new RevisionedCachedRealmRole(loaded, model, realm); + cached = new CachedRealmRole(loaded, model, realm); } - cache.addRevisioned((Revisioned)cached); + cache.addRevisioned(cached); } else if (invalidations.contains(id)) { return getDelegate().getRoleById(id, realm); } else if (managedRoles.containsKey(id)) { return managedRoles.get(id); } - RoleAdapter adapter = new RoleAdapter(cached, null, this, realm); + RoleAdapter adapter = new RoleAdapter(cached,this, realm); managedRoles.put(id, adapter); return adapter; } @Override public GroupModel getGroupById(String id, RealmModel realm) { - RevisionedCachedGroup cached = cache.get(id, RevisionedCachedGroup.class); + CachedGroup cached = cache.get(id, CachedGroup.class); if (cached != null && !cached.getRealm().equals(realm.getId())) { cached = null; } @@ -443,7 +440,7 @@ public class StreamCacheRealmProvider implements CacheRealmProvider { GroupModel model = getDelegate().getGroupById(id, realm); if (model == null) return null; if (invalidations.contains(id)) return model; - cached = new RevisionedCachedGroup(loaded, realm, model); + cached = new CachedGroup(loaded, realm, model); cache.addRevisioned(cached); } else if (invalidations.contains(id)) { @@ -458,7 +455,7 @@ public class StreamCacheRealmProvider implements CacheRealmProvider { @Override public ClientModel getClientById(String id, RealmModel realm) { - RevisionedCachedClient cached = cache.get(id, RevisionedCachedClient.class); + CachedClient cached = cache.get(id, CachedClient.class); if (cached != null && !cached.getRealm().equals(realm.getId())) { cached = null; } @@ -471,7 +468,7 @@ public class StreamCacheRealmProvider implements CacheRealmProvider { ClientModel model = getDelegate().getClientById(id, realm); if (model == null) return null; if (invalidations.contains(id)) return model; - cached = new RevisionedCachedClient(loaded, null, getDelegate(), realm, model); + cached = new CachedClient(loaded, realm, model); logger.tracev("adding client by id cache miss: {0}", cached.getClientId()); cache.addRevisioned(cached); } else if (invalidations.contains(id)) { @@ -516,7 +513,7 @@ public class StreamCacheRealmProvider implements CacheRealmProvider { @Override public ClientTemplateModel getClientTemplateById(String id, RealmModel realm) { - RevisionedCachedClientTemplate cached = cache.get(id, RevisionedCachedClientTemplate.class); + CachedClientTemplate cached = cache.get(id, CachedClientTemplate.class); if (cached != null && !cached.getRealm().equals(realm.getId())) { cached = null; } @@ -526,14 +523,14 @@ public class StreamCacheRealmProvider implements CacheRealmProvider { ClientTemplateModel model = getDelegate().getClientTemplateById(id, realm); if (model == null) return null; if (invalidations.contains(id)) return model; - cached = new RevisionedCachedClientTemplate(loaded, null, getDelegate(), realm, model); + cached = new CachedClientTemplate(loaded, realm, model); cache.addRevisioned(cached); } else if (invalidations.contains(id)) { return getDelegate().getClientTemplateById(id, realm); } else if (managedClientTemplates.containsKey(id)) { return managedClientTemplates.get(id); } - ClientTemplateModel adapter = new ClientTemplateAdapter(realm, cached, this, null); + ClientTemplateModel adapter = new ClientTemplateAdapter(realm, cached, this); managedClientTemplates.put(id, adapter); return adapter; } diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/StreamRealmCache.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/StreamRealmCache.java similarity index 75% rename from model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/StreamRealmCache.java rename to model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/StreamRealmCache.java index 9dd821bdff..da292a1d56 100755 --- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/StreamRealmCache.java +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/StreamRealmCache.java @@ -15,7 +15,7 @@ * limitations under the License. */ -package org.keycloak.models.cache.infinispan.stream; +package org.keycloak.models.cache.infinispan; import org.infinispan.Cache; import org.infinispan.notifications.Listener; @@ -24,12 +24,19 @@ import org.infinispan.notifications.cachelistener.annotation.CacheEntryInvalidat import org.infinispan.notifications.cachelistener.event.CacheEntriesEvictedEvent; import org.infinispan.notifications.cachelistener.event.CacheEntryInvalidatedEvent; import org.jboss.logging.Logger; -import org.keycloak.models.cache.entities.CachedClient; -import org.keycloak.models.cache.entities.CachedClientTemplate; -import org.keycloak.models.cache.entities.CachedGroup; -import org.keycloak.models.cache.entities.CachedRealm; -import org.keycloak.models.cache.entities.CachedRole; -import org.keycloak.models.cache.infinispan.stream.entities.Revisioned; +import org.keycloak.models.cache.infinispan.entities.CachedClient; +import org.keycloak.models.cache.infinispan.entities.CachedClientTemplate; +import org.keycloak.models.cache.infinispan.entities.CachedGroup; +import org.keycloak.models.cache.infinispan.entities.CachedRealm; +import org.keycloak.models.cache.infinispan.entities.CachedRole; +import org.keycloak.models.cache.infinispan.entities.Revisioned; +import org.keycloak.models.cache.infinispan.stream.ClientQueryPredicate; +import org.keycloak.models.cache.infinispan.stream.ClientTemplateQueryPredicate; +import org.keycloak.models.cache.infinispan.stream.GroupQueryPredicate; +import org.keycloak.models.cache.infinispan.stream.HasRolePredicate; +import org.keycloak.models.cache.infinispan.stream.InClientPredicate; +import org.keycloak.models.cache.infinispan.stream.InRealmPredicate; +import org.keycloak.models.cache.infinispan.stream.RealmQueryPredicate; import java.util.HashSet; import java.util.Iterator; @@ -46,15 +53,15 @@ public class StreamRealmCache { protected static final Logger logger = Logger.getLogger(StreamRealmCache.class); protected final Cache revisions; - protected final Cache cache; + protected final Cache cache; - public StreamRealmCache(Cache cache, Cache revisions) { + public StreamRealmCache(Cache cache, Cache revisions) { this.cache = cache; this.cache.addListener(this); this.revisions = revisions; } - public Cache getCache() { + public Cache getCache() { return cache; } @@ -144,11 +151,11 @@ public class StreamRealmCache { } public void realmInvalidation(String id, Set invalidations) { - Predicate> predicate = getRealmInvalidationPredicate(id); + Predicate> predicate = getRealmInvalidationPredicate(id); addInvalidations(predicate, invalidations); } - public Predicate> getRealmInvalidationPredicate(String id) { + public Predicate> getRealmInvalidationPredicate(String id) { return RealmQueryPredicate.create().realm(id); } @@ -156,7 +163,7 @@ public class StreamRealmCache { addInvalidations(getClientInvalidationPredicate(id), invalidations); } - public Predicate> getClientInvalidationPredicate(String id) { + public Predicate> getClientInvalidationPredicate(String id) { return ClientQueryPredicate.create().client(id); } @@ -165,7 +172,7 @@ public class StreamRealmCache { } - public Predicate> getRoleInvalidationPredicate(String id) { + public Predicate> getRoleInvalidationPredicate(String id) { return HasRolePredicate.create().role(id); } @@ -174,7 +181,7 @@ public class StreamRealmCache { } - public Predicate> getGroupInvalidationPredicate(String id) { + public Predicate> getGroupInvalidationPredicate(String id) { return GroupQueryPredicate.create().group(id); } @@ -183,17 +190,17 @@ public class StreamRealmCache { } - public Predicate> getClientTemplateInvalidationPredicate(String id) { + public Predicate> getClientTemplateInvalidationPredicate(String id) { return ClientTemplateQueryPredicate.create().template(id); } public void realmRemoval(String id, Set invalidations) { - Predicate> predicate = getRealmRemovalPredicate(id); + Predicate> predicate = getRealmRemovalPredicate(id); addInvalidations(predicate, invalidations); } - public Predicate> getRealmRemovalPredicate(String id) { - Predicate> predicate = null; + public Predicate> getRealmRemovalPredicate(String id) { + Predicate> predicate = null; predicate = RealmQueryPredicate.create().realm(id) .or(InRealmPredicate.create().realm(id)); return predicate; @@ -203,18 +210,18 @@ public class StreamRealmCache { addInvalidations(getClientAddedPredicate(realmId), invalidations); } - public Predicate> getClientAddedPredicate(String realmId) { + public Predicate> getClientAddedPredicate(String realmId) { return ClientQueryPredicate.create().inRealm(realmId); } public void clientRemoval(String realmId, String id, Set invalidations) { - Predicate> predicate = null; + Predicate> predicate = null; predicate = getClientRemovalPredicate(realmId, id); addInvalidations(predicate, invalidations); } - public Predicate> getClientRemovalPredicate(String realmId, String id) { - Predicate> predicate; + public Predicate> getClientRemovalPredicate(String realmId, String id) { + Predicate> predicate; predicate = ClientQueryPredicate.create().inRealm(realmId) .or(ClientQueryPredicate.create().client(id)) .or(InClientPredicate.create().client(id)); @@ -226,18 +233,18 @@ public class StreamRealmCache { } - public Predicate> getRoleRemovalPredicate(String id) { + public Predicate> getRoleRemovalPredicate(String id) { return getRoleInvalidationPredicate(id); } - public void addInvalidations(Predicate> predicate, Set invalidations) { - Iterator> it = getEntryIterator(predicate); + public void addInvalidations(Predicate> predicate, Set invalidations) { + Iterator> it = getEntryIterator(predicate); while (it.hasNext()) { invalidations.add(it.next().getKey()); } } - private Iterator> getEntryIterator(Predicate> predicate) { + private Iterator> getEntryIterator(Predicate> predicate) { return cache .entrySet() .stream() @@ -249,7 +256,7 @@ public class StreamRealmCache { if (event.isPre()) { Object object = event.getValue(); if (object != null) { - Predicate> predicate = getInvalidationPredicate(object); + Predicate> predicate = getInvalidationPredicate(object); if (predicate != null) runEvictions(predicate); } } @@ -258,18 +265,18 @@ public class StreamRealmCache { @CacheEntriesEvicted public void cacheEvicted(CacheEntriesEvictedEvent event) { for (Object object : event.getEntries().values()) { - Predicate> predicate = getEvictionPredicate(object); + Predicate> predicate = getEvictionPredicate(object); if (predicate != null) runEvictions(predicate); } } - public void runEvictions(Predicate> current) { + public void runEvictions(Predicate> current) { Set evictions = new HashSet<>(); addInvalidations(current, evictions); for (String key : evictions) cache.evict(key); } - protected Predicate> getEvictionPredicate(Object object) { + protected Predicate> getEvictionPredicate(Object object) { if (object instanceof CachedRealm) { CachedRealm cached = (CachedRealm)object; return getRealmInvalidationPredicate(cached.getId()); @@ -288,13 +295,13 @@ public class StreamRealmCache { } return null; } - protected Predicate> getInvalidationPredicate(Object object) { + protected Predicate> getInvalidationPredicate(Object object) { if (object instanceof CachedRealm) { CachedRealm cached = (CachedRealm)object; return getRealmRemovalPredicate(cached.getId()); } else if (object instanceof CachedClient) { CachedClient cached = (CachedClient)object; - Predicate> predicate = getClientRemovalPredicate(cached.getRealm(), cached.getId()); + Predicate> predicate = getClientRemovalPredicate(cached.getRealm(), cached.getId()); for (String roleId : cached.getRoles().values()) { predicate.or(getRoleRemovalPredicate(roleId)); } diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/UpdateCounter.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/UpdateCounter.java similarity index 87% rename from model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/UpdateCounter.java rename to model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/UpdateCounter.java index ea086415c9..0c83dc8286 100755 --- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/UpdateCounter.java +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/UpdateCounter.java @@ -1,4 +1,4 @@ -package org.keycloak.models.cache.infinispan.stream; +package org.keycloak.models.cache.infinispan; import java.util.concurrent.atomic.AtomicLong; diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/UserAdapter.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/UserAdapter.java index b8945bd55d..6421ca2fb5 100755 --- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/UserAdapter.java +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/UserAdapter.java @@ -19,7 +19,7 @@ package org.keycloak.models.cache.infinispan; import org.keycloak.models.*; import org.keycloak.models.cache.CacheUserProvider; -import org.keycloak.models.cache.entities.CachedUser; +import org.keycloak.models.cache.infinispan.entities.CachedUser; import org.keycloak.models.utils.KeycloakModelUtils; import java.util.*; diff --git a/server-spi/src/main/java/org/keycloak/models/cache/UserCache.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/UserCache.java similarity index 91% rename from server-spi/src/main/java/org/keycloak/models/cache/UserCache.java rename to model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/UserCache.java index f64c722091..2df2da63e5 100755 --- a/server-spi/src/main/java/org/keycloak/models/cache/UserCache.java +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/UserCache.java @@ -15,9 +15,9 @@ * limitations under the License. */ -package org.keycloak.models.cache; +package org.keycloak.models.cache.infinispan; -import org.keycloak.models.cache.entities.CachedUser; +import org.keycloak.models.cache.infinispan.entities.CachedUser; /** * @author Bill Burke diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/entities/AbstractRevisioned.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/entities/AbstractRevisioned.java similarity index 77% rename from model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/entities/AbstractRevisioned.java rename to model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/entities/AbstractRevisioned.java index dfea429fe9..89166202c5 100755 --- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/entities/AbstractRevisioned.java +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/entities/AbstractRevisioned.java @@ -1,10 +1,12 @@ -package org.keycloak.models.cache.infinispan.stream.entities; +package org.keycloak.models.cache.infinispan.entities; + +import java.io.Serializable; /** * @author Bill Burke * @version $Revision: 1 $ */ -public class AbstractRevisioned implements Revisioned { +public class AbstractRevisioned implements Revisioned, Serializable { private String id; private Long revision; diff --git a/server-spi/src/main/java/org/keycloak/models/cache/entities/CachedClient.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/entities/CachedClient.java similarity index 92% rename from server-spi/src/main/java/org/keycloak/models/cache/entities/CachedClient.java rename to model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/entities/CachedClient.java index 727cabcd66..c528c8c0d2 100755 --- a/server-spi/src/main/java/org/keycloak/models/cache/entities/CachedClient.java +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/entities/CachedClient.java @@ -15,14 +15,14 @@ * limitations under the License. */ -package org.keycloak.models.cache.entities; +package org.keycloak.models.cache.infinispan.entities; import org.keycloak.models.ClientModel; import org.keycloak.models.ProtocolMapperModel; import org.keycloak.models.RealmModel; import org.keycloak.models.RealmProvider; import org.keycloak.models.RoleModel; -import org.keycloak.models.cache.RealmCache; +import org.keycloak.models.cache.infinispan.RealmCache; import java.io.Serializable; import java.util.HashMap; @@ -37,9 +37,7 @@ import java.util.TreeMap; * @author Bill Burke * @version $Revision: 1 $ */ -public class CachedClient implements Serializable { - - protected String id; +public class CachedClient extends AbstractRevisioned implements InRealm { protected String clientId; protected String name; protected String description; @@ -77,8 +75,8 @@ public class CachedClient implements Serializable { protected boolean useTemplateConfig; protected boolean useTemplateMappers; - public CachedClient(RealmCache cache, RealmProvider delegate, RealmModel realm, ClientModel model) { - id = model.getId(); + public CachedClient(Long revision, RealmModel realm, ClientModel model) { + super(revision, model.getId()); clientAuthenticatorType = model.getClientAuthenticatorType(); secret = model.getSecret(); registrationToken = model.getRegistrationToken(); @@ -112,10 +110,10 @@ public class CachedClient implements Serializable { implicitFlowEnabled = model.isImplicitFlowEnabled(); directAccessGrantsEnabled = model.isDirectAccessGrantsEnabled(); serviceAccountsEnabled = model.isServiceAccountsEnabled(); - cacheRoles(cache, realm, model); + cacheRoles(model); nodeReRegistrationTimeout = model.getNodeReRegistrationTimeout(); - registeredNodes = new TreeMap(model.getRegisteredNodes()); + registeredNodes = new TreeMap<>(model.getRegisteredNodes()); if (model.getClientTemplate() != null) { clientTemplate = model.getClientTemplate().getId(); } @@ -124,17 +122,12 @@ public class CachedClient implements Serializable { useTemplateScope = model.useTemplateScope(); } - protected void cacheRoles(RealmCache cache, RealmModel realm, ClientModel model) { + protected void cacheRoles(ClientModel model) { for (RoleModel role : model.getRoles()) { roles.put(role.getName(), role.getId()); - cache.addRole(new CachedClientRole(id, role, realm)); } } - public String getId() { - return id; - } - public String getClientId() { return clientId; } diff --git a/server-spi/src/main/java/org/keycloak/models/cache/entities/CachedClientRole.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/entities/CachedClientRole.java similarity index 79% rename from server-spi/src/main/java/org/keycloak/models/cache/entities/CachedClientRole.java rename to model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/entities/CachedClientRole.java index 3cbfa304e0..1b35672c49 100755 --- a/server-spi/src/main/java/org/keycloak/models/cache/entities/CachedClientRole.java +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/entities/CachedClientRole.java @@ -15,7 +15,7 @@ * limitations under the License. */ -package org.keycloak.models.cache.entities; +package org.keycloak.models.cache.infinispan.entities; import org.keycloak.models.RealmModel; import org.keycloak.models.RoleModel; @@ -24,12 +24,12 @@ import org.keycloak.models.RoleModel; * @author Bill Burke * @version $Revision: 1 $ */ -public class CachedClientRole extends CachedRole { +public class CachedClientRole extends CachedRole implements InClient { private final String clientId; - public CachedClientRole(String clientId, RoleModel model, RealmModel realm) { - super(model, realm); + public CachedClientRole(Long revision, String clientId, RoleModel model, RealmModel realm) { + super(revision, model, realm); this.clientId = clientId; } diff --git a/server-spi/src/main/java/org/keycloak/models/cache/entities/CachedClientTemplate.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/entities/CachedClientTemplate.java similarity index 88% rename from server-spi/src/main/java/org/keycloak/models/cache/entities/CachedClientTemplate.java rename to model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/entities/CachedClientTemplate.java index 755dee14e7..e0f7e8805d 100755 --- a/server-spi/src/main/java/org/keycloak/models/cache/entities/CachedClientTemplate.java +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/entities/CachedClientTemplate.java @@ -15,14 +15,14 @@ * limitations under the License. */ -package org.keycloak.models.cache.entities; +package org.keycloak.models.cache.infinispan.entities; import org.keycloak.models.ClientTemplateModel; import org.keycloak.models.ProtocolMapperModel; import org.keycloak.models.RealmModel; import org.keycloak.models.RealmProvider; import org.keycloak.models.RoleModel; -import org.keycloak.models.cache.RealmCache; +import org.keycloak.models.cache.infinispan.RealmCache; import java.io.Serializable; import java.util.HashMap; @@ -34,9 +34,8 @@ import java.util.Set; * @author Bill Burke * @version $Revision: 1 $ */ -public class CachedClientTemplate implements Serializable { +public class CachedClientTemplate extends AbstractRevisioned implements InRealm { - private String id; private String name; private String description; private String realm; @@ -50,12 +49,12 @@ public class CachedClientTemplate implements Serializable { private boolean implicitFlowEnabled; private boolean directAccessGrantsEnabled; private boolean serviceAccountsEnabled; - private Set scope = new HashSet(); + private Set scope = new HashSet<>(); private Set protocolMappers = new HashSet(); - private Map attributes = new HashMap(); + private Map attributes = new HashMap<>(); - public CachedClientTemplate(RealmCache cache, RealmProvider delegate, RealmModel realm, ClientTemplateModel model) { - id = model.getId(); + public CachedClientTemplate(Long revision, RealmModel realm, ClientTemplateModel model) { + super(revision, model.getId()); name = model.getName(); description = model.getDescription(); this.realm = realm.getId(); @@ -77,10 +76,6 @@ public class CachedClientTemplate implements Serializable { directAccessGrantsEnabled = model.isDirectAccessGrantsEnabled(); serviceAccountsEnabled = model.isServiceAccountsEnabled(); } - public String getId() { - return id; - } - public String getName() { return name; diff --git a/server-spi/src/main/java/org/keycloak/models/cache/entities/CachedGroup.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/entities/CachedGroup.java similarity index 89% rename from server-spi/src/main/java/org/keycloak/models/cache/entities/CachedGroup.java rename to model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/entities/CachedGroup.java index b898fa13d2..b29125a88c 100755 --- a/server-spi/src/main/java/org/keycloak/models/cache/entities/CachedGroup.java +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/entities/CachedGroup.java @@ -15,7 +15,7 @@ * limitations under the License. */ -package org.keycloak.models.cache.entities; +package org.keycloak.models.cache.infinispan.entities; import org.keycloak.common.util.MultivaluedHashMap; import org.keycloak.models.GroupModel; @@ -30,8 +30,7 @@ import java.util.Set; * @author Bill Burke * @version $Revision: 1 $ */ -public class CachedGroup implements Serializable { - private String id; +public class CachedGroup extends AbstractRevisioned implements InRealm { private String realm; private String name; private String parentId; @@ -39,8 +38,8 @@ public class CachedGroup implements Serializable { private Set roleMappings = new HashSet<>(); private Set subGroups = new HashSet<>(); - public CachedGroup(RealmModel realm, GroupModel group) { - this.id = group.getId(); + public CachedGroup(Long revision, RealmModel realm, GroupModel group) { + super(revision, group.getId()); this.realm = realm.getId(); this.name = group.getName(); this.parentId = group.getParentId(); @@ -57,10 +56,6 @@ public class CachedGroup implements Serializable { } } - public String getId() { - return id; - } - public String getRealm() { return realm; } diff --git a/server-spi/src/main/java/org/keycloak/models/cache/entities/CachedRealm.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/entities/CachedRealm.java similarity index 94% rename from server-spi/src/main/java/org/keycloak/models/cache/entities/CachedRealm.java rename to model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/entities/CachedRealm.java index a037d0549b..d5e02a227e 100755 --- a/server-spi/src/main/java/org/keycloak/models/cache/entities/CachedRealm.java +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/entities/CachedRealm.java @@ -15,7 +15,7 @@ * limitations under the License. */ -package org.keycloak.models.cache.entities; +package org.keycloak.models.cache.infinispan.entities; import org.keycloak.common.enums.SslRequired; import org.keycloak.models.AuthenticationExecutionModel; @@ -35,7 +35,7 @@ import org.keycloak.models.RequiredCredentialModel; import org.keycloak.models.RoleModel; import org.keycloak.models.UserFederationMapperModel; import org.keycloak.models.UserFederationProviderModel; -import org.keycloak.models.cache.RealmCache; +import org.keycloak.models.cache.infinispan.RealmCache; import org.keycloak.common.util.MultivaluedHashMap; import java.io.Serializable; @@ -56,9 +56,8 @@ import java.util.Set; * @author Bill Burke * @version $Revision: 1 $ */ -public class CachedRealm implements Serializable { +public class CachedRealm extends AbstractRevisioned { - protected String id; protected String name; protected String displayName; protected String displayNameHtml; @@ -155,11 +154,8 @@ public class CachedRealm implements Serializable { protected MultivaluedHashMap identityProviderMappers = new MultivaluedHashMap<>(); protected Set identityProviderMapperSet; - public CachedRealm() { - } - - public CachedRealm(RealmCache cache, RealmProvider delegate, RealmModel model) { - id = model.getId(); + public CachedRealm(Long revision, RealmModel model) { + super(revision, model.getId()); name = model.getName(); displayName = model.getDisplayName(); displayNameHtml = model.getDisplayNameHtml(); @@ -244,11 +240,11 @@ public class CachedRealm implements Serializable { ClientModel masterAdminClient = model.getMasterAdminClient(); this.masterAdminClient = (masterAdminClient != null) ? masterAdminClient.getId() : null; - cacheRealmRoles(cache, model); + cacheRealmRoles(model); - cacheClients(cache, delegate, model); + cacheClients(model); - cacheClientTemplates(cache, delegate, model); + cacheClientTemplates(model); internationalizationEnabled = model.isInternationalizationEnabled(); supportedLocales = model.getSupportedLocales(); @@ -286,35 +282,25 @@ public class CachedRealm implements Serializable { } - protected void cacheClientTemplates(RealmCache cache, RealmProvider delegate, RealmModel model) { + protected void cacheClientTemplates(RealmModel model) { for (ClientTemplateModel template : model.getClientTemplates()) { clientTemplates.add(template.getId()); - CachedClientTemplate cachedClient = new CachedClientTemplate(cache, delegate, model, template); - cache.addClientTemplate(cachedClient); } } - protected void cacheClients(RealmCache cache, RealmProvider delegate, RealmModel model) { + protected void cacheClients(RealmModel model) { for (ClientModel client : model.getClients()) { clients.add(client.getId()); - CachedClient cachedClient = new CachedClient(cache, delegate, model, client); - cache.addClient(cachedClient); } } - protected void cacheRealmRoles(RealmCache cache, RealmModel model) { + protected void cacheRealmRoles(RealmModel model) { for (RoleModel role : model.getRoles()) { realmRoles.put(role.getName(), role.getId()); - CachedRole cachedRole = new CachedRealmRole(role, model); - cache.addRole(cachedRole); } } - public String getId() { - return id; - } - public String getMasterAdminClient() { return masterAdminClient; } diff --git a/server-spi/src/main/java/org/keycloak/models/cache/entities/CachedRealmRole.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/entities/CachedRealmRole.java similarity index 84% rename from server-spi/src/main/java/org/keycloak/models/cache/entities/CachedRealmRole.java rename to model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/entities/CachedRealmRole.java index fa3d578fa4..ac36e1100b 100755 --- a/server-spi/src/main/java/org/keycloak/models/cache/entities/CachedRealmRole.java +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/entities/CachedRealmRole.java @@ -15,7 +15,7 @@ * limitations under the License. */ -package org.keycloak.models.cache.entities; +package org.keycloak.models.cache.infinispan.entities; import org.keycloak.models.RealmModel; import org.keycloak.models.RoleModel; @@ -27,8 +27,8 @@ import org.keycloak.models.RoleModel; public class CachedRealmRole extends CachedRole { - public CachedRealmRole(RoleModel model, RealmModel realm) { - super(model, realm); + public CachedRealmRole(Long revision, RoleModel model, RealmModel realm) { + super(revision, model, realm); } diff --git a/server-spi/src/main/java/org/keycloak/models/cache/entities/CachedRole.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/entities/CachedRole.java similarity index 88% rename from server-spi/src/main/java/org/keycloak/models/cache/entities/CachedRole.java rename to model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/entities/CachedRole.java index 8ffc4ffe5a..44a5dc2ba7 100755 --- a/server-spi/src/main/java/org/keycloak/models/cache/entities/CachedRole.java +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/entities/CachedRole.java @@ -15,7 +15,7 @@ * limitations under the License. */ -package org.keycloak.models.cache.entities; +package org.keycloak.models.cache.infinispan.entities; import org.keycloak.models.RealmModel; import org.keycloak.models.RoleModel; @@ -28,9 +28,8 @@ import java.util.Set; * @author Bill Burke * @version $Revision: 1 $ */ -public class CachedRole implements Serializable { +public class CachedRole extends AbstractRevisioned implements InRealm { - final protected String id; final protected String name; final protected String realm; final protected String description; @@ -38,10 +37,10 @@ public class CachedRole implements Serializable { final protected boolean composite; final protected Set composites = new HashSet(); - public CachedRole(RoleModel model, RealmModel realm) { + public CachedRole(Long revision, RoleModel model, RealmModel realm) { + super(revision, model.getId()); composite = model.isComposite(); description = model.getDescription(); - id = model.getId(); name = model.getName(); scopeParamRequired = model.isScopeParamRequired(); this.realm = realm.getId(); @@ -53,10 +52,6 @@ public class CachedRole implements Serializable { } - public String getId() { - return id; - } - public String getName() { return name; } diff --git a/server-spi/src/main/java/org/keycloak/models/cache/entities/CachedUser.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/entities/CachedUser.java similarity index 98% rename from server-spi/src/main/java/org/keycloak/models/cache/entities/CachedUser.java rename to model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/entities/CachedUser.java index 501d3cc8bb..c1bf4cd56a 100755 --- a/server-spi/src/main/java/org/keycloak/models/cache/entities/CachedUser.java +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/entities/CachedUser.java @@ -15,7 +15,7 @@ * limitations under the License. */ -package org.keycloak.models.cache.entities; +package org.keycloak.models.cache.infinispan.entities; import org.keycloak.models.GroupModel; import org.keycloak.models.RealmModel; diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/ClientListQuery.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/entities/ClientListQuery.java similarity index 90% rename from model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/ClientListQuery.java rename to model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/entities/ClientListQuery.java index 1a7d5e2d05..4fc650d6c2 100755 --- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/ClientListQuery.java +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/entities/ClientListQuery.java @@ -1,7 +1,6 @@ -package org.keycloak.models.cache.infinispan.stream; +package org.keycloak.models.cache.infinispan.entities; import org.keycloak.models.RealmModel; -import org.keycloak.models.cache.infinispan.stream.entities.AbstractRevisioned; import java.util.HashSet; import java.util.Set; diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/ClientQuery.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/entities/ClientQuery.java similarity index 58% rename from model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/ClientQuery.java rename to model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/entities/ClientQuery.java index 399ec693ed..e58b9211cc 100755 --- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/ClientQuery.java +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/entities/ClientQuery.java @@ -1,8 +1,7 @@ -package org.keycloak.models.cache.infinispan.stream; +package org.keycloak.models.cache.infinispan.entities; -import org.keycloak.models.cache.infinispan.stream.entities.InRealm; +import org.keycloak.models.cache.infinispan.entities.InRealm; -import java.util.List; import java.util.Set; /** diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/ClientTemplateQuery.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/entities/ClientTemplateQuery.java similarity index 63% rename from model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/ClientTemplateQuery.java rename to model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/entities/ClientTemplateQuery.java index e63cb67de4..e07f7ab1eb 100755 --- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/ClientTemplateQuery.java +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/entities/ClientTemplateQuery.java @@ -1,6 +1,6 @@ -package org.keycloak.models.cache.infinispan.stream; +package org.keycloak.models.cache.infinispan.entities; -import org.keycloak.models.cache.infinispan.stream.entities.InRealm; +import org.keycloak.models.cache.infinispan.entities.InRealm; import java.util.Set; diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/GroupQuery.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/entities/GroupQuery.java similarity index 62% rename from model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/GroupQuery.java rename to model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/entities/GroupQuery.java index b3d86c0c93..905d271399 100755 --- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/GroupQuery.java +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/entities/GroupQuery.java @@ -1,6 +1,6 @@ -package org.keycloak.models.cache.infinispan.stream; +package org.keycloak.models.cache.infinispan.entities; -import org.keycloak.models.cache.infinispan.stream.entities.InRealm; +import org.keycloak.models.cache.infinispan.entities.InRealm; import java.util.Set; diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/entities/InClient.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/entities/InClient.java similarity index 73% rename from model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/entities/InClient.java rename to model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/entities/InClient.java index 3951c7f5c2..464dbaf98d 100755 --- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/entities/InClient.java +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/entities/InClient.java @@ -1,4 +1,4 @@ -package org.keycloak.models.cache.infinispan.stream.entities; +package org.keycloak.models.cache.infinispan.entities; /** * @author Bill Burke diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/entities/InRealm.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/entities/InRealm.java similarity index 73% rename from model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/entities/InRealm.java rename to model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/entities/InRealm.java index 6b550911aa..8a880ecac4 100755 --- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/entities/InRealm.java +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/entities/InRealm.java @@ -1,4 +1,4 @@ -package org.keycloak.models.cache.infinispan.stream.entities; +package org.keycloak.models.cache.infinispan.entities; /** * @author Bill Burke diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/RealmListQuery.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/entities/RealmListQuery.java similarity index 82% rename from model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/RealmListQuery.java rename to model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/entities/RealmListQuery.java index 22a615caf2..446fe58f36 100755 --- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/RealmListQuery.java +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/entities/RealmListQuery.java @@ -1,6 +1,4 @@ -package org.keycloak.models.cache.infinispan.stream; - -import org.keycloak.models.cache.infinispan.stream.entities.AbstractRevisioned; +package org.keycloak.models.cache.infinispan.entities; import java.util.HashSet; import java.util.Set; diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/RealmQuery.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/entities/RealmQuery.java similarity index 60% rename from model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/RealmQuery.java rename to model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/entities/RealmQuery.java index 210978fb15..612e95b60d 100755 --- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/RealmQuery.java +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/entities/RealmQuery.java @@ -1,6 +1,4 @@ -package org.keycloak.models.cache.infinispan.stream; - -import org.keycloak.models.cache.infinispan.stream.entities.InRealm; +package org.keycloak.models.cache.infinispan.entities; import java.util.Set; diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/entities/Revisioned.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/entities/Revisioned.java similarity index 77% rename from model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/entities/Revisioned.java rename to model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/entities/Revisioned.java index c0b136f78e..639f4de642 100755 --- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/entities/Revisioned.java +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/entities/Revisioned.java @@ -1,4 +1,4 @@ -package org.keycloak.models.cache.infinispan.stream.entities; +package org.keycloak.models.cache.infinispan.entities; /** * @author Bill Burke diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/RoleQuery.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/entities/RoleQuery.java similarity index 62% rename from model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/RoleQuery.java rename to model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/entities/RoleQuery.java index 0fcb78a98b..6635831850 100755 --- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/RoleQuery.java +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/entities/RoleQuery.java @@ -1,6 +1,6 @@ -package org.keycloak.models.cache.infinispan.stream; +package org.keycloak.models.cache.infinispan.entities; -import org.keycloak.models.cache.infinispan.stream.entities.InRealm; +import org.keycloak.models.cache.infinispan.entities.InRealm; import java.util.Set; diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/ClientQueryPredicate.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/ClientQueryPredicate.java index 1e0c555519..bf4ade8156 100755 --- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/ClientQueryPredicate.java +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/ClientQueryPredicate.java @@ -1,6 +1,8 @@ package org.keycloak.models.cache.infinispan.stream; import org.jboss.logging.Logger; +import org.keycloak.models.cache.infinispan.entities.ClientQuery; +import org.keycloak.models.cache.infinispan.entities.Revisioned; import java.io.Serializable; import java.util.Map; @@ -10,7 +12,7 @@ import java.util.function.Predicate; * @author Bill Burke * @version $Revision: 1 $ */ -public class ClientQueryPredicate implements Predicate>, Serializable { +public class ClientQueryPredicate implements Predicate>, Serializable { protected static final Logger logger = Logger.getLogger(ClientQueryPredicate.class); private String client; private String inRealm; @@ -34,7 +36,7 @@ public class ClientQueryPredicate implements Predicate @Override - public boolean test(Map.Entry entry) { + public boolean test(Map.Entry entry) { Object value = entry.getValue(); if (value == null) return false; if (!(value instanceof ClientQuery)) return false; diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/ClientTemplateQueryPredicate.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/ClientTemplateQueryPredicate.java index ebf4b6ce63..fba0c02ff6 100755 --- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/ClientTemplateQueryPredicate.java +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/ClientTemplateQueryPredicate.java @@ -1,5 +1,8 @@ package org.keycloak.models.cache.infinispan.stream; +import org.keycloak.models.cache.infinispan.entities.ClientTemplateQuery; +import org.keycloak.models.cache.infinispan.entities.Revisioned; + import java.io.Serializable; import java.util.Map; import java.util.function.Predicate; @@ -8,7 +11,7 @@ import java.util.function.Predicate; * @author Bill Burke * @version $Revision: 1 $ */ -public class ClientTemplateQueryPredicate implements Predicate>, Serializable { +public class ClientTemplateQueryPredicate implements Predicate>, Serializable { private String template; public static ClientTemplateQueryPredicate create() { @@ -25,7 +28,7 @@ public class ClientTemplateQueryPredicate implements Predicate entry) { + public boolean test(Map.Entry entry) { Object value = entry.getValue(); if (value == null) return false; if (!(value instanceof ClientTemplateQuery)) return false; diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/GroupQueryPredicate.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/GroupQueryPredicate.java index 6e4a662969..855930e0d3 100755 --- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/GroupQueryPredicate.java +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/GroupQueryPredicate.java @@ -1,5 +1,8 @@ package org.keycloak.models.cache.infinispan.stream; +import org.keycloak.models.cache.infinispan.entities.GroupQuery; +import org.keycloak.models.cache.infinispan.entities.Revisioned; + import java.io.Serializable; import java.util.Map; import java.util.function.Predicate; @@ -8,7 +11,7 @@ import java.util.function.Predicate; * @author Bill Burke * @version $Revision: 1 $ */ -public class GroupQueryPredicate implements Predicate>, Serializable { +public class GroupQueryPredicate implements Predicate>, Serializable { private String group; public static GroupQueryPredicate create() { @@ -25,7 +28,7 @@ public class GroupQueryPredicate implements Predicate> @Override - public boolean test(Map.Entry entry) { + public boolean test(Map.Entry entry) { Object value = entry.getValue(); if (value == null) return false; if (!(value instanceof GroupQuery)) return false; diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/HasRolePredicate.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/HasRolePredicate.java index 5946726ae7..c4a56638b5 100755 --- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/HasRolePredicate.java +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/HasRolePredicate.java @@ -1,7 +1,8 @@ package org.keycloak.models.cache.infinispan.stream; -import org.keycloak.models.cache.entities.CachedGroup; -import org.keycloak.models.cache.entities.CachedRole; +import org.keycloak.models.cache.infinispan.entities.CachedGroup; +import org.keycloak.models.cache.infinispan.entities.CachedRole; +import org.keycloak.models.cache.infinispan.entities.Revisioned; import java.io.Serializable; import java.util.Map; @@ -11,7 +12,7 @@ import java.util.function.Predicate; * @author Bill Burke * @version $Revision: 1 $ */ -public class HasRolePredicate implements Predicate>, Serializable { +public class HasRolePredicate implements Predicate>, Serializable { private String role; public static HasRolePredicate create() { @@ -24,7 +25,7 @@ public class HasRolePredicate implements Predicate>, S } @Override - public boolean test(Map.Entry entry) { + public boolean test(Map.Entry entry) { Object value = entry.getValue(); if (value == null) return false; if (value instanceof CachedRole) { diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/InClientPredicate.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/InClientPredicate.java index ee5343f841..a582f34f27 100755 --- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/InClientPredicate.java +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/InClientPredicate.java @@ -1,7 +1,7 @@ package org.keycloak.models.cache.infinispan.stream; -import org.keycloak.models.cache.infinispan.stream.entities.InClient; -import org.keycloak.models.cache.infinispan.stream.entities.InRealm; +import org.keycloak.models.cache.infinispan.entities.InClient; +import org.keycloak.models.cache.infinispan.entities.Revisioned; import java.io.Serializable; import java.util.Map; @@ -11,7 +11,7 @@ import java.util.function.Predicate; * @author Bill Burke * @version $Revision: 1 $ */ -public class InClientPredicate implements Predicate>, Serializable { +public class InClientPredicate implements Predicate>, Serializable { private String clientId; public static InClientPredicate create() { @@ -24,7 +24,7 @@ public class InClientPredicate implements Predicate>, } @Override - public boolean test(Map.Entry entry) { + public boolean test(Map.Entry entry) { Object value = entry.getValue(); if (value == null) return false; if (!(value instanceof InClient)) return false; diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/InRealmPredicate.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/InRealmPredicate.java index 265e4d2655..d24a9bd142 100755 --- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/InRealmPredicate.java +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/InRealmPredicate.java @@ -1,6 +1,7 @@ package org.keycloak.models.cache.infinispan.stream; -import org.keycloak.models.cache.infinispan.stream.entities.InRealm; +import org.keycloak.models.cache.infinispan.entities.InRealm; +import org.keycloak.models.cache.infinispan.entities.Revisioned; import java.io.Serializable; import java.util.Map; @@ -10,7 +11,7 @@ import java.util.function.Predicate; * @author Bill Burke * @version $Revision: 1 $ */ -public class InRealmPredicate implements Predicate>, Serializable { +public class InRealmPredicate implements Predicate>, Serializable { private String realm; public static InRealmPredicate create() { @@ -23,7 +24,7 @@ public class InRealmPredicate implements Predicate>, S } @Override - public boolean test(Map.Entry entry) { + public boolean test(Map.Entry entry) { Object value = entry.getValue(); if (value == null) return false; if (!(value instanceof InRealm)) return false; diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/RealmQueryPredicate.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/RealmQueryPredicate.java index 179c7da043..dbb64f5b79 100755 --- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/RealmQueryPredicate.java +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/RealmQueryPredicate.java @@ -1,5 +1,8 @@ package org.keycloak.models.cache.infinispan.stream; +import org.keycloak.models.cache.infinispan.entities.RealmQuery; +import org.keycloak.models.cache.infinispan.entities.Revisioned; + import java.io.Serializable; import java.util.Map; import java.util.function.Predicate; @@ -8,7 +11,7 @@ import java.util.function.Predicate; * @author Bill Burke * @version $Revision: 1 $ */ -public class RealmQueryPredicate implements Predicate>, Serializable { +public class RealmQueryPredicate implements Predicate>, Serializable { private String realm; public static RealmQueryPredicate create() { @@ -25,7 +28,7 @@ public class RealmQueryPredicate implements Predicate> @Override - public boolean test(Map.Entry entry) { + public boolean test(Map.Entry entry) { Object value = entry.getValue(); if (value == null) return false; if (!(value instanceof RealmQuery)) return false; diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/RoleQueryPredicate.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/RoleQueryPredicate.java index 3320963d30..5e37d59e60 100755 --- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/RoleQueryPredicate.java +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/RoleQueryPredicate.java @@ -1,5 +1,8 @@ package org.keycloak.models.cache.infinispan.stream; +import org.keycloak.models.cache.infinispan.entities.Revisioned; +import org.keycloak.models.cache.infinispan.entities.RoleQuery; + import java.io.Serializable; import java.util.Map; import java.util.function.Predicate; @@ -8,7 +11,7 @@ import java.util.function.Predicate; * @author Bill Burke * @version $Revision: 1 $ */ -public class RoleQueryPredicate implements Predicate>, Serializable { +public class RoleQueryPredicate implements Predicate>, Serializable { private String role; public static RoleQueryPredicate create() { @@ -25,7 +28,7 @@ public class RoleQueryPredicate implements Predicate>, @Override - public boolean test(Map.Entry entry) { + public boolean test(Map.Entry entry) { Object value = entry.getValue(); if (value == null) return false; if (!(value instanceof RoleQuery)) return false; diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/entities/RevisionedCachedClient.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/entities/RevisionedCachedClient.java deleted file mode 100755 index f2ee892809..0000000000 --- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/entities/RevisionedCachedClient.java +++ /dev/null @@ -1,39 +0,0 @@ -package org.keycloak.models.cache.infinispan.stream.entities; - -import org.keycloak.models.ClientModel; -import org.keycloak.models.RealmModel; -import org.keycloak.models.RealmProvider; -import org.keycloak.models.RoleModel; -import org.keycloak.models.cache.RealmCache; -import org.keycloak.models.cache.entities.CachedClient; - -/** - * @author Bill Burke - * @version $Revision: 1 $ - */ -public class RevisionedCachedClient extends CachedClient implements Revisioned, InRealm { - - public RevisionedCachedClient(Long revision, RealmCache cache, RealmProvider delegate, RealmModel realm, ClientModel model) { - super(cache, delegate, realm, model); - this.revision = revision; - } - - private Long revision; - - @Override - public Long getRevision() { - return revision; - } - - @Override - public void setRevision(Long revision) { - this.revision = revision; - } - - @Override - protected void cacheRoles(RealmCache cache, RealmModel realm, ClientModel model) { - for (RoleModel role : model.getRoles()) { - roles.put(role.getName(), role.getId()); - } - } -} diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/entities/RevisionedCachedClientRole.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/entities/RevisionedCachedClientRole.java deleted file mode 100755 index bad2ffec37..0000000000 --- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/entities/RevisionedCachedClientRole.java +++ /dev/null @@ -1,31 +0,0 @@ -package org.keycloak.models.cache.infinispan.stream.entities; - -import org.keycloak.models.RealmModel; -import org.keycloak.models.RoleModel; -import org.keycloak.models.cache.entities.CachedClientRole; - -/** - * @author Bill Burke - * @version $Revision: 1 $ - */ -public class RevisionedCachedClientRole extends CachedClientRole implements Revisioned, InClient { - - public RevisionedCachedClientRole(Long revision, String idClient, RoleModel model, RealmModel realm) { - super(idClient, model, realm); - this.revision = revision; - } - - private Long revision; - - @Override - public Long getRevision() { - return revision; - } - - @Override - public void setRevision(Long revision) { - this.revision = revision; - } - - -} diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/entities/RevisionedCachedClientTemplate.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/entities/RevisionedCachedClientTemplate.java deleted file mode 100755 index ad3ac44e1d..0000000000 --- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/entities/RevisionedCachedClientTemplate.java +++ /dev/null @@ -1,33 +0,0 @@ -package org.keycloak.models.cache.infinispan.stream.entities; - -import org.keycloak.models.ClientTemplateModel; -import org.keycloak.models.RealmModel; -import org.keycloak.models.RealmProvider; -import org.keycloak.models.cache.RealmCache; -import org.keycloak.models.cache.entities.CachedClientTemplate; - -/** - * @author Bill Burke - * @version $Revision: 1 $ - */ -public class RevisionedCachedClientTemplate extends CachedClientTemplate implements Revisioned, InRealm { - - public RevisionedCachedClientTemplate(Long revision, RealmCache cache, RealmProvider delegate, RealmModel realm, ClientTemplateModel model) { - super(cache, delegate, realm, model); - this.revision = revision; - } - - private Long revision; - - @Override - public Long getRevision() { - return revision; - } - - @Override - public void setRevision(Long revision) { - this.revision = revision; - } - - -} diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/entities/RevisionedCachedGroup.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/entities/RevisionedCachedGroup.java deleted file mode 100755 index 98ba32f20e..0000000000 --- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/entities/RevisionedCachedGroup.java +++ /dev/null @@ -1,30 +0,0 @@ -package org.keycloak.models.cache.infinispan.stream.entities; - -import org.keycloak.models.GroupModel; -import org.keycloak.models.RealmModel; -import org.keycloak.models.cache.entities.CachedGroup; - -/** - * @author Bill Burke - * @version $Revision: 1 $ - */ -public class RevisionedCachedGroup extends CachedGroup implements Revisioned, InRealm { - public RevisionedCachedGroup(Long revision, RealmModel realm, GroupModel group) { - super(realm, group); - this.revision = revision; - } - - private Long revision; - - @Override - public Long getRevision() { - return revision; - } - - @Override - public void setRevision(Long revision) { - this.revision = revision; - } - - -} diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/entities/RevisionedCachedRealm.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/entities/RevisionedCachedRealm.java deleted file mode 100755 index c1f91ac1f5..0000000000 --- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/entities/RevisionedCachedRealm.java +++ /dev/null @@ -1,54 +0,0 @@ -package org.keycloak.models.cache.infinispan.stream.entities; - -import org.keycloak.models.ClientModel; -import org.keycloak.models.ClientTemplateModel; -import org.keycloak.models.RealmModel; -import org.keycloak.models.RealmProvider; -import org.keycloak.models.RoleModel; -import org.keycloak.models.cache.RealmCache; -import org.keycloak.models.cache.entities.CachedRealm; - -/** - * @author Bill Burke - * @version $Revision: 1 $ - */ -public class RevisionedCachedRealm extends CachedRealm implements Revisioned { - - public RevisionedCachedRealm(Long revision, RealmCache cache, RealmProvider delegate, RealmModel model) { - super(cache, delegate, model); - this.revision = revision; - } - - private Long revision; - - @Override - public Long getRevision() { - return revision; - } - - @Override - public void setRevision(Long revision) { - this.revision = revision; - } - - @Override - protected void cacheClientTemplates(RealmCache cache, RealmProvider delegate, RealmModel model) { - for (ClientTemplateModel template : model.getClientTemplates()) { - clientTemplates.add(template.getId()); - } - } - - @Override - protected void cacheClients(RealmCache cache, RealmProvider delegate, RealmModel model) { - for (ClientModel client : model.getClients()) { - clients.add(client.getId()); - } - } - - @Override - protected void cacheRealmRoles(RealmCache cache, RealmModel model) { - for (RoleModel role : model.getRoles()) { - realmRoles.put(role.getName(), role.getId()); - } - } -} diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/entities/RevisionedCachedRealmRole.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/entities/RevisionedCachedRealmRole.java deleted file mode 100755 index 6685a3ea74..0000000000 --- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/entities/RevisionedCachedRealmRole.java +++ /dev/null @@ -1,30 +0,0 @@ -package org.keycloak.models.cache.infinispan.stream.entities; - -import org.keycloak.models.RealmModel; -import org.keycloak.models.RoleModel; -import org.keycloak.models.cache.entities.CachedRealmRole; - -/** - * @author Bill Burke - * @version $Revision: 1 $ - */ -public class RevisionedCachedRealmRole extends CachedRealmRole implements Revisioned, InRealm { - - public RevisionedCachedRealmRole(Long revision, RoleModel model, RealmModel realm) { - super(model, realm); - this.revision = revision; - } - - private Long revision; - - @Override - public Long getRevision() { - return revision; - } - - @Override - public void setRevision(Long revision) { - this.revision = revision; - } - -} diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/entities/RevisionedCachedUser.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/entities/RevisionedCachedUser.java deleted file mode 100755 index e6135e9bd7..0000000000 --- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/entities/RevisionedCachedUser.java +++ /dev/null @@ -1,29 +0,0 @@ -package org.keycloak.models.cache.infinispan.stream.entities; - -import org.keycloak.models.RealmModel; -import org.keycloak.models.UserModel; -import org.keycloak.models.cache.entities.CachedUser; - -/** - * @author Bill Burke - * @version $Revision: 1 $ - */ -public class RevisionedCachedUser extends CachedUser implements Revisioned, InRealm { - public RevisionedCachedUser(Long revision, RealmModel realm, UserModel user) { - super(realm, user); - this.revision = revision; - } - - private Long revision; - - @Override - public Long getRevision() { - return revision; - } - - @Override - public void setRevision(Long revision) { - this.revision = revision; - } - -} From 1511f7088f633f0c1ace02fa002389dcb53d59f1 Mon Sep 17 00:00:00 2001 From: Bill Burke Date: Fri, 19 Feb 2016 17:08:45 -0500 Subject: [PATCH 3/5] javadoc --- .../infinispan/StreamCacheRealmProvider.java | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/StreamCacheRealmProvider.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/StreamCacheRealmProvider.java index d21599c196..0a50575c94 100755 --- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/StreamCacheRealmProvider.java +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/StreamCacheRealmProvider.java @@ -49,6 +49,50 @@ import java.util.Set; /** + * - the high level architecture of this cache is an invalidation cache. + * - the cache is manual/custom versioned. When a model is updated, we remove it from the cache + * which causes an invalidation message to be sent across the cluster. + * - We had to do it this way because Infinispan REPEATABLE_READ + * wouldn't cut it in invalidation mode. Also, REPEATABLE_READ doesn't work very well on relationships and items that are + * not in the cache. + * - There are two Infinispan caches. One clustered that holds actual objects and a another local one that holds revision + * numbers of cached objects. Whenever a cached object is removed (invalidated), the local revision + * cache number or that key is bumped higher based on a local version counter. Whenever a cache entry is fetched, this + * revision number is also fetched and compared against the revision number in the cache entry to see if the cache entry + * is stale. Whenever a cache entry is added, this revision number is also checked against the revision cache. + * - Revision entries are actually never removed (although they could be evicted by cache eviction policies). The reason for this + * is that it is possible for a stale object to be inserted if one thread loads and the data is updated in the database before + * it is added to the cache. So, we keep the version number around for this. + * - In a transaction, objects are registered to be invalidated. If an object is marked for invalidation within a transaction + * a cached object should never be returned. An DB adapter should always be returned. + * - At prepare phase of the transaction, a local lock on the revision cache will be obtained for each object marked for invalidation + * we sort the list of these keys to order local acquisition and avoid deadlocks. + * - After DB commits, the objects marked for invalidation are invalidated, or rather removed from the cache. At this time + * the revision cache entry for this object has its version number bumped. + * - Whenever an object is marked for invalidation, the cache is also searched for any objects that are related to this object + * and need to also be evicted/removed. We use the Infinispan Stream SPI for this. + * + * ClientList caches: + * - lists of clients are cached in a specific cache entry i.e. realm clients, find client by clientId + * - realm client lists need to be invalidated and evited whenever a client is added or removed from a realm. RealmProvider + * now has addClient/removeClient at its top level. All adapaters should use these methods so that the appropriate invalidations + * can be registered. + * - whenever a client is added/removed the realm of the client is added to a clientListInvalidations set + * this set must be checked before sending back or caching a cached query. This check is required to + * avoid caching an uncommitted removal/add in a query cache. + * - when a client is removed, any queries that contain that client must also be removed. + * - a client removal will also cause anything that is contained and cached within that client to be removed + * + * Clustered caches: + * - There is a Infinispan @Listener registered. If an invalidation event happens, this is treated like + * the object was removed from the database and will perform evictions based on that assumption. + * - Eviction events will also cascade other evictions, but not assume this is a db removal. + * + * Groups and Roles: + * - roles are tricky because of composites. Composite lists are cached too. So, when a role is removed + * we also iterate and invalidate any role or group that contains that role being removed. + * + * * * - any relationship should be resolved from session.realms(). For example if JPA.getClientByClientId() is invoked, * JPA should find the id of the client and then call session.realms().getClientById(). THis is to ensure that the cached From daa09f9a41ddef6006a65cca19521ecdc06eedba Mon Sep 17 00:00:00 2001 From: Bill Burke Date: Sat, 20 Feb 2016 09:40:04 -0500 Subject: [PATCH 4/5] more fine tuning --- .../infinispan/StreamCacheRealmProvider.java | 18 ++++++++++--- .../cache/infinispan/StreamRealmCache.java | 27 +++++-------------- .../ClusteredCacheBehaviorTest.java | 11 +++----- 3 files changed, 24 insertions(+), 32 deletions(-) diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/StreamCacheRealmProvider.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/StreamCacheRealmProvider.java index 0a50575c94..def9b83922 100755 --- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/StreamCacheRealmProvider.java +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/StreamCacheRealmProvider.java @@ -313,7 +313,7 @@ public class StreamCacheRealmProvider implements CacheRealmProvider { @Override public RealmModel getRealmByName(String name) { - String cacheKey = "realm.query.by.name." + name; + String cacheKey = getRealmByNameCacheKey(name); RealmListQuery query = cache.get(cacheKey, RealmListQuery.class); if (query != null) { logger.tracev("realm by name cache hit: {0}", name); @@ -337,6 +337,10 @@ public class StreamCacheRealmProvider implements CacheRealmProvider { } } + public String getRealmByNameCacheKey(String name) { + return "realm.query.by.name." + name; + } + @Override public List getRealms() { // Retrieve realms from backend @@ -353,9 +357,11 @@ public class StreamCacheRealmProvider implements CacheRealmProvider { @Override public boolean removeRealm(String id) { - if (getRealm(id) == null) return false; + RealmModel realm = getRealm(id); + if (realm == null) return false; invalidations.add(getRealmClientsQueryCacheKey(id)); + invalidations.add(getRealmByNameCacheKey(realm.getName())); cache.invalidateObject(id); cache.realmRemoval(id, invalidations); return getDelegate().removeRealm(id); @@ -379,6 +385,7 @@ public class StreamCacheRealmProvider implements CacheRealmProvider { invalidations.add(getRealmClientsQueryCacheKey(realm.getId())); invalidations.add(client.getId()); cache.clientAdded(realm.getId(), client.getId(), invalidations); + // this is needed so that a new client that hasn't been committed isn't cached in a query clientListInvalidations.add(realm.getId()); return client; } @@ -429,6 +436,7 @@ public class StreamCacheRealmProvider implements CacheRealmProvider { if (client == null) return false; // need to invalidate realm client query cache every time client list is changed invalidations.add(getRealmClientsQueryCacheKey(realm.getId())); + invalidations.add(getClientByClientIdCacheKey(client.getClientId(), realm)); clientListInvalidations.add(realm.getId()); registerClientInvalidation(id); cache.clientRemoval(realm.getId(), id, invalidations); @@ -527,7 +535,7 @@ public class StreamCacheRealmProvider implements CacheRealmProvider { @Override public ClientModel getClientByClientId(String clientId, RealmModel realm) { - String cacheKey = realm.getId() + ".client.query.by.clientId." + clientId; + String cacheKey = getClientByClientIdCacheKey(clientId, realm); ClientListQuery query = cache.get(cacheKey, ClientListQuery.class); String id = null; @@ -555,6 +563,10 @@ public class StreamCacheRealmProvider implements CacheRealmProvider { return getClientById(id, realm); } + public String getClientByClientIdCacheKey(String clientId, RealmModel realm) { + return realm.getId() + ".client.query.by.clientId." + clientId; + } + @Override public ClientTemplateModel getClientTemplateById(String id, RealmModel realm) { CachedClientTemplate cached = cache.get(id, CachedClientTemplate.class); diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/StreamRealmCache.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/StreamRealmCache.java index da292a1d56..027793ef0b 100755 --- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/StreamRealmCache.java +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/StreamRealmCache.java @@ -146,6 +146,9 @@ public class StreamRealmCache { } } + + + public void clear() { cache.clear(); } @@ -253,7 +256,7 @@ public class StreamRealmCache { @CacheEntryInvalidated public void cacheInvalidated(CacheEntryInvalidatedEvent event) { - if (event.isPre()) { + if (!event.isPre()) { Object object = event.getValue(); if (object != null) { Predicate> predicate = getInvalidationPredicate(object); @@ -264,8 +267,9 @@ public class StreamRealmCache { @CacheEntriesEvicted public void cacheEvicted(CacheEntriesEvictedEvent event) { + if (!event.isPre()) for (Object object : event.getEntries().values()) { - Predicate> predicate = getEvictionPredicate(object); + Predicate> predicate = getInvalidationPredicate(object); if (predicate != null) runEvictions(predicate); } } @@ -276,25 +280,6 @@ public class StreamRealmCache { for (String key : evictions) cache.evict(key); } - protected Predicate> getEvictionPredicate(Object object) { - if (object instanceof CachedRealm) { - CachedRealm cached = (CachedRealm)object; - return getRealmInvalidationPredicate(cached.getId()); - } else if (object instanceof CachedClient) { - CachedClient cached = (CachedClient)object; - return getClientInvalidationPredicate(cached.getId()); - } else if (object instanceof CachedRole) { - CachedRole cached = (CachedRole)object; - return getRoleInvalidationPredicate(cached.getId()); - } else if (object instanceof CachedGroup) { - CachedGroup cached = (CachedGroup)object; - return getGroupInvalidationPredicate(cached.getId()); - } else if (object instanceof CachedClientTemplate) { - CachedClientTemplate cached = (CachedClientTemplate)object; - return getClientTemplateInvalidationPredicate(cached.getId()); - } - return null; - } protected Predicate> getInvalidationPredicate(Object object) { if (object instanceof CachedRealm) { CachedRealm cached = (CachedRealm)object; diff --git a/model/infinispan/src/test/java/org/keycloak/models/sessions/infinispan/initializer/ClusteredCacheBehaviorTest.java b/model/infinispan/src/test/java/org/keycloak/models/sessions/infinispan/initializer/ClusteredCacheBehaviorTest.java index e83a8b1116..bc8b4a3fdd 100755 --- a/model/infinispan/src/test/java/org/keycloak/models/sessions/infinispan/initializer/ClusteredCacheBehaviorTest.java +++ b/model/infinispan/src/test/java/org/keycloak/models/sessions/infinispan/initializer/ClusteredCacheBehaviorTest.java @@ -64,22 +64,17 @@ public class ClusteredCacheBehaviorTest { @CacheEntryRemoved public void removed(CacheEntryRemovedEvent event) { - if (event.isPre()) { - System.out.println("Listener '" + name + "' entry removed"); - } + System.out.println("Listener '" + name + "' entry removed isPre: " + event.isPre()); } @CacheEntryInvalidated public void removed(CacheEntryInvalidatedEvent event) { - if (event.isPre()) { - System.out.println("Listener '" + name + "' entry invalidated"); - - } + System.out.println("Listener '" + name + "' entry invalidated: isPre: " + event.isPre()); } @CacheEntriesEvicted public void evicted(CacheEntriesEvictedEvent event) { - System.out.println("Listener '" + name + "' entry evicted"); + System.out.println("Listener '" + name + "' entry evicted isPre: " + event.isPre()); } From 4dcdaf4985bdbe78eb418634eaba5c39dd0f6a05 Mon Sep 17 00:00:00 2001 From: Bill Burke Date: Mon, 22 Feb 2016 17:16:35 -0500 Subject: [PATCH 5/5] role cached queries --- .../cache/infinispan/ClientAdapter.java | 27 ++- .../models/cache/infinispan/RealmAdapter.java | 35 ++-- .../infinispan/StreamCacheRealmProvider.java | 194 +++++++++++++++++- .../cache/infinispan/StreamRealmCache.java | 4 +- .../infinispan/entities/CachedClient.java | 12 -- .../infinispan/entities/CachedRealm.java | 27 --- .../infinispan/entities/RoleListQuery.java | 68 ++++++ .../infinispan/stream/HasRolePredicate.java | 5 + .../keycloak/models/jpa/ClientAdapter.java | 62 +++--- .../keycloak/models/jpa/JpaRealmProvider.java | 120 ++++++++++- .../org/keycloak/models/jpa/RealmAdapter.java | 64 ++---- .../models/jpa/entities/ClientEntity.java | 11 - .../models/jpa/entities/RealmEntity.java | 18 -- .../models/jpa/entities/RoleEntity.java | 4 + .../keycloak/adapters/ClientAdapter.java | 53 ++--- .../keycloak/adapters/MongoRealmProvider.java | 103 ++++++++++ .../mongo/keycloak/adapters/RealmAdapter.java | 49 ++--- .../java/org/keycloak/models/ClientModel.java | 6 - .../java/org/keycloak/models/RealmModel.java | 6 - .../org/keycloak/models/RealmProvider.java | 19 ++ .../keycloak/models/RoleContainerModel.java | 10 + 21 files changed, 631 insertions(+), 266 deletions(-) create mode 100755 model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/entities/RoleListQuery.java diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/ClientAdapter.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/ClientAdapter.java index e636f5a9bb..2094fa2329 100755 --- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/ClientAdapter.java +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/ClientAdapter.java @@ -463,11 +463,18 @@ public class ClientAdapter implements ClientModel { } @Override - public void updateDefaultRoles(String[] defaultRoles) { + public void updateDefaultRoles(String... defaultRoles) { getDelegateForUpdate(); updated.updateDefaultRoles(defaultRoles); } + @Override + public void removeDefaultRoles(String... defaultRoles) { + getDelegateForUpdate(); + updated.removeDefaultRoles(defaultRoles); + + } + @Override public boolean isBearerOnly() { if (updated != null) return updated.isBearerOnly(); @@ -542,12 +549,10 @@ public class ClientAdapter implements ClientModel { @Override public RoleModel getRole(String name) { - if (updated != null) return updated.getRole(name); - String id = cached.getRoles().get(name); - if (id == null) { - return null; + for (RoleModel role : getRoles()) { + if (role.getName().equals(name)) return role; } - return cacheSession.getRoleById(id, cachedRealm); + return null; } @Override @@ -575,15 +580,7 @@ public class ClientAdapter implements ClientModel { @Override public Set getRoles() { - if (updated != null) return updated.getRoles(); - - Set roles = new HashSet(); - for (String id : cached.getRoles().values()) { - RoleModel roleById = cacheSession.getRoleById(id, cachedRealm); - if (roleById == null) continue; - roles.add(roleById); - } - return roles; + return cacheSession.getClientRoles(cachedRealm, this); } @Override diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/RealmAdapter.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/RealmAdapter.java index bc39f320d0..030286bc5d 100755 --- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/RealmAdapter.java +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/RealmAdapter.java @@ -581,11 +581,18 @@ public class RealmAdapter implements RealmModel { } @Override - public void updateDefaultRoles(String[] defaultRoles) { + public void updateDefaultRoles(String... defaultRoles) { getDelegateForUpdate(); updated.updateDefaultRoles(defaultRoles); } + @Override + public void removeDefaultRoles(String... defaultRoles) { + getDelegateForUpdate(); + updated.removeDefaultRoles(defaultRoles); + + } + @Override public List getClients() { return cacheSession.getClients(this); @@ -870,12 +877,18 @@ public class RealmAdapter implements RealmModel { @Override public RoleModel getRole(String name) { - if (updated != null) return updated.getRole(name); - String id = cached.getRealmRoles().get(name); - if (id == null) return null; - return cacheSession.getRoleById(id, this); + for (RoleModel role : getRoles()) { + if (role.getName().equals(name)) return role; + } + return null; } + @Override + public Set getRoles() { + return cacheSession.getRealmRoles(this); + } + + @Override public RoleModel addRole(String name) { getDelegateForUpdate(); @@ -899,18 +912,6 @@ public class RealmAdapter implements RealmModel { return updated.removeRole(role); } - @Override - public Set getRoles() { - if (updated != null) return updated.getRoles(); - - Set roles = new HashSet(); - for (String id : cached.getRealmRoles().values()) { - RoleModel roleById = cacheSession.getRoleById(id, this); - if (roleById == null) continue; - roles.add(roleById); - } - return Collections.unmodifiableSet(roles); - } @Override public boolean isIdentityFederationEnabled() { diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/StreamCacheRealmProvider.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/StreamCacheRealmProvider.java index def9b83922..21c0c7df06 100755 --- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/StreamCacheRealmProvider.java +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/StreamCacheRealmProvider.java @@ -37,7 +37,8 @@ import org.keycloak.models.cache.infinispan.entities.CachedRealmRole; import org.keycloak.models.cache.infinispan.entities.CachedRole; import org.keycloak.models.cache.infinispan.entities.ClientListQuery; import org.keycloak.models.cache.infinispan.entities.RealmListQuery; -import org.keycloak.models.cache.infinispan.entities.Revisioned; +import org.keycloak.models.cache.infinispan.entities.RoleListQuery; +import org.keycloak.models.utils.KeycloakModelUtils; import java.util.Collections; import java.util.HashMap; @@ -77,7 +78,7 @@ import java.util.Set; * - realm client lists need to be invalidated and evited whenever a client is added or removed from a realm. RealmProvider * now has addClient/removeClient at its top level. All adapaters should use these methods so that the appropriate invalidations * can be registered. - * - whenever a client is added/removed the realm of the client is added to a clientListInvalidations set + * - whenever a client is added/removed the realm of the client is added to a listInvalidations set * this set must be checked before sending back or caching a cached query. This check is required to * avoid caching an uncommitted removal/add in a query cache. * - when a client is removed, any queries that contain that client must also be removed. @@ -104,6 +105,8 @@ import java.util.Set; public class StreamCacheRealmProvider implements CacheRealmProvider { protected static final Logger logger = Logger.getLogger(StreamCacheRealmProvider.class); public static final String REALM_CLIENTS_QUERY_SUFFIX = ".realm.clients"; + public static final String ROLES_QUERY_SUFFIX = ".roles"; + public static final String ROLE_BY_NAME_QUERY_SUFFIX = ".role.by-name"; protected StreamRealmCache cache; protected KeycloakSession session; protected RealmProvider delegate; @@ -115,7 +118,7 @@ public class StreamCacheRealmProvider implements CacheRealmProvider { protected Map managedClientTemplates = new HashMap<>(); protected Map managedRoles = new HashMap<>(); protected Map managedGroups = new HashMap<>(); - protected Set clientListInvalidations = new HashSet<>(); + protected Set listInvalidations = new HashSet<>(); protected Set invalidations = new HashSet<>(); protected boolean clearAll; @@ -386,7 +389,7 @@ public class StreamCacheRealmProvider implements CacheRealmProvider { invalidations.add(client.getId()); cache.clientAdded(realm.getId(), client.getId(), invalidations); // this is needed so that a new client that hasn't been committed isn't cached in a query - clientListInvalidations.add(realm.getId()); + listInvalidations.add(realm.getId()); return client; } @@ -394,10 +397,17 @@ public class StreamCacheRealmProvider implements CacheRealmProvider { return realm + REALM_CLIENTS_QUERY_SUFFIX; } + private String getRolesCacheKey(String container) { + return container + ROLES_QUERY_SUFFIX; + } + private String getRoleByNameCacheKey(String container, String name) { + return container + "." + name + ROLES_QUERY_SUFFIX; + } + @Override public List getClients(RealmModel realm) { String cacheKey = getRealmClientsQueryCacheKey(realm.getId()); - boolean queryDB = invalidations.contains(cacheKey) || clientListInvalidations.contains(realm.getId()); + boolean queryDB = invalidations.contains(cacheKey) || listInvalidations.contains(realm.getId()); if (queryDB) { return getDelegate().getClients(realm); } @@ -430,6 +440,7 @@ public class StreamCacheRealmProvider implements CacheRealmProvider { return list; } + @Override public boolean removeClient(String id, RealmModel realm) { ClientModel client = getClientById(id, realm); @@ -437,7 +448,7 @@ public class StreamCacheRealmProvider implements CacheRealmProvider { // need to invalidate realm client query cache every time client list is changed invalidations.add(getRealmClientsQueryCacheKey(realm.getId())); invalidations.add(getClientByClientIdCacheKey(client.getClientId(), realm)); - clientListInvalidations.add(realm.getId()); + listInvalidations.add(realm.getId()); registerClientInvalidation(id); cache.clientRemoval(realm.getId(), id, invalidations); for (RoleModel role : client.getRoles()) { @@ -451,6 +462,177 @@ public class StreamCacheRealmProvider implements CacheRealmProvider { if (delegate != null) delegate.close(); } + @Override + public RoleModel addRealmRole(RealmModel realm, String name) { + return addRealmRole(realm, KeycloakModelUtils.generateId(), name); + } + + @Override + public RoleModel addRealmRole(RealmModel realm, String id, String name) { + invalidations.add(getRolesCacheKey(realm.getId())); + // this is needed so that a new role that hasn't been committed isn't cached in a query + listInvalidations.add(realm.getId()); + RoleModel role = getDelegate().addRealmRole(realm, name); + invalidations.add(role.getId()); + return role; + } + + @Override + public Set getRealmRoles(RealmModel realm) { + String cacheKey = getRolesCacheKey(realm.getId()); + boolean queryDB = invalidations.contains(cacheKey) || listInvalidations.contains(realm.getId()); + if (queryDB) { + return getDelegate().getRealmRoles(realm); + } + + RoleListQuery query = cache.get(cacheKey, RoleListQuery.class); + if (query != null) { + logger.tracev("getRealmRoles cache hit: {0}", realm.getName()); + } + + if (query == null) { + Long loaded = cache.getCurrentRevision(cacheKey); + Set model = getDelegate().getRealmRoles(realm); + if (model == null) return null; + Set ids = new HashSet<>(); + for (RoleModel role : model) ids.add(role.getId()); + query = new RoleListQuery(loaded, cacheKey, realm, ids); + logger.tracev("adding realm roles cache miss: realm {0} key {1}", realm.getName(), cacheKey); + cache.addRevisioned(query); + return model; + } + Set list = new HashSet<>(); + for (String id : query.getRoles()) { + RoleModel role = session.realms().getRoleById(id, realm); + if (role == null) { + invalidations.add(cacheKey); + return getDelegate().getRealmRoles(realm); + } + list.add(role); + } + return list; + } + + @Override + public Set getClientRoles(RealmModel realm, ClientModel client) { + String cacheKey = getRolesCacheKey(client.getId()); + boolean queryDB = invalidations.contains(cacheKey) || listInvalidations.contains(client.getId()); + if (queryDB) { + return getDelegate().getClientRoles(realm, client); + } + + RoleListQuery query = cache.get(cacheKey, RoleListQuery.class); + if (query != null) { + logger.tracev("getClientRoles cache hit: {0}", client.getClientId()); + } + + if (query == null) { + Long loaded = cache.getCurrentRevision(cacheKey); + Set model = getDelegate().getClientRoles(realm, client); + if (model == null) return null; + Set ids = new HashSet<>(); + for (RoleModel role : model) ids.add(role.getId()); + query = new RoleListQuery(loaded, cacheKey, realm, ids, client.getClientId()); + logger.tracev("adding client roles cache miss: client {0} key {1}", client.getClientId(), cacheKey); + cache.addRevisioned(query); + return model; + } + Set list = new HashSet<>(); + for (String id : query.getRoles()) { + RoleModel role = session.realms().getRoleById(id, realm); + if (role == null) { + invalidations.add(cacheKey); + return getDelegate().getClientRoles(realm, client); + } + list.add(role); + } + return list; + } + + @Override + public RoleModel addClientRole(RealmModel realm, ClientModel client, String name) { + return addClientRole(realm, client, KeycloakModelUtils.generateId(), name); + } + + @Override + public RoleModel addClientRole(RealmModel realm, ClientModel client, String id, String name) { + invalidations.add(getRolesCacheKey(client.getId())); + // this is needed so that a new role that hasn't been committed isn't cached in a query + listInvalidations.add(client.getId()); + RoleModel role = getDelegate().addClientRole(realm, client, id, name); + invalidations.add(role.getId()); + return role; + } + + @Override + public RoleModel getRealmRole(RealmModel realm, String name) { + String cacheKey = getRoleByNameCacheKey(realm.getId(), name); + boolean queryDB = invalidations.contains(cacheKey) || listInvalidations.contains(realm.getId()); + if (queryDB) { + return getDelegate().getRealmRole(realm, name); + } + + RoleListQuery query = cache.get(cacheKey, RoleListQuery.class); + if (query != null) { + logger.tracev("getRealmRole cache hit: {0}.{1}", realm.getName(), name); + } + + if (query == null) { + Long loaded = cache.getCurrentRevision(cacheKey); + RoleModel model = getDelegate().getRealmRole(realm, name); + if (model == null) return null; + query = new RoleListQuery(loaded, cacheKey, realm, model.getId()); + logger.tracev("adding realm role cache miss: client {0} key {1}", realm.getName(), cacheKey); + cache.addRevisioned(query); + return model; + } + RoleModel role = getRoleById(query.getRoles().iterator().next(), realm); + if (role == null) { + invalidations.add(cacheKey); + return getDelegate().getRealmRole(realm, name); + } + return role; + } + + @Override + public RoleModel getClientRole(RealmModel realm, ClientModel client, String name) { + String cacheKey = getRoleByNameCacheKey(client.getId(), name); + boolean queryDB = invalidations.contains(cacheKey) || listInvalidations.contains(client.getId()); + if (queryDB) { + return getDelegate().getClientRole(realm, client, name); + } + + RoleListQuery query = cache.get(cacheKey, RoleListQuery.class); + if (query != null) { + logger.tracev("getClientRole cache hit: {0}.{1}", client.getClientId(), name); + } + + if (query == null) { + Long loaded = cache.getCurrentRevision(cacheKey); + RoleModel model = getDelegate().getClientRole(realm, client, name); + if (model == null) return null; + query = new RoleListQuery(loaded, cacheKey, realm, model.getId(), client.getClientId()); + logger.tracev("adding client role cache miss: client {0} key {1}", client.getClientId(), cacheKey); + cache.addRevisioned(query); + return model; + } + RoleModel role = getRoleById(query.getRoles().iterator().next(), realm); + if (role == null) { + invalidations.add(cacheKey); + return getDelegate().getClientRole(realm, client, name); + } + return role; + } + + @Override + public boolean removeRole(RealmModel realm, RoleModel role) { + invalidations.add(getRolesCacheKey(role.getContainer().getId())); + invalidations.add(getRoleByNameCacheKey(role.getContainer().getId(), role.getName())); + listInvalidations.add(role.getContainer().getId()); + invalidations.add(role.getId()); + return getDelegate().removeRole(realm, role); + } + @Override public RoleModel getRoleById(String id, RealmModel realm) { CachedRole cached = cache.get(id, CachedRole.class); diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/StreamRealmCache.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/StreamRealmCache.java index 027793ef0b..452eee489d 100755 --- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/StreamRealmCache.java +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/StreamRealmCache.java @@ -37,6 +37,7 @@ import org.keycloak.models.cache.infinispan.stream.HasRolePredicate; import org.keycloak.models.cache.infinispan.stream.InClientPredicate; import org.keycloak.models.cache.infinispan.stream.InRealmPredicate; import org.keycloak.models.cache.infinispan.stream.RealmQueryPredicate; +import org.keycloak.models.cache.infinispan.stream.RoleQueryPredicate; import java.util.HashSet; import java.util.Iterator; @@ -287,9 +288,6 @@ public class StreamRealmCache { } else if (object instanceof CachedClient) { CachedClient cached = (CachedClient)object; Predicate> predicate = getClientRemovalPredicate(cached.getRealm(), cached.getId()); - for (String roleId : cached.getRoles().values()) { - predicate.or(getRoleRemovalPredicate(roleId)); - } return predicate; } else if (object instanceof CachedRole) { CachedRole cached = (CachedRole)object; diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/entities/CachedClient.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/entities/CachedClient.java index c528c8c0d2..cac6bc6721 100755 --- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/entities/CachedClient.java +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/entities/CachedClient.java @@ -67,7 +67,6 @@ public class CachedClient extends AbstractRevisioned implements InRealm { protected boolean implicitFlowEnabled; protected boolean directAccessGrantsEnabled; protected boolean serviceAccountsEnabled; - protected Map roles = new HashMap(); protected int nodeReRegistrationTimeout; protected Map registeredNodes; protected String clientTemplate; @@ -110,7 +109,6 @@ public class CachedClient extends AbstractRevisioned implements InRealm { implicitFlowEnabled = model.isImplicitFlowEnabled(); directAccessGrantsEnabled = model.isDirectAccessGrantsEnabled(); serviceAccountsEnabled = model.isServiceAccountsEnabled(); - cacheRoles(model); nodeReRegistrationTimeout = model.getNodeReRegistrationTimeout(); registeredNodes = new TreeMap<>(model.getRegisteredNodes()); @@ -122,12 +120,6 @@ public class CachedClient extends AbstractRevisioned implements InRealm { useTemplateScope = model.useTemplateScope(); } - protected void cacheRoles(ClientModel model) { - for (RoleModel role : model.getRoles()) { - roles.put(role.getName(), role.getId()); - } - } - public String getClientId() { return clientId; } @@ -244,10 +236,6 @@ public class CachedClient extends AbstractRevisioned implements InRealm { return serviceAccountsEnabled; } - public Map getRoles() { - return roles; - } - public int getNodeReRegistrationTimeout() { return nodeReRegistrationTimeout; } diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/entities/CachedRealm.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/entities/CachedRealm.java index d5e02a227e..b93da32933 100755 --- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/entities/CachedRealm.java +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/entities/CachedRealm.java @@ -145,8 +145,6 @@ public class CachedRealm extends AbstractRevisioned { protected List defaultGroups = new LinkedList(); protected Set groups = new HashSet(); - protected Map realmRoles = new HashMap(); - protected List clients = new LinkedList<>(); protected List clientTemplates= new LinkedList<>(); protected boolean internationalizationEnabled; protected Set supportedLocales; @@ -240,10 +238,6 @@ public class CachedRealm extends AbstractRevisioned { ClientModel masterAdminClient = model.getMasterAdminClient(); this.masterAdminClient = (masterAdminClient != null) ? masterAdminClient.getId() : null; - cacheRealmRoles(model); - - cacheClients(model); - cacheClientTemplates(model); internationalizationEnabled = model.isInternationalizationEnabled(); @@ -288,19 +282,6 @@ public class CachedRealm extends AbstractRevisioned { } } - protected void cacheClients(RealmModel model) { - for (ClientModel client : model.getClients()) { - clients.add(client.getId()); - } - } - - protected void cacheRealmRoles(RealmModel model) { - for (RoleModel role : model.getRoles()) { - realmRoles.put(role.getName(), role.getId()); - } - } - - public String getMasterAdminClient() { return masterAdminClient; } @@ -321,14 +302,6 @@ public class CachedRealm extends AbstractRevisioned { return defaultRoles; } - public Map getRealmRoles() { - return realmRoles; - } - - public List getClients() { - return clients; - } - public boolean isEnabled() { return enabled; } diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/entities/RoleListQuery.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/entities/RoleListQuery.java new file mode 100755 index 0000000000..4b0ab08d66 --- /dev/null +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/entities/RoleListQuery.java @@ -0,0 +1,68 @@ +package org.keycloak.models.cache.infinispan.entities; + +import org.keycloak.models.RealmModel; +import org.keycloak.models.cache.infinispan.entities.AbstractRevisioned; +import org.keycloak.models.cache.infinispan.entities.ClientQuery; +import org.keycloak.models.cache.infinispan.entities.RoleQuery; + +import java.util.HashSet; +import java.util.Set; + +/** + * @author Bill Burke + * @version $Revision: 1 $ + */ +public class RoleListQuery extends AbstractRevisioned implements RoleQuery, InClient { + private final Set roles; + private final String realm; + private final String realmName; + private String client; + + public RoleListQuery(Long revisioned, String id, RealmModel realm, Set roles) { + super(revisioned, id); + this.realm = realm.getId(); + this.realmName = realm.getName(); + this.roles = roles; + } + + public RoleListQuery(Long revisioned, String id, RealmModel realm, String role) { + super(revisioned, id); + this.realm = realm.getId(); + this.realmName = realm.getName(); + this.roles = new HashSet<>(); + this.roles.add(role); + } + + public RoleListQuery(Long revision, String id, RealmModel realm, Set roles, String client) { + this(revision, id, realm, roles); + this.client = client; + } + + public RoleListQuery(Long revision, String id, RealmModel realm, String role, String client) { + this(revision, id, realm, role); + this.client = client; + } + + @Override + public Set getRoles() { + return roles; + } + + @Override + public String getRealm() { + return realm; + } + + @Override + public String getClientId() { + return client; + } + + @Override + public String toString() { + return "RoleListQuery{" + + "id='" + getId() + "'" + + "realmName='" + realmName + '\'' + + '}'; + } +} diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/HasRolePredicate.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/HasRolePredicate.java index c4a56638b5..7d32462de2 100755 --- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/HasRolePredicate.java +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/HasRolePredicate.java @@ -3,6 +3,7 @@ package org.keycloak.models.cache.infinispan.stream; import org.keycloak.models.cache.infinispan.entities.CachedGroup; import org.keycloak.models.cache.infinispan.entities.CachedRole; import org.keycloak.models.cache.infinispan.entities.Revisioned; +import org.keycloak.models.cache.infinispan.entities.RoleQuery; import java.io.Serializable; import java.util.Map; @@ -36,6 +37,10 @@ public class HasRolePredicate implements Predicate CachedGroup cachedRole = (CachedGroup)value; if (cachedRole.getRoleMappings().contains(role)) return true; } + if (value instanceof RoleQuery) { + RoleQuery roleQuery = (RoleQuery)value; + if (roleQuery.getRoles().contains(role)) return true; + } return false; } } diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/ClientAdapter.java b/model/jpa/src/main/java/org/keycloak/models/jpa/ClientAdapter.java index 8affd11629..115d4dd839 100755 --- a/model/jpa/src/main/java/org/keycloak/models/jpa/ClientAdapter.java +++ b/model/jpa/src/main/java/org/keycloak/models/jpa/ClientAdapter.java @@ -612,31 +612,17 @@ public class ClientAdapter implements ClientModel { @Override public RoleModel getRole(String name) { - TypedQuery query = em.createNamedQuery("getClientRoleIdByName", String.class); - query.setParameter("name", name); - query.setParameter("client", entity.getId()); - List roles = query.getResultList(); - if (roles.size() == 0) return null; - return session.realms().getRoleById(roles.get(0), realm); + return session.realms().getClientRole(realm, this, name); } @Override public RoleModel addRole(String name) { - return this.addRole(KeycloakModelUtils.generateId(), name); + return session.realms().addClientRole(realm, this, name); } @Override public RoleModel addRole(String id, String name) { - RoleEntity roleEntity = new RoleEntity(); - roleEntity.setId(id); - roleEntity.setName(name); - roleEntity.setClient(entity); - roleEntity.setClientRole(true); - roleEntity.setRealmId(realm.getId()); - entity.getRoles().add(roleEntity); - em.persist(roleEntity); - em.flush(); - return new RoleAdapter(session, realm, em, roleEntity); + return session.realms().addClientRole(realm, this, id, name); } @Override @@ -650,7 +636,6 @@ public class ClientAdapter implements ClientModel { RoleEntity role = RoleAdapter.toRoleEntity(roleModel, em); if (!role.isClientRole()) return false; - entity.getRoles().remove(role); entity.getDefaultRoles().remove(role); String compositeRoleTable = JpaUtils.getTableNameForNativeQuery("COMPOSITE_ROLE", em); em.createNativeQuery("delete from " + compositeRoleTable + " where CHILD_ROLE = :role").setParameter("role", role).executeUpdate(); @@ -666,24 +651,7 @@ public class ClientAdapter implements ClientModel { @Override public Set getRoles() { - Set list = new HashSet(); - TypedQuery query = em.createNamedQuery("getClientRoles", RoleEntity.class); - query.setParameter("client", entity); - List roles = query.getResultList(); - for (RoleEntity roleEntity : roles) { - list.add(new RoleAdapter(session, realm, em, roleEntity)); - } - - /* - TypedQuery query = em.createNamedQuery("getClientRoleIds", String.class); - query.setParameter("client", entity.getId()); - List roles = query.getResultList(); - for (String id : roles) { - list.add(session.realms().getRoleById(id, realm)); - } - */ - return list; - + return session.realms().getClientRoles(realm, this); } @Override @@ -733,10 +701,10 @@ public class ClientAdapter implements ClientModel { } @Override - public void updateDefaultRoles(String[] defaultRoles) { + public void updateDefaultRoles(String... defaultRoles) { Collection entities = entity.getDefaultRoles(); Set already = new HashSet(); - List remove = new ArrayList(); + List remove = new ArrayList<>(); for (RoleEntity rel : entities) { if (!contains(rel.getName(), defaultRoles)) { remove.add(rel); @@ -756,6 +724,24 @@ public class ClientAdapter implements ClientModel { em.flush(); } + @Override + public void removeDefaultRoles(String... defaultRoles) { + Collection entities = entity.getDefaultRoles(); + List remove = new ArrayList(); + for (RoleEntity rel : entities) { + if (contains(rel.getName(), defaultRoles)) { + remove.add(rel); + } + } + for (RoleEntity entity : remove) { + entities.remove(entity); + } + em.flush(); + } + + + + @Override public int getNodeReRegistrationTimeout() { return entity.getNodeReRegistrationTimeout(); diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/JpaRealmProvider.java b/model/jpa/src/main/java/org/keycloak/models/jpa/JpaRealmProvider.java index 6c2ae6b84c..6080d72ed5 100755 --- a/model/jpa/src/main/java/org/keycloak/models/jpa/JpaRealmProvider.java +++ b/model/jpa/src/main/java/org/keycloak/models/jpa/JpaRealmProvider.java @@ -18,6 +18,7 @@ package org.keycloak.models.jpa; import org.jboss.logging.Logger; +import org.keycloak.connections.jpa.util.JpaUtils; import org.keycloak.migration.MigrationModel; import org.keycloak.models.ClientModel; import org.keycloak.models.ClientTemplateModel; @@ -25,6 +26,7 @@ import org.keycloak.models.GroupModel; import org.keycloak.models.KeycloakSession; import org.keycloak.models.RealmModel; import org.keycloak.models.RealmProvider; +import org.keycloak.models.RoleContainerModel; import org.keycloak.models.RoleModel; import org.keycloak.models.jpa.entities.ClientEntity; import org.keycloak.models.jpa.entities.ClientTemplateEntity; @@ -37,8 +39,10 @@ import javax.persistence.EntityManager; import javax.persistence.TypedQuery; import java.util.ArrayList; import java.util.Collections; +import java.util.HashSet; import java.util.LinkedList; import java.util.List; +import java.util.Set; /** * @author Bill Burke @@ -135,15 +139,15 @@ public class JpaRealmProvider implements RealmProvider { for (String client : clients) { session.realms().removeClient(client, adapter); } - /* - for (ClientEntity a : new LinkedList<>(realm.getClients())) { - adapter.removeClient(a.getId()); - } - */ + for (ClientTemplateEntity a : new LinkedList<>(realm.getClientTemplates())) { adapter.removeClientTemplate(a.getId()); } + for (RoleModel role : adapter.getRoles()) { + session.realms().removeRole(adapter, role); + } + em.remove(realm); em.flush(); @@ -155,6 +159,112 @@ public class JpaRealmProvider implements RealmProvider { public void close() { } + @Override + public RoleModel addRealmRole(RealmModel realm, String name) { + return addRealmRole(realm, KeycloakModelUtils.generateId(), name); + + } + @Override + public RoleModel addRealmRole(RealmModel realm, String id, String name) { + RoleEntity entity = new RoleEntity(); + entity.setId(id); + entity.setName(name); + RealmEntity ref = em.getReference(RealmEntity.class, realm.getId()); + entity.setRealm(ref); + entity.setRealmId(realm.getId()); + em.persist(entity); + em.flush(); + return new RoleAdapter(session, realm, em, entity); + + } + + @Override + public RoleModel getRealmRole(RealmModel realm, String name) { + TypedQuery query = em.createNamedQuery("getRealmRoleIdByName", String.class); + query.setParameter("name", name); + query.setParameter("realm", realm.getId()); + List roles = query.getResultList(); + if (roles.size() == 0) return null; + return session.realms().getRoleById(roles.get(0), realm); + } + + @Override + public RoleModel addClientRole(RealmModel realm, ClientModel client, String name) { + return addClientRole(realm, client, KeycloakModelUtils.generateId(), name); + } + @Override + public RoleModel addClientRole(RealmModel realm, ClientModel client, String id, String name) { + ClientEntity clientEntity = em.getReference(ClientEntity.class, client.getId()); + RoleEntity roleEntity = new RoleEntity(); + roleEntity.setId(id); + roleEntity.setName(name); + roleEntity.setClient(clientEntity); + roleEntity.setClientRole(true); + roleEntity.setRealmId(realm.getId()); + em.persist(roleEntity); + em.flush(); + return new RoleAdapter(session, realm, em, roleEntity); + } + + @Override + public Set getRealmRoles(RealmModel realm) { + TypedQuery query = em.createNamedQuery("getRealmRoleIds", String.class); + query.setParameter("realm", realm.getId()); + List roles = query.getResultList(); + + if (roles.isEmpty()) return Collections.EMPTY_SET; + Set list = new HashSet(); + for (String id : roles) { + list.add(session.realms().getRoleById(id, realm)); + } + return Collections.unmodifiableSet(list); + } + + @Override + public RoleModel getClientRole(RealmModel realm, ClientModel client, String name) { + TypedQuery query = em.createNamedQuery("getClientRoleIdByName", String.class); + query.setParameter("name", name); + query.setParameter("client", client.getId()); + List roles = query.getResultList(); + if (roles.size() == 0) return null; + return session.realms().getRoleById(roles.get(0), realm); + } + + + @Override + public Set getClientRoles(RealmModel realm, ClientModel client) { + Set list = new HashSet(); + TypedQuery query = em.createNamedQuery("getClientRoleIds", String.class); + query.setParameter("client", client.getId()); + List roles = query.getResultList(); + for (String id : roles) { + list.add(session.realms().getRoleById(id, realm)); + } + return list; + + } + + @Override + public boolean removeRole(RealmModel realm, RoleModel role) { + session.users().preRemove(realm, role); + RoleEntity roleEntity = em.getReference(RoleEntity.class, role.getId()); + RoleContainerModel container = role.getContainer(); + if (container.getDefaultRoles().contains(role.getName())) { + container.removeDefaultRoles(role.getName()); + } + String compositeRoleTable = JpaUtils.getTableNameForNativeQuery("COMPOSITE_ROLE", em); + em.createNativeQuery("delete from " + compositeRoleTable + " where CHILD_ROLE = :role").setParameter("role", roleEntity).executeUpdate(); + em.createNamedQuery("deleteScopeMappingByRole").setParameter("role", roleEntity).executeUpdate(); + em.createNamedQuery("deleteTemplateScopeMappingByRole").setParameter("role", roleEntity).executeUpdate(); + em.createNamedQuery("deleteGroupRoleMappingsByRole").setParameter("roleId", roleEntity.getId()).executeUpdate(); + + em.remove(roleEntity); + em.flush(); + + return true; + + } + @Override public RoleModel getRoleById(String id, RealmModel realm) { RoleEntity entity = em.find(RoleEntity.class, id); diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/RealmAdapter.java b/model/jpa/src/main/java/org/keycloak/models/jpa/RealmAdapter.java index ad2024b940..16eb1423cd 100755 --- a/model/jpa/src/main/java/org/keycloak/models/jpa/RealmAdapter.java +++ b/model/jpa/src/main/java/org/keycloak/models/jpa/RealmAdapter.java @@ -682,6 +682,21 @@ public class RealmAdapter implements RealmModel { em.flush(); } + @Override + public void removeDefaultRoles(String... defaultRoles) { + Collection entities = realm.getDefaultRoles(); + List remove = new ArrayList(); + for (RoleEntity rel : entities) { + if (contains(rel.getName(), defaultRoles)) { + remove.add(rel); + } + } + for (RoleEntity entity : remove) { + entities.remove(entity); + } + em.flush(); + } + @Override public List getDefaultGroups() { Collection entities = realm.getDefaultGroups(); @@ -980,66 +995,27 @@ public class RealmAdapter implements RealmModel { @Override public RoleModel getRole(String name) { - TypedQuery query = em.createNamedQuery("getRealmRoleIdByName", String.class); - query.setParameter("name", name); - query.setParameter("realm", realm.getId()); - List roles = query.getResultList(); - if (roles.size() == 0) return null; - return session.realms().getRoleById(roles.get(0), this); + return session.realms().getRealmRole(this, name); } @Override public RoleModel addRole(String name) { - return this.addRole(KeycloakModelUtils.generateId(), name); + return session.realms().addRealmRole(this, name); } @Override public RoleModel addRole(String id, String name) { - RoleEntity entity = new RoleEntity(); - entity.setId(id); - entity.setName(name); - entity.setRealm(realm); - entity.setRealmId(realm.getId()); - realm.getRoles().add(entity); - em.persist(entity); - em.flush(); - return new RoleAdapter(session, this, em, entity); + return session.realms().addRealmRole(this, id, name); } @Override public boolean removeRole(RoleModel role) { - if (role == null) { - return false; - } - if (!role.getContainer().equals(this)) return false; - session.users().preRemove(this, role); - RoleEntity roleEntity = RoleAdapter.toRoleEntity(role, em); - realm.getRoles().remove(roleEntity); - realm.getDefaultRoles().remove(roleEntity); - - String compositeRoleTable = JpaUtils.getTableNameForNativeQuery("COMPOSITE_ROLE", em); - em.createNativeQuery("delete from " + compositeRoleTable + " where CHILD_ROLE = :role").setParameter("role", roleEntity).executeUpdate(); - em.createNamedQuery("deleteScopeMappingByRole").setParameter("role", roleEntity).executeUpdate(); - em.createNamedQuery("deleteTemplateScopeMappingByRole").setParameter("role", roleEntity).executeUpdate(); - em.createNamedQuery("deleteGroupRoleMappingsByRole").setParameter("roleId", roleEntity.getId()).executeUpdate(); - - em.remove(roleEntity); - em.flush(); - - return true; + return session.realms().removeRole(this, role); } @Override public Set getRoles() { - Collection roles = realm.getRoles(); - if (roles == null) return Collections.EMPTY_SET; - Set list = new HashSet(); - for (RoleEntity entity : roles) { - list.add(new RoleAdapter(session, this, em, entity)); - // can't get it from cache cuz of stack overflow - // list.add(session.realms().getRoleById(entity.getId(), this)); - } - return Collections.unmodifiableSet(list); + return session.realms().getRealmRoles(this); } @Override diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/ClientEntity.java b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/ClientEntity.java index fd4e0a5323..fc10217127 100755 --- a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/ClientEntity.java +++ b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/ClientEntity.java @@ -157,9 +157,6 @@ public class ClientEntity { @Column(name="NODE_REREG_TIMEOUT") private int nodeReRegistrationTimeout; - @OneToMany(fetch = FetchType.LAZY, cascade ={CascadeType.REMOVE}, mappedBy = "client") - Collection roles = new ArrayList(); - @OneToMany(fetch = FetchType.LAZY, cascade ={CascadeType.REMOVE}, orphanRemoval = true) @JoinTable(name="CLIENT_DEFAULT_ROLES", joinColumns = { @JoinColumn(name="CLIENT_ID")}, inverseJoinColumns = { @JoinColumn(name="ROLE_ID")}) Collection defaultRoles = new ArrayList(); @@ -354,14 +351,6 @@ public class ClientEntity { this.managementUrl = managementUrl; } - public Collection getRoles() { - return roles; - } - - public void setRoles(Collection roles) { - this.roles = roles; - } - public Collection getDefaultRoles() { return defaultRoles; } diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/RealmEntity.java b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/RealmEntity.java index f33aa211ce..052ce6e558 100755 --- a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/RealmEntity.java +++ b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/RealmEntity.java @@ -150,9 +150,6 @@ public class RealmEntity { @OneToMany(fetch = FetchType.LAZY, cascade ={CascadeType.REMOVE}, orphanRemoval = true, mappedBy = "realm") Collection clientTemplates = new ArrayList<>(); - @OneToMany(fetch = FetchType.LAZY, cascade ={CascadeType.REMOVE}, mappedBy = "realm") - Collection roles = new ArrayList(); - @ElementCollection @MapKeyColumn(name="NAME") @Column(name="VALUE") @@ -418,21 +415,6 @@ public class RealmEntity { public void setRequiredCredentials(Collection requiredCredentials) { this.requiredCredentials = requiredCredentials; } - public Collection getRoles() { - return roles; - } - - public void setRoles(Collection roles) { - this.roles = roles; - } - - public void addRole(RoleEntity role) { - if (roles == null) { - roles = new ArrayList(); - } - roles.add(role); - } - public Map getSmtpConfig() { return smtpConfig; } diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/RoleEntity.java b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/RoleEntity.java index 5c02336621..3d1cae40b1 100755 --- a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/RoleEntity.java +++ b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/RoleEntity.java @@ -52,6 +52,8 @@ import java.util.Collection; @NamedQuery(name="getClientRoleIds", query="select role.id from RoleEntity role where role.client.id = :client"), @NamedQuery(name="getClientRoleByName", query="select role from RoleEntity role where role.name = :name and role.client = :client"), @NamedQuery(name="getClientRoleIdByName", query="select role.id from RoleEntity role where role.name = :name and role.client.id = :client"), + @NamedQuery(name="getRealmRoles", query="select role from RoleEntity role where role.clientRole = false and role.realm = :realm"), + @NamedQuery(name="getRealmRoleIds", query="select role.id from RoleEntity role where role.clientRole = false and role.realm.id = :realm"), @NamedQuery(name="getRealmRoleByName", query="select role from RoleEntity role where role.clientRole = false and role.name = :name and role.realm = :realm"), @NamedQuery(name="getRealmRoleIdByName", query="select role.id from RoleEntity role where role.clientRole = false and role.name = :name and role.realm.id = :realm") }) @@ -108,6 +110,8 @@ public class RoleEntity { this.realmId = realmId; } + + public String getName() { return name; } diff --git a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/ClientAdapter.java b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/ClientAdapter.java index 91c9308407..ff18fdf7ce 100755 --- a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/ClientAdapter.java +++ b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/ClientAdapter.java @@ -567,34 +567,18 @@ public class ClientAdapter extends AbstractMongoAdapter imple } @Override - public RoleAdapter getRole(String name) { - DBObject query = new QueryBuilder() - .and("name").is(name) - .and("clientId").is(getId()) - .get(); - MongoRoleEntity role = getMongoStore().loadSingleEntity(MongoRoleEntity.class, query, invocationContext); - if (role == null) { - return null; - } else { - return new RoleAdapter(session, getRealm(), role, invocationContext); - } + public RoleModel getRole(String name) { + return session.realms().getClientRole(realm, this, name); } @Override - public RoleAdapter addRole(String name) { - return this.addRole(null, name); + public RoleModel addRole(String name) { + return session.realms().addClientRole(realm, this, name); } @Override - public RoleAdapter addRole(String id, String name) { - MongoRoleEntity roleEntity = new MongoRoleEntity(); - roleEntity.setId(id); - roleEntity.setName(name); - roleEntity.setClientId(getId()); - - getMongoStore().insertEntity(roleEntity, invocationContext); - - return new RoleAdapter(session, getRealm(), roleEntity, this, invocationContext); + public RoleModel addRole(String id, String name) { + return session.realms().addClientRole(realm, this, id, name); } @Override @@ -605,17 +589,7 @@ public class ClientAdapter extends AbstractMongoAdapter imple @Override public Set getRoles() { - DBObject query = new QueryBuilder() - .and("clientId").is(getId()) - .get(); - List roles = getMongoStore().loadEntities(MongoRoleEntity.class, query, invocationContext); - - Set result = new HashSet(); - for (MongoRoleEntity role : roles) { - result.add(new RoleAdapter(session, getRealm(), role, this, invocationContext)); - } - - return result; + return session.realms().getClientRoles(realm, this); } @Override @@ -653,7 +627,7 @@ public class ClientAdapter extends AbstractMongoAdapter imple } @Override - public void updateDefaultRoles(String[] defaultRoles) { + public void updateDefaultRoles(String... defaultRoles) { List roleNames = new ArrayList(); for (String roleName : defaultRoles) { RoleModel role = getRole(roleName); @@ -668,6 +642,17 @@ public class ClientAdapter extends AbstractMongoAdapter imple updateMongoEntity(); } + @Override + public void removeDefaultRoles(String... defaultRoles) { + List roleNames = new ArrayList(); + for (String role : getMongoEntity().getDefaultRoles()) { + if (!RealmAdapter.contains(role, defaultRoles)) roleNames.add(role); + } + getMongoEntity().setDefaultRoles(roleNames); + updateMongoEntity(); + } + + @Override public int getNodeReRegistrationTimeout() { return getMongoEntity().getNodeReRegistrationTimeout(); diff --git a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/MongoRealmProvider.java b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/MongoRealmProvider.java index 1c4036b3c7..f8c9b7912f 100755 --- a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/MongoRealmProvider.java +++ b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/MongoRealmProvider.java @@ -40,7 +40,9 @@ import org.keycloak.models.utils.KeycloakModelUtils; import java.util.ArrayList; import java.util.Collections; +import java.util.HashSet; import java.util.List; +import java.util.Set; /** * @author Marek Posolda @@ -209,6 +211,107 @@ public class MongoRealmProvider implements RealmProvider { return Collections.unmodifiableList(result); } + @Override + public RoleModel addRealmRole(RealmModel realm, String name) { + return addRealmRole(realm, KeycloakModelUtils.generateId(), name); + } + + @Override + public RoleModel addRealmRole(RealmModel realm, String id, String name) { + MongoRoleEntity roleEntity = new MongoRoleEntity(); + roleEntity.setId(id); + roleEntity.setName(name); + roleEntity.setRealmId(realm.getId()); + + getMongoStore().insertEntity(roleEntity, invocationContext); + + return new RoleAdapter(session, realm, roleEntity, realm, invocationContext); + } + + @Override + public Set getRealmRoles(RealmModel realm) { + DBObject query = new QueryBuilder() + .and("realmId").is(realm.getId()) + .get(); + List roles = getMongoStore().loadEntities(MongoRoleEntity.class, query, invocationContext); + + + if (roles == null) return Collections.EMPTY_SET; + Set result = new HashSet(); + for (MongoRoleEntity role : roles) { + result.add(session.realms().getRoleById(role.getId(), realm)); + } + + return Collections.unmodifiableSet(result); + + } + + @Override + public Set getClientRoles(RealmModel realm, ClientModel client) { + DBObject query = new QueryBuilder() + .and("clientId").is(client.getId()) + .get(); + List roles = getMongoStore().loadEntities(MongoRoleEntity.class, query, invocationContext); + + Set result = new HashSet(); + for (MongoRoleEntity role : roles) { + result.add(session.realms().getRoleById(role.getId(), realm)); + } + + return result; + } + + @Override + public RoleModel getRealmRole(RealmModel realm, String name) { + DBObject query = new QueryBuilder() + .and("name").is(name) + .and("realmId").is(realm.getId()) + .get(); + MongoRoleEntity role = getMongoStore().loadSingleEntity(MongoRoleEntity.class, query, invocationContext); + if (role == null) { + return null; + } else { + return session.realms().getRoleById(role.getId(), realm); + } + } + + @Override + public RoleModel getClientRole(RealmModel realm, ClientModel client, String name) { + DBObject query = new QueryBuilder() + .and("name").is(name) + .and("clientId").is(client.getId()) + .get(); + MongoRoleEntity role = getMongoStore().loadSingleEntity(MongoRoleEntity.class, query, invocationContext); + if (role == null) { + return null; + } else { + return session.realms().getRoleById(role.getId(), realm); + } + } + + @Override + public RoleModel addClientRole(RealmModel realm, ClientModel client, String name) { + return addClientRole(realm, client, KeycloakModelUtils.generateId(), name); + } + + @Override + public RoleModel addClientRole(RealmModel realm, ClientModel client, String id, String name) { + MongoRoleEntity roleEntity = new MongoRoleEntity(); + roleEntity.setId(id); + roleEntity.setName(name); + roleEntity.setClientId(client.getId()); + + getMongoStore().insertEntity(roleEntity, invocationContext); + + return new RoleAdapter(session, realm, roleEntity, client, invocationContext); + } + + @Override + public boolean removeRole(RealmModel realm, RoleModel role) { + session.users().preRemove(realm, role); + return getMongoStore().removeEntity(MongoRoleEntity.class, role.getId(), invocationContext); + } + @Override public boolean removeClient(String id, RealmModel realm) { if (id == null) return false; diff --git a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/RealmAdapter.java b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/RealmAdapter.java index edb57d2156..6c4b6f9f22 100755 --- a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/RealmAdapter.java +++ b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/RealmAdapter.java @@ -595,47 +595,30 @@ public class RealmAdapter extends AbstractMongoAdapter impleme } @Override - public RoleAdapter getRole(String name) { - DBObject query = new QueryBuilder() - .and("name").is(name) - .and("realmId").is(getId()) - .get(); - MongoRoleEntity role = getMongoStore().loadSingleEntity(MongoRoleEntity.class, query, invocationContext); - if (role == null) { - return null; - } else { - return new RoleAdapter(session, this, role, this, invocationContext); - } + public RoleModel getRole(String name) { + return session.realms().getRealmRole(this, name); } @Override public RoleModel addRole(String name) { - return this.addRole(null, name); + return session.realms().addRealmRole(this, name); } @Override public RoleModel addRole(String id, String name) { - MongoRoleEntity roleEntity = new MongoRoleEntity(); - roleEntity.setId(id); - roleEntity.setName(name); - roleEntity.setRealmId(getId()); - - getMongoStore().insertEntity(roleEntity, invocationContext); - - return new RoleAdapter(session, this, roleEntity, this, invocationContext); + return session.realms().addRealmRole(this, id, name); } @Override public boolean removeRole(RoleModel role) { - return removeRoleById(role.getId()); + return session.realms().removeRole(this, role); } @Override public boolean removeRoleById(String id) { RoleModel role = getRoleById(id); if (role == null) return false; - session.users().preRemove(this, role); - return getMongoStore().removeEntity(MongoRoleEntity.class, id, invocationContext); + return removeRole(role); } @Override @@ -657,7 +640,7 @@ public class RealmAdapter extends AbstractMongoAdapter impleme @Override public RoleModel getRoleById(String id) { - return model.getRoleById(id, this); + return session.realms().getRoleById(id, this); } @Override @@ -780,6 +763,24 @@ public class RealmAdapter extends AbstractMongoAdapter impleme updateRealm(); } + public static boolean contains(String str, String[] array) { + for (String s : array) { + if (str.equals(s)) return true; + } + return false; + } + + + @Override + public void removeDefaultRoles(String... defaultRoles) { + List roleNames = new ArrayList(); + for (String role : realm.getDefaultRoles()) { + if (!contains(role, defaultRoles)) roleNames.add(role); + } + realm.setDefaultRoles(roleNames); + updateRealm(); + } + @Override public List getDefaultGroups() { List entities = realm.getDefaultGroups(); diff --git a/server-spi/src/main/java/org/keycloak/models/ClientModel.java b/server-spi/src/main/java/org/keycloak/models/ClientModel.java index 839996981a..6d96eb0a6b 100755 --- a/server-spi/src/main/java/org/keycloak/models/ClientModel.java +++ b/server-spi/src/main/java/org/keycloak/models/ClientModel.java @@ -85,12 +85,6 @@ public interface ClientModel extends RoleContainerModel, ProtocolMapperContaine void setBaseUrl(String url); - List getDefaultRoles(); - - void addDefaultRole(String name); - - void updateDefaultRoles(String[] defaultRoles); - boolean isBearerOnly(); void setBearerOnly(boolean only); diff --git a/server-spi/src/main/java/org/keycloak/models/RealmModel.java b/server-spi/src/main/java/org/keycloak/models/RealmModel.java index bc7dec5960..1c42e45e51 100755 --- a/server-spi/src/main/java/org/keycloak/models/RealmModel.java +++ b/server-spi/src/main/java/org/keycloak/models/RealmModel.java @@ -181,12 +181,6 @@ public interface RealmModel extends RoleContainerModel { RoleModel getRoleById(String id); - List getDefaultRoles(); - - void addDefaultRole(String name); - - void updateDefaultRoles(String[] defaultRoles); - List getDefaultGroups(); void addDefaultGroup(GroupModel group); diff --git a/server-spi/src/main/java/org/keycloak/models/RealmProvider.java b/server-spi/src/main/java/org/keycloak/models/RealmProvider.java index a101ce4919..e7584e7054 100755 --- a/server-spi/src/main/java/org/keycloak/models/RealmProvider.java +++ b/server-spi/src/main/java/org/keycloak/models/RealmProvider.java @@ -21,6 +21,7 @@ import org.keycloak.migration.MigrationModel; import org.keycloak.provider.Provider; import java.util.List; +import java.util.Set; /** * @author Bill Burke @@ -45,6 +46,24 @@ public interface RealmProvider extends Provider { ClientModel getClientByClientId(String clientId, RealmModel realm); + RoleModel addRealmRole(RealmModel realm, String name); + + RoleModel addRealmRole(RealmModel realm, String id, String name); + + RoleModel getRealmRole(RealmModel realm, String name); + + RoleModel addClientRole(RealmModel realm, ClientModel client, String name); + + RoleModel addClientRole(RealmModel realm, ClientModel client, String id, String name); + + Set getRealmRoles(RealmModel realm); + + RoleModel getClientRole(RealmModel realm, ClientModel client, String name); + + Set getClientRoles(RealmModel realm, ClientModel client); + + boolean removeRole(RealmModel realm, RoleModel role); + RoleModel getRoleById(String id, RealmModel realm); boolean removeClient(String id, RealmModel realm); diff --git a/server-spi/src/main/java/org/keycloak/models/RoleContainerModel.java b/server-spi/src/main/java/org/keycloak/models/RoleContainerModel.java index f405821ff0..24c60b303d 100755 --- a/server-spi/src/main/java/org/keycloak/models/RoleContainerModel.java +++ b/server-spi/src/main/java/org/keycloak/models/RoleContainerModel.java @@ -17,6 +17,7 @@ package org.keycloak.models; +import java.util.List; import java.util.Set; /** @@ -24,6 +25,8 @@ import java.util.Set; * @version $Revision: 1 $ */ public interface RoleContainerModel { + String getId(); + RoleModel getRole(String name); RoleModel addRole(String name); @@ -34,4 +37,11 @@ public interface RoleContainerModel { Set getRoles(); + List getDefaultRoles(); + + void addDefaultRole(String name); + + void updateDefaultRoles(String... defaultRoles); + + void removeDefaultRoles(String... defaultRoles); }