From 36c2422fa442ff3b30f351edffb9dee84d4ea0f6 Mon Sep 17 00:00:00 2001 From: Bill Burke Date: Thu, 20 Oct 2016 10:35:28 -0400 Subject: [PATCH] realm cache event --- .../models/cache/infinispan/RealmAdapter.java | 21 +++++- .../cache/infinispan/RealmCacheSession.java | 17 +++++ .../infinispan/entities/CachedRealm.java | 2 +- .../models/cache/CachedRealmModel.java | 65 +++++++++++++++++++ .../models/cache/CachedUserModel.java | 6 +- 5 files changed, 105 insertions(+), 6 deletions(-) create mode 100644 server-spi/src/main/java/org/keycloak/models/cache/CachedRealmModel.java 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 4802a6b1be..4406731726 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 @@ -36,6 +36,7 @@ import org.keycloak.models.RequiredCredentialModel; import org.keycloak.models.RoleModel; import org.keycloak.models.UserFederationMapperModel; import org.keycloak.models.UserFederationProviderModel; +import org.keycloak.models.cache.CachedRealmModel; import org.keycloak.models.cache.infinispan.entities.CachedRealm; import org.keycloak.models.utils.KeycloakModelUtils; @@ -50,12 +51,13 @@ import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; /** * @author Bill Burke * @version $Revision: 1 $ */ -public class RealmAdapter implements RealmModel { +public class RealmAdapter implements CachedRealmModel { protected CachedRealm cached; protected RealmCacheSession cacheSession; protected RealmModel updated; @@ -66,17 +68,32 @@ public class RealmAdapter implements RealmModel { this.cacheSession = cacheSession; } - protected void getDelegateForUpdate() { + @Override + public RealmModel getDelegateForUpdate() { if (updated == null) { cacheSession.registerRealmInvalidation(cached.getId()); updated = cacheSession.getDelegate().getRealm(cached.getId()); if (updated == null) throw new IllegalStateException("Not found in database"); } + return updated; } protected boolean invalidated; + + @Override public void invalidate() { invalidated = true; + getDelegateForUpdate(); + } + + @Override + public long getCacheTimestamp() { + return cached.getCacheTimestamp(); + } + + @Override + public ConcurrentHashMap getCachedWith() { + return cached.getCachedWith(); } protected boolean isUpdated() { diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/RealmCacheSession.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/RealmCacheSession.java index 6cd91a59ec..418b264b05 100755 --- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/RealmCacheSession.java +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/RealmCacheSession.java @@ -29,6 +29,7 @@ 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.CachedRealmModel; import org.keycloak.models.cache.infinispan.entities.CachedClient; import org.keycloak.models.cache.infinispan.entities.CachedClientRole; import org.keycloak.models.cache.infinispan.entities.CachedClientTemplate; @@ -374,6 +375,7 @@ public class RealmCacheSession implements CacheRealmProvider { if (cached != null) { logger.tracev("by id cache hit: {0}", cached.getName()); } + boolean wasCached = false; if (cached == null) { Long loaded = cache.getCurrentRevision(id); RealmModel model = getDelegate().getRealm(id); @@ -381,12 +383,27 @@ public class RealmCacheSession implements CacheRealmProvider { if (invalidations.contains(id)) return model; cached = new CachedRealm(loaded, model); cache.addRevisioned(cached, startupRevision); + wasCached =true; } else if (invalidations.contains(id)) { return getDelegate().getRealm(id); } else if (managedRealms.containsKey(id)) { return managedRealms.get(id); } RealmAdapter adapter = new RealmAdapter(cached, this); + if (wasCached) { + CachedRealmModel.RealmCachedEvent event = new CachedRealmModel.RealmCachedEvent() { + @Override + public CachedRealmModel getRealm() { + return adapter; + } + + @Override + public KeycloakSession getKeycloakSession() { + return session; + } + }; + session.getKeycloakSessionFactory().publish(event); + } managedRealms.put(id, adapter); return adapter; } diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/entities/CachedRealm.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/entities/CachedRealm.java index 99b718c595..4647f74f68 100755 --- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/entities/CachedRealm.java +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/entities/CachedRealm.java @@ -52,7 +52,7 @@ import java.util.Set; * @author Bill Burke * @version $Revision: 1 $ */ -public class CachedRealm extends AbstractRevisioned { +public class CachedRealm extends AbstractExtendableRevisioned { protected String name; protected String displayName; diff --git a/server-spi/src/main/java/org/keycloak/models/cache/CachedRealmModel.java b/server-spi/src/main/java/org/keycloak/models/cache/CachedRealmModel.java new file mode 100644 index 0000000000..16a965f79f --- /dev/null +++ b/server-spi/src/main/java/org/keycloak/models/cache/CachedRealmModel.java @@ -0,0 +1,65 @@ +/* + * 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; + +import org.keycloak.models.KeycloakSession; +import org.keycloak.models.RealmModel; +import org.keycloak.models.UserModel; +import org.keycloak.provider.ProviderEvent; + +import java.util.concurrent.ConcurrentHashMap; + +/** + * Cached realms will implement this interface + * + * @author Bill Burke + * @version $Revision: 1 $ + */ +public interface CachedRealmModel extends RealmModel { + + interface RealmCachedEvent extends ProviderEvent { + CachedRealmModel getRealm(); + KeycloakSession getKeycloakSession(); + } + + /** + * Invalidates the cache for this model and returns a delegate that represents the actual data provider + * + * @return + */ + RealmModel getDelegateForUpdate(); + + /** + * Invalidate the cache for this model + * + */ + void invalidate(); + + /** + * When was the model was loaded from database. + * + * @return + */ + long getCacheTimestamp(); + + /** + * Returns a map that contains custom things that are cached along with this model. You can write to this map. + * + * @return + */ + ConcurrentHashMap getCachedWith(); +} diff --git a/server-spi/src/main/java/org/keycloak/models/cache/CachedUserModel.java b/server-spi/src/main/java/org/keycloak/models/cache/CachedUserModel.java index 9ee5a6a090..67431a90f9 100644 --- a/server-spi/src/main/java/org/keycloak/models/cache/CachedUserModel.java +++ b/server-spi/src/main/java/org/keycloak/models/cache/CachedUserModel.java @@ -36,20 +36,20 @@ public interface CachedUserModel extends UserModel { UserModel getDelegateForUpdate(); /** - * Invalidate the cache for this user + * Invalidate the cache for this model * */ void invalidate(); /** - * When was the user loaded from database. + * When was the model was loaded from database. * * @return */ long getCacheTimestamp(); /** - * Returns a map that contains custom things that are cached along with the user. You can write to this map. + * Returns a map that contains custom things that are cached along with this model. You can write to this map. * * @return */