keycloak-uncached

Details

diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/entities/CachedResourceServer.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/entities/CachedResourceServer.java
index a904bd1..ac07f6e 100644
--- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/entities/CachedResourceServer.java
+++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/entities/CachedResourceServer.java
@@ -27,8 +27,8 @@ import org.keycloak.representations.idm.authorization.PolicyEnforcementMode;
  */
 public class CachedResourceServer extends AbstractRevisioned {
 
-    private boolean allowRemoteResourceManagement;
-    private PolicyEnforcementMode policyEnforcementMode;
+    private final boolean allowRemoteResourceManagement;
+    private final PolicyEnforcementMode policyEnforcementMode;
 
     public CachedResourceServer(Long revision, ResourceServer resourceServer) {
         super(revision, resourceServer.getId());
@@ -43,5 +43,4 @@ public class CachedResourceServer extends AbstractRevisioned {
     public PolicyEnforcementMode getPolicyEnforcementMode() {
         return this.policyEnforcementMode;
     }
-
 }
diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/StoreFactoryCacheSession.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/StoreFactoryCacheSession.java
index 717d6a2..c2b60c7 100644
--- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/StoreFactoryCacheSession.java
+++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/StoreFactoryCacheSession.java
@@ -74,6 +74,7 @@ import org.keycloak.models.cache.infinispan.authorization.events.ResourceServerU
 import org.keycloak.models.cache.infinispan.authorization.events.ResourceUpdatedEvent;
 import org.keycloak.models.cache.infinispan.authorization.events.ScopeRemovedEvent;
 import org.keycloak.models.cache.infinispan.authorization.events.ScopeUpdatedEvent;
+import org.keycloak.models.cache.infinispan.entities.NonExistentItem;
 import org.keycloak.models.cache.infinispan.events.InvalidationEvent;
 import org.keycloak.representations.idm.authorization.AbstractPolicyRepresentation;
 import org.keycloak.storage.StorageId;
@@ -400,6 +401,15 @@ public class StoreFactoryCacheSession implements CachedStoreFactoryProvider {
         return delegate;
     }
 
+    private void setModelDoesNotExists(String id, Long loaded) {
+        if (! invalidations.contains(id)) {
+            cache.addRevisioned(new NonExistentItem(id, loaded), startupRevision);
+        }
+    }
+
+    private boolean modelMightExist(String id) {
+        return invalidations.contains(id) || cache.get(id, NonExistentItem.class) == null;
+    }
 
     protected class ResourceServerCache implements ResourceServerStore {
         @Override
@@ -425,22 +435,25 @@ public class StoreFactoryCacheSession implements CachedStoreFactoryProvider {
 
         }
 
-       @Override
+        @Override
         public ResourceServer findById(String id) {
             if (id == null) return null;
             CachedResourceServer cached = cache.get(id, CachedResourceServer.class);
             if (cached != null) {
                 logger.tracev("by id cache hit: {0}", cached.getId());
             }
-            boolean wasCached = false;
+
             if (cached == null) {
                 Long loaded = cache.getCurrentRevision(id);
+                if (! modelMightExist(id)) return null;
                 ResourceServer model = getResourceServerStoreDelegate().findById(id);
-                if (model == null) return null;
+                if (model == null) {
+                    setModelDoesNotExists(id, loaded);
+                    return null;
+                }
                 if (invalidations.contains(id)) return model;
                 cached = new CachedResourceServer(loaded, model);
                 cache.addRevisioned(cached, startupRevision);
-                wasCached =true;
             } else if (invalidations.contains(id)) {
                 return getResourceServerStoreDelegate().findById(id);
             } else if (managedResourceServers.containsKey(id)) {
@@ -484,15 +497,17 @@ public class StoreFactoryCacheSession implements CachedStoreFactoryProvider {
             if (cached != null) {
                 logger.tracev("by id cache hit: {0}", cached.getId());
             }
-            boolean wasCached = false;
             if (cached == null) {
                 Long loaded = cache.getCurrentRevision(id);
+                if (! modelMightExist(id)) return null;
                 Scope model = getScopeStoreDelegate().findById(id, resourceServerId);
-                if (model == null) return null;
+                if (model == null) {
+                    setModelDoesNotExists(id, loaded);
+                    return null;
+                }
                 if (invalidations.contains(id)) return model;
                 cached = new CachedScope(loaded, model);
                 cache.addRevisioned(cached, startupRevision);
-                wasCached =true;
             } else if (invalidations.contains(id)) {
                 return getScopeStoreDelegate().findById(id, resourceServerId);
             } else if (managedScopes.containsKey(id)) {
@@ -552,6 +567,9 @@ public class StoreFactoryCacheSession implements CachedStoreFactoryProvider {
             Resource resource = getResourceStoreDelegate().create(id, name, resourceServer, owner);
             Resource cached = findById(resource.getId(), resourceServer.getId());
             registerResourceInvalidation(resource.getId(), resource.getName(), resource.getType(), resource.getUris(), resource.getScopes().stream().map(scope -> scope.getId()).collect(Collectors.toSet()), resourceServer.getId(), resource.getOwner());
+            if (cached == null) {
+                cached = findById(resource.getId(), resourceServer.getId());
+            }
             return cached;
         }
 
@@ -575,15 +593,17 @@ public class StoreFactoryCacheSession implements CachedStoreFactoryProvider {
             if (cached != null) {
                 logger.tracev("by id cache hit: {0}", cached.getId());
             }
-            boolean wasCached = false;
             if (cached == null) {
                 Long loaded = cache.getCurrentRevision(id);
+                if (! modelMightExist(id)) return null;
                 Resource model = getResourceStoreDelegate().findById(id, resourceServerId);
-                if (model == null) return null;
+                if (model == null) {
+                    setModelDoesNotExists(id, loaded);
+                    return null;
+                }
                 if (invalidations.contains(id)) return model;
                 cached = new CachedResource(loaded, model);
                 cache.addRevisioned(cached, startupRevision);
-                wasCached =true;
             } else if (invalidations.contains(id)) {
                 return getResourceStoreDelegate().findById(id, resourceServerId);
             } else if (managedResources.containsKey(id)) {
@@ -743,6 +763,9 @@ public class StoreFactoryCacheSession implements CachedStoreFactoryProvider {
             Policy policy = getPolicyStoreDelegate().create(representation, resourceServer);
             Policy cached = findById(policy.getId(), resourceServer.getId());
             registerPolicyInvalidation(policy.getId(), representation.getName(), representation.getResources(), representation.getScopes(), null, resourceServer.getId());
+            if (cached == null) {
+                cached = findById(policy.getId(), resourceServer.getId());
+            }
             return cached;
         }
 
@@ -775,15 +798,17 @@ public class StoreFactoryCacheSession implements CachedStoreFactoryProvider {
             if (cached != null) {
                 logger.tracev("by id cache hit: {0}", cached.getId());
             }
-            boolean wasCached = false;
             if (cached == null) {
                 Long loaded = cache.getCurrentRevision(id);
+                if (! modelMightExist(id)) return null;
                 Policy model = getPolicyStoreDelegate().findById(id, resourceServerId);
-                if (model == null) return null;
+                if (model == null) {
+                    setModelDoesNotExists(id, loaded);
+                    return null;
+                }
                 if (invalidations.contains(id)) return model;
                 cached = new CachedPolicy(loaded, model);
                 cache.addRevisioned(cached, startupRevision);
-                wasCached =true;
             } else if (invalidations.contains(id)) {
                 return getPolicyStoreDelegate().findById(id, resourceServerId);
             } else if (managedPolicies.containsKey(id)) {
@@ -975,15 +1000,17 @@ public class StoreFactoryCacheSession implements CachedStoreFactoryProvider {
             if (cached != null) {
                 logger.tracev("by id cache hit: {0}", cached.getId());
             }
-            boolean wasCached = false;
             if (cached == null) {
                 Long loaded = cache.getCurrentRevision(id);
+                if (! modelMightExist(id)) return null;
                 PermissionTicket model = getPermissionTicketStoreDelegate().findById(id, resourceServerId);
-                if (model == null) return null;
+                if (model == null) {
+                    setModelDoesNotExists(id, loaded);
+                    return null;
+                }
                 if (invalidations.contains(id)) return model;
                 cached = new CachedPermissionTicket(loaded, model);
                 cache.addRevisioned(cached, startupRevision);
-                wasCached =true;
             } else if (invalidations.contains(id)) {
                 return getPermissionTicketStoreDelegate().findById(id, resourceServerId);
             } else if (managedPermissionTickets.containsKey(id)) {
diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/CacheManager.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/CacheManager.java
index 9a0839f..92116b4 100755
--- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/CacheManager.java
+++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/CacheManager.java
@@ -91,7 +91,7 @@ public abstract class CacheManager {
 
     }
 
-    public <T> T get(String id, Class<T> type) {
+    public <T extends Revisioned> T get(String id, Class<T> type) {
         Revisioned o = (Revisioned)cache.get(id);
         if (o == null) {
             return null;
diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/entities/NonExistentItem.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/entities/NonExistentItem.java
new file mode 100644
index 0000000..04d7470
--- /dev/null
+++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/entities/NonExistentItem.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2018 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.entities;
+
+/**
+ *
+ * @author hmlnarik
+ */
+public class NonExistentItem implements Revisioned {
+
+    private final String id;
+
+    private Long revision;
+
+    public NonExistentItem(String id) {
+        this.id = id;
+    }
+
+    public NonExistentItem(String id, Long revision) {
+        this.id = id;
+        this.revision = revision;
+    }
+
+    @Override
+    public String getId() {
+        return this.id;
+    }
+
+    @Override
+    public Long getRevision() {
+        return this.revision;
+    }
+
+    @Override
+    public void setRevision(Long revision) {
+        this.revision = revision;
+    }
+
+}
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/permissions/MgmtPermissions.java b/services/src/main/java/org/keycloak/services/resources/admin/permissions/MgmtPermissions.java
index b0994b8..735dd48 100644
--- a/services/src/main/java/org/keycloak/services/resources/admin/permissions/MgmtPermissions.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/permissions/MgmtPermissions.java
@@ -248,10 +248,10 @@ class MgmtPermissions implements AdminPermissionEvaluator, AdminPermissionManage
     @Override
     public ResourceServer realmResourceServer() {
         if (realmResourceServer != null) return realmResourceServer;
-        ResourceServerStore resourceServerStore = authz.getStoreFactory().getResourceServerStore();
         ClientModel client = getRealmManagementClient();
         if (client == null) return null;
-        realmResourceServer = authz.getStoreFactory().getResourceServerStore().findById(client.getId());
+        ResourceServerStore resourceServerStore = authz.getStoreFactory().getResourceServerStore();
+        realmResourceServer = resourceServerStore.findById(client.getId());
         return realmResourceServer;
 
     }