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