mirror of
https://github.com/keycloak/keycloak.git
synced 2026-01-25 16:42:34 +00:00
KEYCLOAK-2179 Cache fixes
This commit is contained in:
@@ -29,7 +29,7 @@ public class ClientAdapter implements ClientModel {
|
||||
private void getDelegateForUpdate() {
|
||||
if (updated == null) {
|
||||
cacheSession.registerApplicationInvalidation(getId());
|
||||
updated = updated = cacheSession.getDelegate().getClientById(getId(), cachedRealm);
|
||||
updated = cacheSession.getDelegate().getClientById(getId(), cachedRealm);
|
||||
if (updated == null) throw new IllegalStateException("Not found in database");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,16 @@
|
||||
package org.keycloak.models.cache.infinispan;
|
||||
|
||||
import org.infinispan.Cache;
|
||||
import org.infinispan.notifications.Listener;
|
||||
import org.infinispan.notifications.cachelistener.annotation.CacheEntriesEvicted;
|
||||
import org.infinispan.notifications.cachelistener.annotation.CacheEntryCreated;
|
||||
import org.infinispan.notifications.cachelistener.annotation.CacheEntryInvalidated;
|
||||
import org.infinispan.notifications.cachelistener.annotation.CacheEntryRemoved;
|
||||
import org.infinispan.notifications.cachelistener.event.CacheEntriesEvictedEvent;
|
||||
import org.infinispan.notifications.cachelistener.event.CacheEntryCreatedEvent;
|
||||
import org.infinispan.notifications.cachelistener.event.CacheEntryInvalidatedEvent;
|
||||
import org.infinispan.notifications.cachelistener.event.CacheEntryRemovedEvent;
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.Config;
|
||||
import org.keycloak.connections.infinispan.InfinispanConnectionProvider;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
@@ -8,6 +18,7 @@ import org.keycloak.models.KeycloakSessionFactory;
|
||||
import org.keycloak.models.cache.CacheRealmProvider;
|
||||
import org.keycloak.models.cache.CacheRealmProviderFactory;
|
||||
import org.keycloak.models.cache.RealmCache;
|
||||
import org.keycloak.models.cache.entities.CachedRealm;
|
||||
import org.keycloak.models.cache.entities.CachedUser;
|
||||
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
@@ -18,10 +29,14 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
*/
|
||||
public class InfinispanCacheRealmProviderFactory implements CacheRealmProviderFactory {
|
||||
|
||||
protected final ConcurrentHashMap<String, String> realmLookup = new ConcurrentHashMap<String, String>();
|
||||
private static final Logger log = Logger.getLogger(InfinispanCacheRealmProviderFactory.class);
|
||||
|
||||
protected volatile InfinispanRealmCache realmCache;
|
||||
|
||||
protected final ConcurrentHashMap<String, String> realmLookup = new ConcurrentHashMap<>();
|
||||
|
||||
private boolean isNewInfinispan;
|
||||
|
||||
@Override
|
||||
public CacheRealmProvider create(KeycloakSession session) {
|
||||
lazyInit(session);
|
||||
@@ -32,13 +47,25 @@ public class InfinispanCacheRealmProviderFactory implements CacheRealmProviderFa
|
||||
if (realmCache == null) {
|
||||
synchronized (this) {
|
||||
if (realmCache == null) {
|
||||
checkIspnVersion();
|
||||
|
||||
Cache<String, Object> cache = session.getProvider(InfinispanConnectionProvider.class).getCache(InfinispanConnectionProvider.REALM_CACHE_NAME);
|
||||
cache.addListener(new CacheListener());
|
||||
realmCache = new InfinispanRealmCache(cache, realmLookup);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void checkIspnVersion() {
|
||||
try {
|
||||
CacheEntryCreatedEvent.class.getMethod("getValue");
|
||||
isNewInfinispan = true;
|
||||
} catch (NoSuchMethodException nsme) {
|
||||
isNewInfinispan = false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(Config.Scope config) {
|
||||
}
|
||||
@@ -57,4 +84,71 @@ public class InfinispanCacheRealmProviderFactory implements CacheRealmProviderFa
|
||||
return "infinispan";
|
||||
}
|
||||
|
||||
@Listener
|
||||
public class CacheListener {
|
||||
|
||||
@CacheEntryCreated
|
||||
public void created(CacheEntryCreatedEvent<String, Object> event) {
|
||||
if (!event.isPre()) {
|
||||
Object object;
|
||||
|
||||
// Try optimized version if available
|
||||
if (isNewInfinispan) {
|
||||
object = event.getValue();
|
||||
} else {
|
||||
String id = event.getKey();
|
||||
object = event.getCache().get(id);
|
||||
}
|
||||
|
||||
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<String, Object> event) {
|
||||
if (event.isPre()) {
|
||||
Object object = event.getValue();
|
||||
if (object != null) {
|
||||
remove(object);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@CacheEntryInvalidated
|
||||
public void removed(CacheEntryInvalidatedEvent<String, Object> event) {
|
||||
if (event.isPre()) {
|
||||
Object object = event.getValue();
|
||||
if (object != null) {
|
||||
remove(object);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@CacheEntriesEvicted
|
||||
public void userEvicted(CacheEntriesEvictedEvent<String, Object> 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 c : realm.getClients().values()) {
|
||||
realmCache.evictCachedApplicationById(c);
|
||||
}
|
||||
|
||||
log.tracev("Realm removed realm={0}", realm.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,6 +103,12 @@ public class InfinispanRealmCache implements RealmCache {
|
||||
cache.remove(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void evictCachedApplicationById(String id) {
|
||||
logger.tracev("Evicting application {0}", id);
|
||||
cache.evict(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CachedGroup getGroup(String id) {
|
||||
if (!enabled) return null;
|
||||
|
||||
@@ -26,6 +26,8 @@ public interface RealmCache {
|
||||
|
||||
void invalidateApplication(CachedClient app);
|
||||
|
||||
void evictCachedApplicationById(String id);
|
||||
|
||||
void addCachedClient(CachedClient app);
|
||||
|
||||
void invalidateCachedApplicationById(String id);
|
||||
|
||||
@@ -7,10 +7,12 @@ import org.junit.Assert;
|
||||
import org.junit.ClassRule;
|
||||
import org.junit.Test;
|
||||
import org.keycloak.models.*;
|
||||
import org.keycloak.models.cache.infinispan.ClientAdapter;
|
||||
import org.keycloak.models.cache.infinispan.RealmAdapter;
|
||||
import org.keycloak.testsuite.rule.KeycloakRule;
|
||||
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
@@ -27,10 +29,12 @@ public class CacheTest {
|
||||
// load up cache
|
||||
KeycloakSession session = kc.startSession();
|
||||
RealmModel realm = session.realms().getRealmByName("test");
|
||||
assertTrue(realm instanceof RealmAdapter);
|
||||
ClientModel testApp = realm.getClientByClientId("test-app");
|
||||
assertTrue(testApp instanceof ClientAdapter);
|
||||
assertNotNull(testApp);
|
||||
appId = testApp.getId();
|
||||
Assert.assertTrue(testApp.isEnabled());
|
||||
assertTrue(testApp.isEnabled());
|
||||
kc.stopSession(session, true);
|
||||
}
|
||||
{
|
||||
@@ -40,16 +44,18 @@ public class CacheTest {
|
||||
// KEYCLOAK-1240 - obtain the realm via session.realms().getRealms()
|
||||
RealmModel realm = null;
|
||||
List<RealmModel> realms = session.realms().getRealms();
|
||||
|
||||
for (RealmModel current : realms) {
|
||||
assertTrue(current instanceof RealmAdapter);
|
||||
if ("test".equals(current.getName())) {
|
||||
realm = current;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Assert.assertTrue(realm instanceof RealmAdapter);
|
||||
realm.setAccessCodeLifespanLogin(200);
|
||||
ClientModel testApp = realm.getClientByClientId("test-app");
|
||||
|
||||
assertNotNull(testApp);
|
||||
testApp.setEnabled(false);
|
||||
kc.stopSession(session, true);
|
||||
@@ -62,10 +68,7 @@ public class CacheTest {
|
||||
ClientModel testApp = session.realms().getClientById(appId, realm);
|
||||
Assert.assertFalse(testApp.isEnabled());
|
||||
kc.stopSession(session, true);
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
Reference in New Issue
Block a user