keycloak-aplcache

Changes

model/infinispan/src/main/java/org/keycloak/models/authorization/infinispan/AbstractCachedStore.java 73(+0 -73)

model/infinispan/src/main/java/org/keycloak/models/authorization/infinispan/CachedPolicyStore.java 500(+0 -500)

model/infinispan/src/main/java/org/keycloak/models/authorization/infinispan/CachedResourceServerStore.java 172(+0 -172)

model/infinispan/src/main/java/org/keycloak/models/authorization/infinispan/CachedResourceStore.java 321(+0 -321)

model/infinispan/src/main/java/org/keycloak/models/authorization/infinispan/CachedScopeStore.java 231(+0 -231)

model/infinispan/src/main/java/org/keycloak/models/authorization/infinispan/InfinispanStoreFactoryProvider.java 166(+0 -166)

model/infinispan/src/main/java/org/keycloak/models/authorization/infinispan/StoreFactoryCacheManager.java 72(+0 -72)

Details

diff --git a/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/client/ClientPolicyProviderFactory.java b/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/client/ClientPolicyProviderFactory.java
index d061357..49a54eb 100644
--- a/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/client/ClientPolicyProviderFactory.java
+++ b/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/client/ClientPolicyProviderFactory.java
@@ -107,7 +107,7 @@ public class ClientPolicyProviderFactory implements PolicyProviderFactory<Client
                             if (clients.isEmpty()) {
                                 policyStore.delete(policy.getId());
                             } else {
-                                policy.getConfig().put("clients", JsonSerialization.writeValueAsString(clients));
+                                policy.putConfig("clients", JsonSerialization.writeValueAsString(clients));
                             }
                         } catch (IOException e) {
                             throw new RuntimeException("Error while synchronizing clients with policy [" + policy.getName() + "].", e);
@@ -152,11 +152,7 @@ public class ClientPolicyProviderFactory implements PolicyProviderFactory<Client
         }
 
         try {
-            Map<String, String> config = policy.getConfig();
-
-            config.put("clients", JsonSerialization.writeValueAsString(updatedClients));
-
-            policy.setConfig(config);
+            policy.putConfig("clients", JsonSerialization.writeValueAsString(updatedClients));
         } catch (IOException cause) {
             throw new RuntimeException("Failed to serialize clients", cause);
         }
diff --git a/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/js/JSPolicyProviderFactory.java b/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/js/JSPolicyProviderFactory.java
index 1a1ed34..3e68d7f 100644
--- a/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/js/JSPolicyProviderFactory.java
+++ b/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/js/JSPolicyProviderFactory.java
@@ -70,9 +70,7 @@ public class JSPolicyProviderFactory implements PolicyProviderFactory<JSPolicyRe
     }
 
     private void updatePolicy(Policy policy, String code) {
-        Map<String, String> config = policy.getConfig();
-        config.put("code", code);
-        policy.setConfig(config);
+        policy.putConfig("code", code);
     }
 
     @Override
diff --git a/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/resource/ResourcePolicyProviderFactory.java b/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/resource/ResourcePolicyProviderFactory.java
index 6ea7230..1de28f5 100644
--- a/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/resource/ResourcePolicyProviderFactory.java
+++ b/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/resource/ResourcePolicyProviderFactory.java
@@ -1,5 +1,6 @@
 package org.keycloak.authorization.policy.provider.resource;
 
+import java.util.HashMap;
 import java.util.Map;
 
 import org.keycloak.Config;
@@ -64,7 +65,7 @@ public class ResourcePolicyProviderFactory implements PolicyProviderFactory<Reso
             //TODO: remove this check once we migrate to new API
             if (ResourcePermissionRepresentation.class.equals(representation.getClass())) {
                 ResourcePermissionRepresentation resourcePermission = ResourcePermissionRepresentation.class.cast(representation);
-                Map<String, String> config = policy.getConfig();
+                Map<String, String> config = new HashMap(policy.getConfig());
 
                 config.compute("defaultResourceType", (key, value) -> {
                     String resourceType = resourcePermission.getResourceType();
diff --git a/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/role/RolePolicyProviderFactory.java b/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/role/RolePolicyProviderFactory.java
index 03ea156..64bcf49 100644
--- a/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/role/RolePolicyProviderFactory.java
+++ b/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/role/RolePolicyProviderFactory.java
@@ -163,11 +163,7 @@ public class RolePolicyProviderFactory implements PolicyProviderFactory<RolePoli
         }
 
         try {
-            Map<String, String> config = policy.getConfig();
-
-            config.put("roles", JsonSerialization.writeValueAsString(updatedRoles));
-
-            policy.setConfig(config);
+            policy.putConfig("roles", JsonSerialization.writeValueAsString(updatedRoles));
         } catch (IOException cause) {
             throw new RuntimeException("Failed to serialize roles", cause);
         }
@@ -224,9 +220,7 @@ public class RolePolicyProviderFactory implements PolicyProviderFactory<RolePoli
                     if (roles.isEmpty()) {
                         policyStore.delete(policy.getId());
                     } else {
-                        Map<String, String> config = policy.getConfig();
-                        config.put("roles", JsonSerialization.writeValueAsString(roles));
-                        policy.setConfig(config);
+                        policy.putConfig("roles", JsonSerialization.writeValueAsString(roles));
                     }
                 } catch (IOException e) {
                     throw new RuntimeException("Error while synchronizing roles with policy [" + policy.getName() + "].", e);
diff --git a/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/time/TimePolicyProviderFactory.java b/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/time/TimePolicyProviderFactory.java
index a3958b9..fc69f3b 100644
--- a/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/time/TimePolicyProviderFactory.java
+++ b/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/time/TimePolicyProviderFactory.java
@@ -1,6 +1,7 @@
 package org.keycloak.authorization.policy.provider.time;
 
 import java.text.SimpleDateFormat;
+import java.util.HashMap;
 import java.util.Map;
 
 import org.keycloak.Config;
@@ -118,7 +119,7 @@ public class TimePolicyProviderFactory implements PolicyProviderFactory<TimePoli
             validateFormat(noa);
         }
 
-        Map<String, String> config = policy.getConfig();
+        Map<String, String> config = new HashMap(policy.getConfig());
 
         config.compute("nbf", (s, s2) -> nbf != null ? nbf : null);
         config.compute("noa", (s, s2) -> noa != null ? noa : null);
diff --git a/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/user/UserPolicyProviderFactory.java b/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/user/UserPolicyProviderFactory.java
index e4bbaf9..a21bf74 100644
--- a/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/user/UserPolicyProviderFactory.java
+++ b/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/user/UserPolicyProviderFactory.java
@@ -138,11 +138,8 @@ public class UserPolicyProviderFactory implements PolicyProviderFactory<UserPoli
         }
 
         try {
-            Map<String, String> config = policy.getConfig();
 
-            config.put("users", JsonSerialization.writeValueAsString(updatedUsers));
-
-            policy.setConfig(config);
+            policy.putConfig("users", JsonSerialization.writeValueAsString(updatedUsers));
         } catch (IOException cause) {
             throw new RuntimeException("Failed to serialize users", cause);
         }
@@ -181,7 +178,7 @@ public class UserPolicyProviderFactory implements PolicyProviderFactory<UserPoli
                                 if (users.isEmpty()) {
                                     policyStore.delete(policy.getId());
                                 } else {
-                                    policy.getConfig().put("users", JsonSerialization.writeValueAsString(users));
+                                    policy.putConfig("users", JsonSerialization.writeValueAsString(users));
                                 }
                             } catch (IOException e) {
                                 throw new RuntimeException("Error while synchronizing users with policy [" + policy.getName() + "].", e);
diff --git a/authz/policy/drools/src/main/java/org/keycloak/authorization/policy/provider/drools/DroolsPolicyProviderFactory.java b/authz/policy/drools/src/main/java/org/keycloak/authorization/policy/provider/drools/DroolsPolicyProviderFactory.java
index 1fb3c1f..0a71317 100644
--- a/authz/policy/drools/src/main/java/org/keycloak/authorization/policy/provider/drools/DroolsPolicyProviderFactory.java
+++ b/authz/policy/drools/src/main/java/org/keycloak/authorization/policy/provider/drools/DroolsPolicyProviderFactory.java
@@ -120,17 +120,15 @@ public class DroolsPolicyProviderFactory implements PolicyProviderFactory<RulePo
     }
 
     private void updateConfig(Policy policy, RulePolicyRepresentation representation) {
-        Map<String, String> config = policy.getConfig();
 
-        config.put("mavenArtifactGroupId", representation.getArtifactGroupId());
-        config.put("mavenArtifactId", representation.getArtifactId());
-        config.put("mavenArtifactVersion", representation.getArtifactVersion());
-        config.put("scannerPeriod", representation.getScannerPeriod());
-        config.put("scannerPeriodUnit", representation.getScannerPeriodUnit());
-        config.put("sessionName", representation.getSessionName());
-        config.put("moduleName", representation.getModuleName());
+        policy.putConfig("mavenArtifactGroupId", representation.getArtifactGroupId());
+        policy.putConfig("mavenArtifactId", representation.getArtifactId());
+        policy.putConfig("mavenArtifactVersion", representation.getArtifactVersion());
+        policy.putConfig("scannerPeriod", representation.getScannerPeriod());
+        policy.putConfig("scannerPeriodUnit", representation.getScannerPeriodUnit());
+        policy.putConfig("sessionName", representation.getSessionName());
+        policy.putConfig("moduleName", representation.getModuleName());
 
-        policy.setConfig(config);
     }
 
     void update(Policy policy) {
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 1394d80..17ae121 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
@@ -126,6 +126,16 @@ public class DefaultInfinispanConnectionProviderFactory implements InfinispanCon
             cacheManager.getCache(InfinispanConnectionProvider.KEYS_CACHE_NAME, true);
             cacheManager.getCache(InfinispanConnectionProvider.ACTION_TOKEN_CACHE, true);
 
+            long authzRevisionsMaxEntries = cacheManager.getCache(InfinispanConnectionProvider.AUTHORIZATION_CACHE_NAME).getCacheConfiguration().eviction().maxEntries();
+            authzRevisionsMaxEntries = authzRevisionsMaxEntries > 0
+                    ? 2 * authzRevisionsMaxEntries
+                    : InfinispanConnectionProvider.AUTHORIZATION_REVISIONS_CACHE_DEFAULT_MAX;
+
+            cacheManager.defineConfiguration(InfinispanConnectionProvider.AUTHORIZATION_REVISIONS_CACHE_NAME, getRevisionCacheConfig(authzRevisionsMaxEntries));
+            cacheManager.getCache(InfinispanConnectionProvider.AUTHORIZATION_REVISIONS_CACHE_NAME, true);
+
+
+
             logger.debugv("Using container managed Infinispan cache container, lookup={1}", cacheContainerLookup);
         } catch (Exception e) {
             throw new RuntimeException("Failed to retrieve cache container", e);
@@ -157,6 +167,7 @@ public class DefaultInfinispanConnectionProviderFactory implements InfinispanCon
         Configuration modelCacheConfiguration = modelCacheConfigBuilder.build();
 
         cacheManager.defineConfiguration(InfinispanConnectionProvider.REALM_CACHE_NAME, modelCacheConfiguration);
+        cacheManager.defineConfiguration(InfinispanConnectionProvider.AUTHORIZATION_CACHE_NAME, modelCacheConfiguration);
         cacheManager.defineConfiguration(InfinispanConnectionProvider.USER_CACHE_NAME, modelCacheConfiguration);
 
         ConfigurationBuilder sessionConfigBuilder = new ConfigurationBuilder();
@@ -186,14 +197,12 @@ public class DefaultInfinispanConnectionProviderFactory implements InfinispanCon
         cacheManager.defineConfiguration(InfinispanConnectionProvider.SESSION_CACHE_NAME, sessionCacheConfiguration);
         cacheManager.defineConfiguration(InfinispanConnectionProvider.OFFLINE_SESSION_CACHE_NAME, sessionCacheConfiguration);
         cacheManager.defineConfiguration(InfinispanConnectionProvider.LOGIN_FAILURE_CACHE_NAME, sessionCacheConfiguration);
-        cacheManager.defineConfiguration(InfinispanConnectionProvider.AUTHORIZATION_CACHE_NAME, sessionCacheConfiguration);
         cacheManager.defineConfiguration(InfinispanConnectionProvider.AUTHENTICATION_SESSIONS_CACHE_NAME, sessionCacheConfiguration);
 
         // Retrieve caches to enforce rebalance
         cacheManager.getCache(InfinispanConnectionProvider.SESSION_CACHE_NAME, true);
         cacheManager.getCache(InfinispanConnectionProvider.OFFLINE_SESSION_CACHE_NAME, true);
         cacheManager.getCache(InfinispanConnectionProvider.LOGIN_FAILURE_CACHE_NAME, true);
-        cacheManager.getCache(InfinispanConnectionProvider.AUTHORIZATION_CACHE_NAME, true);
         cacheManager.getCache(InfinispanConnectionProvider.AUTHENTICATION_SESSIONS_CACHE_NAME, true);
 
         ConfigurationBuilder replicationConfigBuilder = new ConfigurationBuilder();
@@ -236,6 +245,14 @@ public class DefaultInfinispanConnectionProviderFactory implements InfinispanCon
 
         cacheManager.defineConfiguration(InfinispanConnectionProvider.ACTION_TOKEN_CACHE, getActionTokenCacheConfig());
         cacheManager.getCache(InfinispanConnectionProvider.ACTION_TOKEN_CACHE, true);
+
+        long authzRevisionsMaxEntries = cacheManager.getCache(InfinispanConnectionProvider.AUTHORIZATION_CACHE_NAME).getCacheConfiguration().eviction().maxEntries();
+        authzRevisionsMaxEntries = authzRevisionsMaxEntries > 0
+                ? 2 * authzRevisionsMaxEntries
+                : InfinispanConnectionProvider.AUTHORIZATION_REVISIONS_CACHE_DEFAULT_MAX;
+
+        cacheManager.defineConfiguration(InfinispanConnectionProvider.AUTHORIZATION_REVISIONS_CACHE_NAME, getRevisionCacheConfig(authzRevisionsMaxEntries));
+        cacheManager.getCache(InfinispanConnectionProvider.AUTHORIZATION_REVISIONS_CACHE_NAME, true);
     }
 
     private Configuration getRevisionCacheConfig(long maxEntries) {
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
index 8e190cd..8618a69 100755
--- a/model/infinispan/src/main/java/org/keycloak/connections/infinispan/InfinispanConnectionProvider.java
+++ b/model/infinispan/src/main/java/org/keycloak/connections/infinispan/InfinispanConnectionProvider.java
@@ -39,6 +39,8 @@ public interface InfinispanConnectionProvider extends Provider {
     String AUTHENTICATION_SESSIONS_CACHE_NAME = "authenticationSessions";
     String WORK_CACHE_NAME = "work";
     String AUTHORIZATION_CACHE_NAME = "authorization";
+    String AUTHORIZATION_REVISIONS_CACHE_NAME = "authorizationRevisions";
+    int AUTHORIZATION_REVISIONS_CACHE_DEFAULT_MAX = 20000;
 
     String ACTION_TOKEN_CACHE = "actionTokens";
     int ACTION_TOKEN_CACHE_DEFAULT_MAX = -1;
diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/entities/PolicyListQuery.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/entities/PolicyListQuery.java
new file mode 100755
index 0000000..1cbf044
--- /dev/null
+++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/entities/PolicyListQuery.java
@@ -0,0 +1,36 @@
+package org.keycloak.models.cache.infinispan.authorization.entities;
+
+import org.keycloak.models.cache.infinispan.entities.AbstractRevisioned;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class PolicyListQuery extends AbstractRevisioned implements InResourceServer {
+    private final Set<String> policies;
+    private final String serverId;
+
+    public PolicyListQuery(Long revision, String id, String policyId, String serverId) {
+        super(revision, id);
+        this.serverId = serverId;
+        policies = new HashSet<>();
+        policies.add(policyId);
+    }
+    public PolicyListQuery(Long revision, String id, Set<String> policies, String serverId) {
+        super(revision, id);
+        this.serverId = serverId;
+        this.policies = policies;
+    }
+
+    @Override
+    public String getResourceServerId() {
+        return serverId;
+    }
+
+    public Set<String> getPolicies() {
+        return policies;
+    }
+}
\ No newline at end of file
diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/entities/ResourceListQuery.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/entities/ResourceListQuery.java
new file mode 100755
index 0000000..d322b62
--- /dev/null
+++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/entities/ResourceListQuery.java
@@ -0,0 +1,36 @@
+package org.keycloak.models.cache.infinispan.authorization.entities;
+
+import org.keycloak.models.cache.infinispan.entities.AbstractRevisioned;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class ResourceListQuery extends AbstractRevisioned implements InResourceServer {
+    private final Set<String> resources;
+    private final String serverId;
+
+    public ResourceListQuery(Long revision, String id, String resourceId, String serverId) {
+        super(revision, id);
+        this.serverId = serverId;
+        resources = new HashSet<>();
+        resources.add(resourceId);
+    }
+    public ResourceListQuery(Long revision, String id, Set<String> resources, String serverId) {
+        super(revision, id);
+        this.serverId = serverId;
+        this.resources = resources;
+    }
+
+    @Override
+    public String getResourceServerId() {
+        return serverId;
+    }
+
+    public Set<String> getResources() {
+        return resources;
+    }
+}
\ No newline at end of file
diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/entities/ResourceServerListQuery.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/entities/ResourceServerListQuery.java
new file mode 100755
index 0000000..7cfc122
--- /dev/null
+++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/entities/ResourceServerListQuery.java
@@ -0,0 +1,29 @@
+package org.keycloak.models.cache.infinispan.authorization.entities;
+
+import org.keycloak.models.cache.infinispan.entities.AbstractRevisioned;
+import org.keycloak.models.cache.infinispan.entities.RealmQuery;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class ResourceServerListQuery extends AbstractRevisioned {
+    private final Set<String> servers;
+
+    public ResourceServerListQuery(Long revision, String id, String serverId) {
+        super(revision, id);
+        servers = new HashSet<>();
+        servers.add(serverId);
+    }
+    public ResourceServerListQuery(Long revision, String id, Set<String> servers) {
+        super(revision, id);
+        this.servers = servers;
+    }
+
+    public Set<String> getResourceServers() {
+        return servers;
+    }
+}
\ No newline at end of file
diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/entities/ScopeListQuery.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/entities/ScopeListQuery.java
new file mode 100755
index 0000000..2579e61
--- /dev/null
+++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/entities/ScopeListQuery.java
@@ -0,0 +1,36 @@
+package org.keycloak.models.cache.infinispan.authorization.entities;
+
+import org.keycloak.models.cache.infinispan.entities.AbstractRevisioned;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class ScopeListQuery extends AbstractRevisioned implements InResourceServer {
+    private final Set<String> scopes;
+    private final String serverId;
+
+    public ScopeListQuery(Long revision, String id, String scopeId, String serverId) {
+        super(revision, id);
+        this.serverId = serverId;
+        scopes = new HashSet<>();
+        scopes.add(scopeId);
+    }
+    public ScopeListQuery(Long revision, String id, Set<String> scopes, String serverId) {
+        super(revision, id);
+        this.serverId = serverId;
+        this.scopes = scopes;
+    }
+
+    @Override
+    public String getResourceServerId() {
+        return serverId;
+    }
+
+    public Set<String> getScopes() {
+        return scopes;
+    }
+}
\ No newline at end of file
diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/PolicyRemovedEvent.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/PolicyRemovedEvent.java
new file mode 100644
index 0000000..3a721ba
--- /dev/null
+++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/PolicyRemovedEvent.java
@@ -0,0 +1,56 @@
+/*
+ * 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.authorization.events;
+
+import org.keycloak.models.cache.infinispan.authorization.StoreFactoryCacheManager;
+import org.keycloak.models.cache.infinispan.events.InvalidationEvent;
+
+import java.util.Set;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class PolicyRemovedEvent extends InvalidationEvent implements AuthorizationCacheInvalidationEvent {
+
+    private String id;
+    private String name;
+    private String serverId;
+
+    public static PolicyRemovedEvent create(String id, String name, String serverId) {
+        PolicyRemovedEvent event = new PolicyRemovedEvent();
+        event.id = id;
+        event.name = name;
+        event.serverId = serverId;
+        return event;
+    }
+
+    @Override
+    public String getId() {
+        return id;
+    }
+
+    @Override
+    public String toString() {
+        return String.format("PolicyRemovedEvent [ id=%s, name=%s]", id, name);
+    }
+
+    @Override
+    public void addInvalidations(StoreFactoryCacheManager cache, Set<String> invalidations) {
+        cache.policyRemoval(id, name, serverId, invalidations);
+    }
+}
diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/PolicyUpdatedEvent.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/PolicyUpdatedEvent.java
new file mode 100644
index 0000000..1e1d992
--- /dev/null
+++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/PolicyUpdatedEvent.java
@@ -0,0 +1,56 @@
+/*
+ * 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.authorization.events;
+
+import org.keycloak.models.cache.infinispan.authorization.StoreFactoryCacheManager;
+import org.keycloak.models.cache.infinispan.events.InvalidationEvent;
+
+import java.util.Set;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class PolicyUpdatedEvent extends InvalidationEvent implements AuthorizationCacheInvalidationEvent {
+
+    private String id;
+    private String name;
+    private String serverId;
+
+    public static PolicyUpdatedEvent create(String id, String name, String serverId) {
+        PolicyUpdatedEvent event = new PolicyUpdatedEvent();
+        event.id = id;
+        event.name = name;
+        event.serverId = serverId;
+        return event;
+    }
+
+    @Override
+    public String getId() {
+        return id;
+    }
+
+    @Override
+    public String toString() {
+        return String.format("PolicyUpdatedEvent [ id=%s, name=%s ]", id, name);
+    }
+
+    @Override
+    public void addInvalidations(StoreFactoryCacheManager cache, Set<String> invalidations) {
+        cache.policyUpdated(id, name, serverId, invalidations);
+    }
+}
diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/ResourceRemovedEvent.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/ResourceRemovedEvent.java
new file mode 100644
index 0000000..4e1a31f
--- /dev/null
+++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/ResourceRemovedEvent.java
@@ -0,0 +1,56 @@
+/*
+ * 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.authorization.events;
+
+import org.keycloak.models.cache.infinispan.authorization.StoreFactoryCacheManager;
+import org.keycloak.models.cache.infinispan.events.InvalidationEvent;
+
+import java.util.Set;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class ResourceRemovedEvent extends InvalidationEvent implements AuthorizationCacheInvalidationEvent {
+
+    private String id;
+    private String name;
+    private String serverId;
+
+    public static ResourceRemovedEvent create(String id, String name, String serverId) {
+        ResourceRemovedEvent event = new ResourceRemovedEvent();
+        event.id = id;
+        event.name = name;
+        event.serverId = serverId;
+        return event;
+    }
+
+    @Override
+    public String getId() {
+        return id;
+    }
+
+    @Override
+    public String toString() {
+        return String.format("ResourceRemovedEvent [ id=%s, name=%s ]", id, name);
+    }
+
+    @Override
+    public void addInvalidations(StoreFactoryCacheManager cache, Set<String> invalidations) {
+        cache.resourceRemoval(id, name, serverId, invalidations);
+    }
+}
diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/ResourceServerRemovedEvent.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/ResourceServerRemovedEvent.java
new file mode 100644
index 0000000..fbe5a7a
--- /dev/null
+++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/ResourceServerRemovedEvent.java
@@ -0,0 +1,54 @@
+/*
+ * 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.authorization.events;
+
+import org.keycloak.models.cache.infinispan.authorization.StoreFactoryCacheManager;
+import org.keycloak.models.cache.infinispan.events.InvalidationEvent;
+
+import java.util.Set;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class ResourceServerRemovedEvent extends InvalidationEvent implements AuthorizationCacheInvalidationEvent {
+
+    private String id;
+    private String clientId;
+
+    public static ResourceServerRemovedEvent create(String id, String clientId) {
+        ResourceServerRemovedEvent event = new ResourceServerRemovedEvent();
+        event.id = id;
+        event.clientId = clientId;
+        return event;
+    }
+
+    @Override
+    public String getId() {
+        return id;
+    }
+
+    @Override
+    public String toString() {
+        return String.format("ResourceServerRemovedEvent [ id=%s, clientId=%s ]", id, clientId);
+    }
+
+    @Override
+    public void addInvalidations(StoreFactoryCacheManager cache, Set<String> invalidations) {
+        cache.resourceServerRemoval(id, clientId, invalidations);
+    }
+}
diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/ResourceServerUpdatedEvent.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/ResourceServerUpdatedEvent.java
new file mode 100644
index 0000000..2034c9b
--- /dev/null
+++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/ResourceServerUpdatedEvent.java
@@ -0,0 +1,54 @@
+/*
+ * 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.authorization.events;
+
+import org.keycloak.models.cache.infinispan.authorization.StoreFactoryCacheManager;
+import org.keycloak.models.cache.infinispan.events.InvalidationEvent;
+
+import java.util.Set;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class ResourceServerUpdatedEvent extends InvalidationEvent implements AuthorizationCacheInvalidationEvent {
+
+    private String id;
+    private String clientId;
+
+    public static ResourceServerUpdatedEvent create(String id, String clientId) {
+        ResourceServerUpdatedEvent event = new ResourceServerUpdatedEvent();
+        event.id = id;
+        event.clientId = clientId;
+        return event;
+    }
+
+    @Override
+    public String getId() {
+        return id;
+    }
+
+    @Override
+    public String toString() {
+        return String.format("ResourceServerRemovedEvent [ id=%s, clientId=%s ]", id, clientId);
+    }
+
+    @Override
+    public void addInvalidations(StoreFactoryCacheManager cache, Set<String> invalidations) {
+        cache.resourceServerUpdated(id, clientId, invalidations);
+    }
+}
diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/ResourceUpdatedEvent.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/ResourceUpdatedEvent.java
new file mode 100644
index 0000000..113d5e0
--- /dev/null
+++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/ResourceUpdatedEvent.java
@@ -0,0 +1,56 @@
+/*
+ * 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.authorization.events;
+
+import org.keycloak.models.cache.infinispan.authorization.StoreFactoryCacheManager;
+import org.keycloak.models.cache.infinispan.events.InvalidationEvent;
+
+import java.util.Set;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class ResourceUpdatedEvent extends InvalidationEvent implements AuthorizationCacheInvalidationEvent {
+
+    private String id;
+    private String name;
+    private String serverId;
+
+    public static ResourceUpdatedEvent create(String id, String name, String serverId) {
+        ResourceUpdatedEvent event = new ResourceUpdatedEvent();
+        event.id = id;
+        event.name = name;
+        event.serverId = serverId;
+        return event;
+    }
+
+    @Override
+    public String getId() {
+        return id;
+    }
+
+    @Override
+    public String toString() {
+        return String.format("ResourceUpdatedEvent [ id=%s, name=%s ]", id, name);
+    }
+
+    @Override
+    public void addInvalidations(StoreFactoryCacheManager cache, Set<String> invalidations) {
+        cache.resourceUpdated(id, name, serverId, invalidations);
+    }
+}
diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/ScopeRemovedEvent.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/ScopeRemovedEvent.java
new file mode 100644
index 0000000..eb2747c
--- /dev/null
+++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/ScopeRemovedEvent.java
@@ -0,0 +1,56 @@
+/*
+ * 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.authorization.events;
+
+import org.keycloak.models.cache.infinispan.authorization.StoreFactoryCacheManager;
+import org.keycloak.models.cache.infinispan.events.InvalidationEvent;
+
+import java.util.Set;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class ScopeRemovedEvent extends InvalidationEvent implements AuthorizationCacheInvalidationEvent {
+
+    private String id;
+    private String name;
+    private String serverId;
+
+    public static ScopeRemovedEvent create(String id, String name, String serverId) {
+        ScopeRemovedEvent event = new ScopeRemovedEvent();
+        event.id = id;
+        event.name = name;
+        event.serverId = serverId;
+        return event;
+    }
+
+    @Override
+    public String getId() {
+        return id;
+    }
+
+    @Override
+    public String toString() {
+        return String.format("ScopeRemovedEvent [ id=%s, name=%s]", id, name);
+    }
+
+    @Override
+    public void addInvalidations(StoreFactoryCacheManager cache, Set<String> invalidations) {
+        cache.scopeRemoval(id, name, serverId, invalidations);
+    }
+}
diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/ScopeUpdatedEvent.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/ScopeUpdatedEvent.java
new file mode 100644
index 0000000..9fbbd44
--- /dev/null
+++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/ScopeUpdatedEvent.java
@@ -0,0 +1,56 @@
+/*
+ * 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.authorization.events;
+
+import org.keycloak.models.cache.infinispan.authorization.StoreFactoryCacheManager;
+import org.keycloak.models.cache.infinispan.events.InvalidationEvent;
+
+import java.util.Set;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class ScopeUpdatedEvent extends InvalidationEvent implements AuthorizationCacheInvalidationEvent {
+
+    private String id;
+    private String name;
+    private String serverId;
+
+    public static ScopeUpdatedEvent create(String id, String name, String serverId) {
+        ScopeUpdatedEvent event = new ScopeUpdatedEvent();
+        event.id = id;
+        event.name = name;
+        event.serverId = serverId;
+        return event;
+    }
+
+    @Override
+    public String getId() {
+        return id;
+    }
+
+    @Override
+    public String toString() {
+        return String.format("ScopeUpdatedEvent [ id=%s, name=%s ]", id, name);
+    }
+
+    @Override
+    public void addInvalidations(StoreFactoryCacheManager cache, Set<String> invalidations) {
+        cache.scopeUpdated(id, name, serverId, invalidations);
+    }
+}
diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/PolicyAdapter.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/PolicyAdapter.java
new file mode 100644
index 0000000..a8cd379
--- /dev/null
+++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/PolicyAdapter.java
@@ -0,0 +1,280 @@
+/*
+ * 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.authorization;
+
+import org.keycloak.authorization.model.CachedModel;
+import org.keycloak.authorization.model.Policy;
+import org.keycloak.authorization.model.Resource;
+import org.keycloak.authorization.model.ResourceServer;
+import org.keycloak.authorization.model.Scope;
+import org.keycloak.models.cache.infinispan.authorization.entities.CachedPolicy;
+import org.keycloak.representations.idm.authorization.DecisionStrategy;
+import org.keycloak.representations.idm.authorization.Logic;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class PolicyAdapter implements Policy, CachedModel<Policy> {
+    protected CachedPolicy cached;
+    protected StoreFactoryCacheSession cacheSession;
+    protected Policy updated;
+
+    public PolicyAdapter(CachedPolicy cached, StoreFactoryCacheSession cacheSession) {
+        this.cached = cached;
+        this.cacheSession = cacheSession;
+    }
+
+    @Override
+    public Policy getDelegateForUpdate() {
+        if (updated == null) {
+            cacheSession.registerPolicyInvalidation(cached.getId(), cached.getName(), cached.getResourceServerId());
+            updated = cacheSession.getPolicyStoreDelegate().findById(cached.getId(), cached.getResourceServerId());
+            if (updated == null) throw new IllegalStateException("Not found in database");
+        }
+        return updated;
+    }
+
+    protected boolean invalidated;
+
+    protected void invalidateFlag() {
+        invalidated = true;
+
+    }
+
+    @Override
+    public void invalidate() {
+        invalidated = true;
+        getDelegateForUpdate();
+    }
+
+    @Override
+    public long getCacheTimestamp() {
+        return cached.getCacheTimestamp();
+    }
+
+    protected boolean isUpdated() {
+        if (updated != null) return true;
+        if (!invalidated) return false;
+        updated = cacheSession.getPolicyStoreDelegate().findById(cached.getId(), cached.getResourceServerId());
+        if (updated == null) throw new IllegalStateException("Not found in database");
+        return true;
+    }
+
+
+    @Override
+    public String getId() {
+        if (isUpdated()) return updated.getId();
+        return cached.getId();
+    }
+
+    @Override
+    public String getName() {
+        if (isUpdated()) return updated.getName();
+        return cached.getName();
+    }
+
+    @Override
+    public void setName(String name) {
+        getDelegateForUpdate();
+        updated.setName(name);
+
+    }
+
+    @Override
+    public ResourceServer getResourceServer() {
+        return cacheSession.getResourceServerStore().findById(cached.getResourceServerId());
+    }
+
+    @Override
+    public String getType() {
+        if (isUpdated()) return updated.getType();
+        return cached.getType();
+    }
+
+    @Override
+    public DecisionStrategy getDecisionStrategy() {
+        if (isUpdated()) return updated.getDecisionStrategy();
+        return cached.getDecisionStrategy();
+    }
+
+    @Override
+    public void setDecisionStrategy(DecisionStrategy decisionStrategy) {
+        getDelegateForUpdate();
+        updated.setDecisionStrategy(decisionStrategy);
+
+    }
+
+    @Override
+    public Logic getLogic() {
+        if (isUpdated()) return updated.getLogic();
+        return cached.getLogic();
+    }
+
+    @Override
+    public void setLogic(Logic logic) {
+        getDelegateForUpdate();
+        updated.setLogic(logic);
+
+    }
+
+    @Override
+    public Map<String, String> getConfig() {
+        if (isUpdated()) return updated.getConfig();
+        return cached.getConfig();
+    }
+
+    @Override
+    public void setConfig(Map<String, String> config) {
+        getDelegateForUpdate();
+        updated.setConfig(config);
+
+    }
+
+    @Override
+    public void removeConfig(String name) {
+        getDelegateForUpdate();
+        updated.removeConfig(name);
+
+    }
+
+    @Override
+    public void putConfig(String name, String value) {
+        getDelegateForUpdate();
+        updated.putConfig(name, value);
+    }
+
+    @Override
+    public String getDescription() {
+        if (isUpdated()) return updated.getDescription();
+        return cached.getDescription();
+    }
+
+    @Override
+    public void setDescription(String description) {
+        getDelegateForUpdate();
+        updated.setDescription(description);
+    }
+
+    protected Set<Policy> associatedPolicies;
+
+    @Override
+    public Set<Policy> getAssociatedPolicies() {
+        if (isUpdated()) return updated.getAssociatedPolicies();
+        if (associatedPolicies != null) return associatedPolicies;
+        associatedPolicies = new HashSet<>();
+        for (String scopeId : cached.getAssociatedPoliciesIds()) {
+            associatedPolicies.add(cacheSession.getPolicyStore().findById(scopeId, cached.getResourceServerId()));
+        }
+        associatedPolicies = Collections.unmodifiableSet(associatedPolicies);
+        return associatedPolicies;
+    }
+
+    protected Set<Resource> resources;
+    @Override
+    public Set<Resource> getResources() {
+        if (isUpdated()) return updated.getResources();
+        if (resources != null) return resources;
+        resources = new HashSet<>();
+        for (String resourceId : cached.getResourcesIds()) {
+            resources.add(cacheSession.getResourceStore().findById(resourceId, cached.getResourceServerId()));
+        }
+        resources = Collections.unmodifiableSet(resources);
+        return resources;
+    }
+
+    @Override
+    public void addScope(Scope scope) {
+        getDelegateForUpdate();
+        updated.addScope(scope);
+
+    }
+
+    @Override
+    public void removeScope(Scope scope) {
+        getDelegateForUpdate();
+        updated.removeScope(scope);
+
+    }
+
+    @Override
+    public void addAssociatedPolicy(Policy associatedPolicy) {
+        getDelegateForUpdate();
+        updated.addAssociatedPolicy(associatedPolicy);
+
+    }
+
+    @Override
+    public void removeAssociatedPolicy(Policy associatedPolicy) {
+        getDelegateForUpdate();
+        updated.removeAssociatedPolicy(associatedPolicy);
+
+    }
+
+    @Override
+    public void addResource(Resource resource) {
+        getDelegateForUpdate();
+        updated.addResource(resource);
+
+    }
+
+    @Override
+    public void removeResource(Resource resource) {
+        getDelegateForUpdate();
+        updated.removeResource(resource);
+
+    }
+
+    protected Set<Scope> scopes;
+
+    @Override
+    public Set<Scope> getScopes() {
+        if (isUpdated()) return updated.getScopes();
+        if (scopes != null) return scopes;
+        scopes = new HashSet<>();
+        for (String scopeId : cached.getScopesIds()) {
+            scopes.add(cacheSession.getScopeStore().findById(scopeId, cached.getResourceServerId()));
+        }
+        scopes = Collections.unmodifiableSet(scopes);
+        return scopes;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || !(o instanceof Policy)) return false;
+
+        Policy that = (Policy) o;
+        return that.getId().equals(getId());
+    }
+
+    @Override
+    public int hashCode() {
+        return getId().hashCode();
+    }
+
+
+
+
+}
diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/ResourceAdapter.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/ResourceAdapter.java
new file mode 100644
index 0000000..d44cc7c
--- /dev/null
+++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/ResourceAdapter.java
@@ -0,0 +1,184 @@
+/*
+ * 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.authorization;
+
+import org.keycloak.authorization.model.CachedModel;
+import org.keycloak.authorization.model.Resource;
+import org.keycloak.authorization.model.ResourceServer;
+import org.keycloak.authorization.model.Scope;
+import org.keycloak.models.cache.infinispan.authorization.entities.CachedResource;
+
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class ResourceAdapter implements Resource, CachedModel<Resource> {
+    protected CachedResource cached;
+    protected StoreFactoryCacheSession cacheSession;
+    protected Resource updated;
+
+    public ResourceAdapter(CachedResource cached, StoreFactoryCacheSession cacheSession) {
+        this.cached = cached;
+        this.cacheSession = cacheSession;
+    }
+
+    @Override
+    public Resource getDelegateForUpdate() {
+        if (updated == null) {
+            cacheSession.registerResourceInvalidation(cached.getId(), cached.getName(), cached.getResourceServerId());
+            updated = cacheSession.getResourceStoreDelegate().findById(cached.getId(), cached.getResourceServerId());
+            if (updated == null) throw new IllegalStateException("Not found in database");
+        }
+        return updated;
+    }
+
+    protected boolean invalidated;
+
+    protected void invalidateFlag() {
+        invalidated = true;
+
+    }
+
+    @Override
+    public void invalidate() {
+        invalidated = true;
+        getDelegateForUpdate();
+    }
+
+    @Override
+    public long getCacheTimestamp() {
+        return cached.getCacheTimestamp();
+    }
+
+    protected boolean isUpdated() {
+        if (updated != null) return true;
+        if (!invalidated) return false;
+        updated = cacheSession.getResourceStoreDelegate().findById(cached.getId(), cached.getResourceServerId());
+        if (updated == null) throw new IllegalStateException("Not found in database");
+        return true;
+    }
+
+
+    @Override
+    public String getId() {
+        if (isUpdated()) return updated.getId();
+        return cached.getId();
+    }
+
+    @Override
+    public String getName() {
+        if (isUpdated()) return updated.getName();
+        return cached.getName();
+    }
+
+    @Override
+    public void setName(String name) {
+        getDelegateForUpdate();
+        updated.setName(name);
+
+    }
+
+    @Override
+    public String getIconUri() {
+        if (isUpdated()) return updated.getIconUri();
+        return cached.getIconUri();
+    }
+
+    @Override
+    public void setIconUri(String iconUri) {
+        getDelegateForUpdate();
+        updated.setIconUri(iconUri);
+
+    }
+
+    @Override
+    public ResourceServer getResourceServer() {
+        return cacheSession.getResourceServerStore().findById(cached.getResourceServerId());
+    }
+
+    @Override
+    public String getUri() {
+        if (isUpdated()) return updated.getUri();
+        return cached.getUri();
+    }
+
+    @Override
+    public void setUri(String uri) {
+        getDelegateForUpdate();
+        updated.setUri(uri);
+
+    }
+
+    @Override
+    public String getType() {
+        if (isUpdated()) return updated.getType();
+        return cached.getType();
+    }
+
+    @Override
+    public void setType(String type) {
+        getDelegateForUpdate();
+        updated.setType(type);
+
+    }
+
+    protected List<Scope> scopes;
+
+    @Override
+    public List<Scope> getScopes() {
+        if (isUpdated()) return updated.getScopes();
+        if (scopes != null) return scopes;
+        scopes = new LinkedList<>();
+        for (String scopeId : cached.getScopesIds()) {
+            scopes.add(cacheSession.getScopeStore().findById(scopeId, cached.getResourceServerId()));
+        }
+        scopes = Collections.unmodifiableList(scopes);
+        return scopes;
+    }
+
+    @Override
+    public String getOwner() {
+        if (isUpdated()) return updated.getOwner();
+        return cached.getOwner();
+    }
+
+    @Override
+    public void updateScopes(Set<Scope> scopes) {
+        getDelegateForUpdate();
+        updated.updateScopes(scopes);
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || !(o instanceof Resource)) return false;
+
+        Resource that = (Resource) o;
+        return that.getId().equals(getId());
+    }
+
+    @Override
+    public int hashCode() {
+        return getId().hashCode();
+    }
+
+}
diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/ResourceServerAdapter.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/ResourceServerAdapter.java
new file mode 100644
index 0000000..bb3ec6c
--- /dev/null
+++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/ResourceServerAdapter.java
@@ -0,0 +1,127 @@
+/*
+ * 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.authorization;
+
+import org.keycloak.authorization.model.CachedModel;
+import org.keycloak.authorization.model.ResourceServer;
+import org.keycloak.models.cache.infinispan.authorization.entities.CachedResourceServer;
+import org.keycloak.representations.idm.authorization.PolicyEnforcementMode;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class ResourceServerAdapter implements ResourceServer, CachedModel<ResourceServer> {
+    protected CachedResourceServer cached;
+    protected StoreFactoryCacheSession cacheSession;
+    protected ResourceServer updated;
+
+    public ResourceServerAdapter(CachedResourceServer cached, StoreFactoryCacheSession cacheSession) {
+        this.cached = cached;
+        this.cacheSession = cacheSession;
+    }
+
+    @Override
+    public ResourceServer getDelegateForUpdate() {
+        if (updated == null) {
+            cacheSession.registerResourceServerInvalidation(cached.getId(), cached.getClientId());
+            updated = cacheSession.getResourceServerStoreDelegate().findById(cached.getId());
+            if (updated == null) throw new IllegalStateException("Not found in database");
+        }
+        return updated;
+    }
+
+    protected boolean invalidated;
+
+    protected void invalidateFlag() {
+        invalidated = true;
+
+    }
+
+    @Override
+    public void invalidate() {
+        invalidated = true;
+        getDelegateForUpdate();
+    }
+
+    @Override
+    public long getCacheTimestamp() {
+        return cached.getCacheTimestamp();
+    }
+
+    protected boolean isUpdated() {
+        if (updated != null) return true;
+        if (!invalidated) return false;
+        updated = cacheSession.getResourceServerStoreDelegate().findById(cached.getId());
+        if (updated == null) throw new IllegalStateException("Not found in database");
+        return true;
+    }
+
+
+    @Override
+    public String getId() {
+        if (isUpdated()) return updated.getId();
+        return cached.getId();
+    }
+
+    @Override
+    public String getClientId() {
+        if (isUpdated()) return updated.getClientId();
+        return cached.getClientId();
+    }
+
+    @Override
+    public boolean isAllowRemoteResourceManagement() {
+        if (isUpdated()) return updated.isAllowRemoteResourceManagement();
+        return cached.isAllowRemoteResourceManagement();
+    }
+
+    @Override
+    public void setAllowRemoteResourceManagement(boolean allowRemoteResourceManagement) {
+        getDelegateForUpdate();
+        updated.setAllowRemoteResourceManagement(allowRemoteResourceManagement);
+    }
+
+    @Override
+    public PolicyEnforcementMode getPolicyEnforcementMode() {
+        if (isUpdated()) return updated.getPolicyEnforcementMode();
+        return cached.getPolicyEnforcementMode();
+    }
+
+    @Override
+    public void setPolicyEnforcementMode(PolicyEnforcementMode enforcementMode) {
+        getDelegateForUpdate();
+        updated.setPolicyEnforcementMode(enforcementMode);
+
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || !(o instanceof ResourceServer)) return false;
+
+        ResourceServer that = (ResourceServer) o;
+        return that.getId().equals(getId());
+    }
+
+    @Override
+    public int hashCode() {
+        return getId().hashCode();
+    }
+
+
+}
diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/ScopeAdapter.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/ScopeAdapter.java
new file mode 100644
index 0000000..d90b27a
--- /dev/null
+++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/ScopeAdapter.java
@@ -0,0 +1,127 @@
+/*
+ * 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.authorization;
+
+import org.keycloak.authorization.model.CachedModel;
+import org.keycloak.authorization.model.ResourceServer;
+import org.keycloak.authorization.model.Scope;
+import org.keycloak.models.cache.infinispan.authorization.entities.CachedScope;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class ScopeAdapter implements Scope, CachedModel<Scope> {
+    protected CachedScope cached;
+    protected StoreFactoryCacheSession cacheSession;
+    protected Scope updated;
+
+    public ScopeAdapter(CachedScope cached, StoreFactoryCacheSession cacheSession) {
+        this.cached = cached;
+        this.cacheSession = cacheSession;
+    }
+
+    @Override
+    public Scope getDelegateForUpdate() {
+        if (updated == null) {
+            cacheSession.registerScopeInvalidation(cached.getId(), cached.getName(), cached.getResourceServerId());
+            updated = cacheSession.getScopeStoreDelegate().findById(cached.getId(), cached.getResourceServerId());
+            if (updated == null) throw new IllegalStateException("Not found in database");
+        }
+        return updated;
+    }
+
+    protected boolean invalidated;
+
+    protected void invalidateFlag() {
+        invalidated = true;
+
+    }
+
+    @Override
+    public void invalidate() {
+        invalidated = true;
+        getDelegateForUpdate();
+    }
+
+    @Override
+    public long getCacheTimestamp() {
+        return cached.getCacheTimestamp();
+    }
+
+    protected boolean isUpdated() {
+        if (updated != null) return true;
+        if (!invalidated) return false;
+        updated = cacheSession.getScopeStoreDelegate().findById(cached.getId(), cached.getResourceServerId());
+        if (updated == null) throw new IllegalStateException("Not found in database");
+        return true;
+    }
+
+
+    @Override
+    public String getId() {
+        if (isUpdated()) return updated.getId();
+        return cached.getId();
+    }
+
+    @Override
+    public String getName() {
+        if (isUpdated()) return updated.getName();
+        return cached.getName();
+    }
+
+    @Override
+    public void setName(String name) {
+        getDelegateForUpdate();
+        updated.setName(name);
+
+    }
+
+    @Override
+    public String getIconUri() {
+        if (isUpdated()) return updated.getIconUri();
+        return cached.getIconUri();
+    }
+
+    @Override
+    public void setIconUri(String iconUri) {
+        getDelegateForUpdate();
+        updated.setIconUri(iconUri);
+
+    }
+
+    @Override
+    public ResourceServer getResourceServer() {
+        return cacheSession.getResourceServerStore().findById(cached.getResourceServerId());
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || !(o instanceof Scope)) return false;
+
+        Scope that = (Scope) o;
+        return that.getId().equals(getId());
+    }
+
+    @Override
+    public int hashCode() {
+        return getId().hashCode();
+    }
+
+
+}
diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/StoreFactoryCacheManager.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/StoreFactoryCacheManager.java
new file mode 100644
index 0000000..2c86648
--- /dev/null
+++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/StoreFactoryCacheManager.java
@@ -0,0 +1,93 @@
+/*
+ * 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.authorization;
+
+import org.infinispan.Cache;
+import org.jboss.logging.Logger;
+import org.keycloak.models.cache.infinispan.CacheManager;
+import org.keycloak.models.cache.infinispan.RealmCacheManager;
+import org.keycloak.models.cache.infinispan.authorization.events.AuthorizationCacheInvalidationEvent;
+import org.keycloak.models.cache.infinispan.authorization.stream.InResourceServerPredicate;
+import org.keycloak.models.cache.infinispan.entities.Revisioned;
+import org.keycloak.models.cache.infinispan.events.InvalidationEvent;
+
+import java.util.Set;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class StoreFactoryCacheManager extends CacheManager {
+    private static final Logger logger = Logger.getLogger(RealmCacheManager.class);
+
+    public StoreFactoryCacheManager(Cache<String, Revisioned> cache, Cache<String, Long> revisions) {
+        super(cache, revisions);
+    }
+    @Override
+    protected Logger getLogger() {
+        return logger;
+    }
+
+    @Override
+    protected void addInvalidationsFromEvent(InvalidationEvent event, Set<String> invalidations) {
+        if (event instanceof AuthorizationCacheInvalidationEvent) {
+            invalidations.add(event.getId());
+
+            ((AuthorizationCacheInvalidationEvent) event).addInvalidations(this, invalidations);
+        }
+    }
+
+    public void resourceServerUpdated(String id, String clientId, Set<String> invalidations) {
+        invalidations.add(id);
+        invalidations.add(StoreFactoryCacheSession.getResourceServerByClientCacheKey(clientId));
+    }
+
+    public void resourceServerRemoval(String id, String name, Set<String> invalidations) {
+        resourceServerUpdated(id, name, invalidations);
+
+        addInvalidations(InResourceServerPredicate.create().resourceServer(id), invalidations);
+    }
+
+    public void scopeUpdated(String id, String name, String serverId, Set<String> invalidations) {
+        invalidations.add(id);
+        invalidations.add(StoreFactoryCacheSession.getScopeByNameCacheKey(name, serverId));
+    }
+
+    public void scopeRemoval(String id, String name, String serverId, Set<String> invalidations) {
+        scopeUpdated(id, name, serverId, invalidations);
+    }
+
+    public void resourceUpdated(String id, String name, String serverId, Set<String> invalidations) {
+        invalidations.add(id);
+        invalidations.add(StoreFactoryCacheSession.getResourceByNameCacheKey(name, serverId));
+    }
+
+    public void resourceRemoval(String id, String name, String serverId, Set<String> invalidations) {
+        resourceUpdated(id, name, serverId, invalidations);
+    }
+
+    public void policyUpdated(String id, String name, String serverId, Set<String> invalidations) {
+        invalidations.add(id);
+        invalidations.add(StoreFactoryCacheSession.getPolicyByNameCacheKey(name, serverId));
+    }
+
+    public void policyRemoval(String id, String name, String serverId, Set<String> invalidations) {
+        policyUpdated(id, name, serverId, invalidations);
+    }
+
+
+}
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
new file mode 100644
index 0000000..87f311b
--- /dev/null
+++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/StoreFactoryCacheSession.java
@@ -0,0 +1,667 @@
+/*
+ * 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.authorization;
+
+import org.jboss.logging.Logger;
+import org.keycloak.authorization.model.Policy;
+import org.keycloak.authorization.model.Resource;
+import org.keycloak.authorization.model.ResourceServer;
+import org.keycloak.authorization.model.Scope;
+import org.keycloak.authorization.store.PolicyStore;
+import org.keycloak.authorization.store.ResourceServerStore;
+import org.keycloak.authorization.store.ResourceStore;
+import org.keycloak.authorization.store.ScopeStore;
+import org.keycloak.authorization.store.StoreFactory;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.KeycloakTransaction;
+import org.keycloak.models.cache.authorization.CachedStoreFactoryProvider;
+import org.keycloak.models.cache.infinispan.authorization.entities.CachedPolicy;
+import org.keycloak.models.cache.infinispan.authorization.entities.CachedResource;
+import org.keycloak.models.cache.infinispan.authorization.entities.CachedResourceServer;
+import org.keycloak.models.cache.infinispan.authorization.entities.CachedScope;
+import org.keycloak.models.cache.infinispan.authorization.entities.PolicyListQuery;
+import org.keycloak.models.cache.infinispan.authorization.entities.ResourceListQuery;
+import org.keycloak.models.cache.infinispan.authorization.entities.ResourceServerListQuery;
+import org.keycloak.models.cache.infinispan.authorization.entities.ScopeListQuery;
+import org.keycloak.models.cache.infinispan.authorization.events.PolicyRemovedEvent;
+import org.keycloak.models.cache.infinispan.authorization.events.PolicyUpdatedEvent;
+import org.keycloak.models.cache.infinispan.authorization.events.ResourceRemovedEvent;
+import org.keycloak.models.cache.infinispan.authorization.events.ResourceServerRemovedEvent;
+import org.keycloak.models.cache.infinispan.authorization.events.ResourceServerUpdatedEvent;
+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.events.InvalidationEvent;
+import org.keycloak.representations.idm.authorization.AbstractPolicyRepresentation;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class StoreFactoryCacheSession implements CachedStoreFactoryProvider {
+    protected static final Logger logger = Logger.getLogger(StoreFactoryCacheSession.class);
+
+    protected StoreFactoryCacheManager cache;
+    protected boolean transactionActive;
+    protected boolean setRollbackOnly;
+
+    protected Map<String, ResourceServerAdapter> managedResourceServers = new HashMap<>();
+    protected Map<String, ScopeAdapter> managedScopes = new HashMap<>();
+    protected Map<String, ResourceAdapter> managedResources = new HashMap<>();
+    protected Map<String, PolicyAdapter> managedPolicies = new HashMap<>();
+    protected Set<String> invalidations = new HashSet<>();
+    protected Set<InvalidationEvent> invalidationEvents = new HashSet<>(); // Events to be sent across cluster
+
+    protected boolean clearAll;
+    protected final long startupRevision;
+    protected StoreFactory delegate;
+    protected KeycloakSession session;
+    protected ResourceServerCache resourceServerCache;
+    protected ScopeCache scopeCache;
+    protected ResourceCache resourceCache;
+    protected PolicyCache policyCache;
+
+    public StoreFactoryCacheSession(StoreFactoryCacheManager cache, KeycloakSession session) {
+        this.cache = cache;
+        this.startupRevision = cache.getCurrentCounter();
+        this.session = session;
+        this.resourceServerCache = new ResourceServerCache();
+        this.scopeCache = new ScopeCache();
+        this.resourceCache = new ResourceCache();
+        this.policyCache = new PolicyCache();
+        session.getTransactionManager().enlistPrepare(getPrepareTransaction());
+        session.getTransactionManager().enlistAfterCompletion(getAfterTransaction());
+    }
+
+    @Override
+    public ResourceServerStore getResourceServerStore() {
+        return resourceServerCache;
+    }
+
+    @Override
+    public ScopeStore getScopeStore() {
+        return scopeCache;
+    }
+
+    @Override
+    public ResourceStore getResourceStore() {
+        return resourceCache;
+    }
+
+    @Override
+    public PolicyStore getPolicyStore() {
+        return policyCache;
+    }
+
+    public void close() {
+    }
+
+    private KeycloakTransaction getPrepareTransaction() {
+        return new KeycloakTransaction() {
+            @Override
+            public void begin() {
+                transactionActive = true;
+            }
+
+            @Override
+            public void commit() {
+            }
+
+            @Override
+            public void rollback() {
+                setRollbackOnly = true;
+                transactionActive = false;
+            }
+
+            @Override
+            public void setRollbackOnly() {
+                setRollbackOnly = true;
+            }
+
+            @Override
+            public boolean getRollbackOnly() {
+                return setRollbackOnly;
+            }
+
+            @Override
+            public boolean isActive() {
+                return transactionActive;
+            }
+        };
+    }
+
+    private KeycloakTransaction getAfterTransaction() {
+        return new KeycloakTransaction() {
+            @Override
+            public void begin() {
+                transactionActive = true;
+            }
+
+            @Override
+            public void commit() {
+                try {
+                    if (getDelegate() == null) return;
+                    if (clearAll) {
+                        cache.clear();
+                    }
+                    runInvalidations();
+                    transactionActive = false;
+                } finally {
+                    cache.endRevisionBatch();
+                }
+            }
+
+            @Override
+            public void rollback() {
+                try {
+                    setRollbackOnly = true;
+                    runInvalidations();
+                    transactionActive = false;
+                } finally {
+                    cache.endRevisionBatch();
+                }
+            }
+
+            @Override
+            public void setRollbackOnly() {
+                setRollbackOnly = true;
+            }
+
+            @Override
+            public boolean getRollbackOnly() {
+                return setRollbackOnly;
+            }
+
+            @Override
+            public boolean isActive() {
+                return transactionActive;
+            }
+        };
+    }
+
+    protected void runInvalidations() {
+        for (String id : invalidations) {
+            cache.invalidateObject(id);
+        }
+
+        cache.sendInvalidationEvents(session, invalidationEvents);
+    }
+
+
+
+    public long getStartupRevision() {
+        return startupRevision;
+    }
+
+    public boolean isInvalid(String id) {
+        return invalidations.contains(id);
+    }
+
+    public void registerResourceServerInvalidation(String id, String clientId) {
+        cache.resourceServerUpdated(id, clientId, invalidations);
+        ResourceServerAdapter adapter = managedResourceServers.get(id);
+        if (adapter != null) adapter.invalidateFlag();
+
+        invalidationEvents.add(ResourceServerUpdatedEvent.create(id, clientId));
+    }
+
+    public void registerScopeInvalidation(String id, String name, String serverId) {
+        cache.scopeUpdated(id, name, serverId, invalidations);
+        ScopeAdapter adapter = managedScopes.get(id);
+        if (adapter != null) adapter.invalidateFlag();
+
+        invalidationEvents.add(ScopeUpdatedEvent.create(id, name, serverId));
+    }
+
+    public void registerResourceInvalidation(String id, String name, String serverId) {
+        cache.resourceUpdated(id, name, serverId, invalidations);
+        ResourceAdapter adapter = managedResources.get(id);
+        if (adapter != null) adapter.invalidateFlag();
+
+        invalidationEvents.add(ResourceUpdatedEvent.create(id, name, serverId));
+    }
+
+    public void registerPolicyInvalidation(String id, String name, String serverId) {
+        cache.policyUpdated(id, name, serverId, invalidations);
+        PolicyAdapter adapter = managedPolicies.get(id);
+        if (adapter != null) adapter.invalidateFlag();
+
+        invalidationEvents.add(PolicyUpdatedEvent.create(id, name, serverId));
+    }
+
+    public ResourceServerStore getResourceServerStoreDelegate() {
+        return getDelegate().getResourceServerStore();
+    }
+
+    public ScopeStore getScopeStoreDelegate() {
+        return getDelegate().getScopeStore();
+    }
+
+    public ResourceStore getResourceStoreDelegate() {
+        return getDelegate().getResourceStore();
+    }
+
+    public PolicyStore getPolicyStoreDelegate() {
+        return getDelegate().getPolicyStore();
+    }
+
+    public static String getResourceServerByClientCacheKey(String clientId) {
+        return "resource.server.client.id." + clientId;
+    }
+
+    public static String getScopeByNameCacheKey(String name, String serverId) {
+        return "scope.name." + name + "." + serverId;
+    }
+
+    public static String getResourceByNameCacheKey(String name, String serverId) {
+        return "resource.name." + name + "." + serverId;
+    }
+
+    public static String getPolicyByNameCacheKey(String name, String serverId) {
+        return "policy.name." + name + "." + serverId;
+    }
+
+    public StoreFactory getDelegate() {
+        if (delegate != null) return delegate;
+        delegate = session.getProvider(StoreFactory.class);
+        return delegate;
+    }
+
+
+    protected class ResourceServerCache implements ResourceServerStore {
+        @Override
+        public ResourceServer create(String clientId) {
+            ResourceServer server = getResourceServerStoreDelegate().create(clientId);
+            registerResourceServerInvalidation(server.getId(), server.getClientId());
+            return server;
+        }
+
+        @Override
+        public void delete(String id) {
+            if (id == null) return;
+            ResourceServer server = findById(id);
+            if (server == null) return;
+
+            cache.invalidateObject(id);
+            invalidationEvents.add(ResourceServerRemovedEvent.create(id, server.getClientId()));
+            cache.resourceServerRemoval(id, server.getClientId(), invalidations);
+            getResourceServerStoreDelegate().delete(id);
+
+        }
+
+       @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);
+                ResourceServer model = getResourceServerStoreDelegate().findById(id);
+                if (model == null) 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)) {
+                return managedResourceServers.get(id);
+            }
+            ResourceServerAdapter adapter = new ResourceServerAdapter(cached, StoreFactoryCacheSession.this);
+             managedResourceServers.put(id, adapter);
+            return adapter;
+        }
+
+
+        @Override
+        public ResourceServer findByClient(String clientId) {
+            String cacheKey = getResourceServerByClientCacheKey(clientId);
+            ResourceServerListQuery query = cache.get(cacheKey, ResourceServerListQuery.class);
+            if (query != null) {
+                logger.tracev("ResourceServer by clientId cache hit: {0}", clientId);
+            }
+            if (query == null) {
+                Long loaded = cache.getCurrentRevision(cacheKey);
+                ResourceServer model = getResourceServerStoreDelegate().findByClient(clientId);
+                if (model == null) return null;
+                if (invalidations.contains(model.getId())) return model;
+                query = new ResourceServerListQuery(loaded, cacheKey, model.getId());
+                cache.addRevisioned(query, startupRevision);
+                return model;
+            } else if (invalidations.contains(cacheKey)) {
+                return getResourceServerStoreDelegate().findByClient(clientId);
+            } else {
+                String serverId = query.getResourceServers().iterator().next();
+                if (invalidations.contains(serverId)) {
+                    return getResourceServerStoreDelegate().findByClient(clientId);
+                }
+                return findById(serverId);
+            }
+        }
+    }
+
+    protected class ScopeCache implements ScopeStore {
+        @Override
+        public Scope create(String name, ResourceServer resourceServer) {
+            Scope scope = getScopeStoreDelegate().create(name, resourceServer);
+            registerScopeInvalidation(scope.getId(), scope.getName(), resourceServer.getId());
+            return scope;
+        }
+
+        @Override
+        public void delete(String id) {
+            if (id == null) return;
+            Scope scope = findById(id, null);
+            if (scope == null) return;
+
+            cache.invalidateObject(id);
+            invalidationEvents.add(ScopeRemovedEvent.create(id, scope.getName(), scope.getResourceServer().getId()));
+            cache.scopeRemoval(id, scope.getName(), scope.getResourceServer().getId(), invalidations);
+            getScopeStoreDelegate().delete(id);
+        }
+
+        @Override
+        public Scope findById(String id, String resourceServerId) {
+            if (id == null) return null;
+            CachedScope cached = cache.get(id, CachedScope.class);
+            if (cached != null) {
+                logger.tracev("by id cache hit: {0}", cached.getId());
+            }
+            boolean wasCached = false;
+            if (cached == null) {
+                Long loaded = cache.getCurrentRevision(id);
+                Scope model = getScopeStoreDelegate().findById(id, resourceServerId);
+                if (model == null) 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)) {
+                return managedScopes.get(id);
+            }
+            ScopeAdapter adapter = new ScopeAdapter(cached, StoreFactoryCacheSession.this);
+            managedScopes.put(id, adapter);
+            return adapter;
+        }
+
+        @Override
+        public Scope findByName(String name, String resourceServerId) {
+            if (name == null) return null;
+            String cacheKey = getScopeByNameCacheKey(name, resourceServerId);
+            ScopeListQuery query = cache.get(cacheKey, ScopeListQuery.class);
+            if (query != null) {
+                logger.tracev("scope by name cache hit: {0}", name);
+            }
+            if (query == null) {
+                Long loaded = cache.getCurrentRevision(cacheKey);
+                Scope model = getScopeStoreDelegate().findByName(name, resourceServerId);
+                if (model == null) return null;
+                if (invalidations.contains(model.getId())) return model;
+                query = new ScopeListQuery(loaded, cacheKey, model.getId(), resourceServerId);
+                cache.addRevisioned(query, startupRevision);
+                return model;
+            } else if (invalidations.contains(cacheKey)) {
+                return getScopeStoreDelegate().findByName(name, resourceServerId);
+            } else {
+                String id = query.getScopes().iterator().next();
+                if (invalidations.contains(id)) {
+                    return getScopeStoreDelegate().findByName(name, resourceServerId);
+                }
+                return findById(id, query.getResourceServerId());
+            }
+        }
+
+        @Override
+        public List<Scope> findByResourceServer(String id) {
+            return getScopeStoreDelegate().findByResourceServer(id);
+        }
+
+        @Override
+        public List<Scope> findByResourceServer(Map<String, String[]> attributes, String resourceServerId, int firstResult, int maxResult) {
+            return getScopeStoreDelegate().findByResourceServer(attributes, resourceServerId, firstResult, maxResult);
+        }
+    }
+
+    protected class ResourceCache implements ResourceStore {
+        @Override
+        public Resource create(String name, ResourceServer resourceServer, String owner) {
+            Resource resource = getResourceStoreDelegate().create(name, resourceServer, owner);
+            registerResourceInvalidation(resource.getId(), resource.getName(), resourceServer.getId());
+            return resource;
+        }
+
+        @Override
+        public void delete(String id) {
+            if (id == null) return;
+            Resource resource = findById(id, null);
+            if (resource == null) return;
+
+            cache.invalidateObject(id);
+            invalidationEvents.add(ResourceRemovedEvent.create(id, resource.getName(), resource.getResourceServer().getId()));
+            cache.resourceRemoval(id, resource.getName(), resource.getResourceServer().getId(), invalidations);
+            getResourceStoreDelegate().delete(id);
+
+        }
+
+        @Override
+        public Resource findById(String id, String resourceServerId) {
+            if (id == null) return null;
+            CachedResource cached = cache.get(id, CachedResource.class);
+            if (cached != null) {
+                logger.tracev("by id cache hit: {0}", cached.getId());
+            }
+            boolean wasCached = false;
+            if (cached == null) {
+                Long loaded = cache.getCurrentRevision(id);
+                Resource model = getResourceStoreDelegate().findById(id, resourceServerId);
+                if (model == null) 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)) {
+                return managedResources.get(id);
+            }
+            ResourceAdapter adapter = new ResourceAdapter(cached, StoreFactoryCacheSession.this);
+            managedResources.put(id, adapter);
+            return adapter;
+        }
+
+        @Override
+        public Resource findByName(String name, String resourceServerId) {
+            if (name == null) return null;
+            String cacheKey = getResourceByNameCacheKey(name, resourceServerId);
+            ResourceListQuery query = cache.get(cacheKey, ResourceListQuery.class);
+            if (query != null) {
+                logger.tracev("resource by name cache hit: {0}", name);
+            }
+            if (query == null) {
+                Long loaded = cache.getCurrentRevision(cacheKey);
+                Resource model = getResourceStoreDelegate().findByName(name, resourceServerId);
+                if (model == null) return null;
+                if (invalidations.contains(model.getId())) return model;
+                query = new ResourceListQuery(loaded, cacheKey, model.getId(), resourceServerId);
+                cache.addRevisioned(query, startupRevision);
+                return model;
+            } else if (invalidations.contains(cacheKey)) {
+                return getResourceStoreDelegate().findByName(name, resourceServerId);
+            } else {
+                String id = query.getResources().iterator().next();
+                if (invalidations.contains(id)) {
+                    return getResourceStoreDelegate().findByName(name, resourceServerId);
+                }
+                return findById(id, query.getResourceServerId());
+            }
+        }
+
+        @Override
+        public List<Resource> findByOwner(String ownerId, String resourceServerId) {
+            return getResourceStoreDelegate().findByOwner(ownerId, resourceServerId);
+        }
+
+        @Override
+        public List<Resource> findByUri(String uri, String resourceServerId) {
+            return getResourceStoreDelegate().findByUri(uri, resourceServerId);
+        }
+
+        @Override
+        public List<Resource> findByResourceServer(String resourceServerId) {
+            return getResourceStoreDelegate().findByResourceServer(resourceServerId);
+        }
+
+        @Override
+        public List<Resource> findByResourceServer(Map<String, String[]> attributes, String resourceServerId, int firstResult, int maxResult) {
+            return getResourceStoreDelegate().findByResourceServer(attributes, resourceServerId, firstResult, maxResult);
+        }
+
+        @Override
+        public List<Resource> findByScope(List<String> ids, String resourceServerId) {
+            return getResourceStoreDelegate().findByScope(ids, resourceServerId);
+        }
+
+         @Override
+        public List<Resource> findByType(String type, String resourceServerId) {
+             return getResourceStoreDelegate().findByType(type, resourceServerId);
+        }
+    }
+
+    protected class PolicyCache implements PolicyStore {
+        @Override
+        public Policy create(AbstractPolicyRepresentation representation, ResourceServer resourceServer) {
+            Policy resource = getPolicyStoreDelegate().create(representation, resourceServer);
+            registerPolicyInvalidation(resource.getId(), resource.getName(), resourceServer.getId());
+            return resource;
+        }
+
+        @Override
+        public void delete(String id) {
+            if (id == null) return;
+            Policy policy = findById(id, null);
+            if (policy == null) return;
+
+            cache.invalidateObject(id);
+            invalidationEvents.add(PolicyRemovedEvent.create(id, policy.getName(), policy.getResourceServer().getId()));
+            cache.policyRemoval(id, policy.getName(), policy.getResourceServer().getId(), invalidations);
+            getPolicyStoreDelegate().delete(id);
+
+        }
+
+        @Override
+        public Policy findById(String id, String resourceServerId) {
+            if (id == null) return null;
+
+            CachedPolicy cached = cache.get(id, CachedPolicy.class);
+            if (cached != null) {
+                logger.tracev("by id cache hit: {0}", cached.getId());
+            }
+            boolean wasCached = false;
+            if (cached == null) {
+                Long loaded = cache.getCurrentRevision(id);
+                Policy model = getPolicyStoreDelegate().findById(id, resourceServerId);
+                if (model == null) 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)) {
+                return managedPolicies.get(id);
+            }
+            PolicyAdapter adapter = new PolicyAdapter(cached, StoreFactoryCacheSession.this);
+            managedPolicies.put(id, adapter);
+            return adapter;
+        }
+
+        @Override
+        public Policy findByName(String name, String resourceServerId) {
+            if (name == null) return null;
+            String cacheKey = getPolicyByNameCacheKey(name, resourceServerId);
+            PolicyListQuery query = cache.get(cacheKey, PolicyListQuery.class);
+            if (query != null) {
+                logger.tracev("policy by name cache hit: {0}", name);
+            }
+            if (query == null) {
+                Long loaded = cache.getCurrentRevision(cacheKey);
+                Policy model = getPolicyStoreDelegate().findByName(name, resourceServerId);
+                if (model == null) return null;
+                if (invalidations.contains(model.getId())) return model;
+                query = new PolicyListQuery(loaded, cacheKey, model.getId(), resourceServerId);
+                cache.addRevisioned(query, startupRevision);
+                return model;
+            } else if (invalidations.contains(cacheKey)) {
+                return getPolicyStoreDelegate().findByName(name, resourceServerId);
+            } else {
+                String id = query.getPolicies().iterator().next();
+                if (invalidations.contains(id)) {
+                    return getPolicyStoreDelegate().findByName(name, resourceServerId);
+                }
+                return findById(id, query.getResourceServerId());
+            }
+        }
+
+        @Override
+        public List<Policy> findByResourceServer(String resourceServerId) {
+            return getPolicyStoreDelegate().findByResourceServer(resourceServerId);
+        }
+
+        @Override
+        public List<Policy> findByResourceServer(Map<String, String[]> attributes, String resourceServerId, int firstResult, int maxResult) {
+            return getPolicyStoreDelegate().findByResourceServer(attributes, resourceServerId, firstResult, maxResult);
+        }
+
+        @Override
+        public List<Policy> findByResource(String resourceId, String resourceServerId) {
+            return getPolicyStoreDelegate().findByResource(resourceId, resourceServerId);
+        }
+
+        @Override
+        public List<Policy> findByResourceType(String resourceType, String resourceServerId) {
+            return getPolicyStoreDelegate().findByResourceType(resourceType, resourceServerId);
+        }
+
+        @Override
+        public List<Policy> findByScopeIds(List<String> scopeIds, String resourceServerId) {
+            return getPolicyStoreDelegate().findByScopeIds(scopeIds, resourceServerId);
+        }
+
+        @Override
+        public List<Policy> findByType(String type, String resourceServerId) {
+            return getPolicyStoreDelegate().findByType(type, resourceServerId);
+        }
+
+        @Override
+        public List<Policy> findDependentPolicies(String id, String resourceServerId) {
+            return getPolicyStoreDelegate().findDependentPolicies(id, resourceServerId);
+        }
+    }
+
+
+}
diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/stream/InResourceServerPredicate.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/stream/InResourceServerPredicate.java
new file mode 100755
index 0000000..46782b8
--- /dev/null
+++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/stream/InResourceServerPredicate.java
@@ -0,0 +1,35 @@
+package org.keycloak.models.cache.infinispan.authorization.stream;
+
+import org.keycloak.models.cache.infinispan.authorization.entities.InResourceServer;
+import org.keycloak.models.cache.infinispan.entities.InRealm;
+import org.keycloak.models.cache.infinispan.entities.Revisioned;
+
+import java.io.Serializable;
+import java.util.Map;
+import java.util.function.Predicate;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class InResourceServerPredicate implements Predicate<Map.Entry<String, Revisioned>>, Serializable {
+    private String serverId;
+
+    public static InResourceServerPredicate create() {
+        return new InResourceServerPredicate();
+    }
+
+    public InResourceServerPredicate resourceServer(String id) {
+        serverId = id;
+        return this;
+    }
+
+    @Override
+    public boolean test(Map.Entry<String, Revisioned> entry) {
+        Object value = entry.getValue();
+        if (value == null) return false;
+        if (!(value instanceof InResourceServer)) return false;
+
+        return serverId.equals(((InResourceServer)value).getResourceServerId());
+    }
+}
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 c254ea7..c9832ff 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
@@ -215,7 +215,7 @@ public abstract class CacheManager {
     }
 
 
-    protected void invalidationEventReceived(InvalidationEvent event) {
+    public void invalidationEventReceived(InvalidationEvent event) {
         Set<String> invalidations = new HashSet<>();
 
         addInvalidationsFromEvent(event, invalidations);
diff --git a/model/infinispan/src/main/resources/META-INF/services/org.keycloak.models.cache.authorization.CachedStoreProviderFactory b/model/infinispan/src/main/resources/META-INF/services/org.keycloak.models.cache.authorization.CachedStoreProviderFactory
index 0a46bb3..d9bed49 100644
--- a/model/infinispan/src/main/resources/META-INF/services/org.keycloak.models.cache.authorization.CachedStoreProviderFactory
+++ b/model/infinispan/src/main/resources/META-INF/services/org.keycloak.models.cache.authorization.CachedStoreProviderFactory
@@ -16,4 +16,4 @@
 # limitations under the License.
 #
 
-org.keycloak.models.authorization.infinispan.InfinispanStoreProviderFactory
\ No newline at end of file
+org.keycloak.models.cache.infinispan.authorization.InfinispanCacheStoreFactoryProviderFactory
\ No newline at end of file
diff --git a/model/jpa/src/main/java/org/keycloak/authorization/jpa/entities/PolicyEntity.java b/model/jpa/src/main/java/org/keycloak/authorization/jpa/entities/PolicyEntity.java
index 0305ae5..dc11724 100644
--- a/model/jpa/src/main/java/org/keycloak/authorization/jpa/entities/PolicyEntity.java
+++ b/model/jpa/src/main/java/org/keycloak/authorization/jpa/entities/PolicyEntity.java
@@ -35,6 +35,8 @@ import javax.persistence.JoinColumn;
 import javax.persistence.JoinTable;
 import javax.persistence.ManyToOne;
 import javax.persistence.MapKeyColumn;
+import javax.persistence.NamedQueries;
+import javax.persistence.NamedQuery;
 import javax.persistence.OneToMany;
 import javax.persistence.Table;
 import javax.persistence.UniqueConstraint;
@@ -52,11 +54,25 @@ import org.keycloak.representations.idm.authorization.Logic;
 @Table(name = "RESOURCE_SERVER_POLICY", uniqueConstraints = {
         @UniqueConstraint(columnNames = {"NAME", "RESOURCE_SERVER_ID"})
 })
-public class PolicyEntity implements Policy {
+@NamedQueries(
+        {
+                @NamedQuery(name="findPolicyIdByServerId", query="select p.id from PolicyEntity p where  p.resourceServer.id = :serverId "),
+                @NamedQuery(name="findPolicyIdByName", query="select p.id from PolicyEntity p where  p.resourceServer.id = :serverId  and p.name = :name"),
+                @NamedQuery(name="findPolicyIdByResource", query="select p.id from PolicyEntity p inner join p.resources r where p.resourceServer.id = :serverId and (r.resourceServer.id = :serverId and r.id = :resourceId)"),
+                @NamedQuery(name="findPolicyIdByScope", query="select pe.id from PolicyEntity pe where pe.resourceServer.id = :serverId and pe.id IN (select p.id from ScopeEntity s inner join s.policies p where s.resourceServer.id = :serverId and (p.resourceServer.id = :serverId and p.type = 'scope' and s.id in (:scopeIds)))"),
+                @NamedQuery(name="findPolicyIdByType", query="select p.id from PolicyEntity p where p.resourceServer.id = :serverId and p.type = :type"),
+                @NamedQuery(name="findPolicyIdByResourceType", query="select p.id from PolicyEntity p inner join p.config c where p.resourceServer.id = :serverId and KEY(c) = 'defaultResourceType' and c like :type"),
+                @NamedQuery(name="findPolicyIdByDependentPolices", query="select p.id from PolicyEntity p inner join p.associatedPolicies ap where p.resourceServer.id = :serverId and (ap.resourceServer.id = :serverId and ap.id = :policyId)"),
+                @NamedQuery(name="deletePolicyByResourceServer", query="delete from PolicyEntity p where p.resourceServer.id = :serverId")
+        }
+)
+
+public class PolicyEntity {
 
     @Id
-    @Column(name="ID", length = 36)
-    @Access(AccessType.PROPERTY) // we do this because relationships often fetch id, but not entity.  This avoids an extra SQL
+    @Column(name = "ID", length = 36)
+    @Access(AccessType.PROPERTY)
+    // we do this because relationships often fetch id, but not entity.  This avoids an extra SQL
     private String id;
 
     @Column(name = "NAME")
@@ -75,9 +91,9 @@ public class PolicyEntity implements Policy {
     private Logic logic = Logic.POSITIVE;
 
     @ElementCollection(fetch = FetchType.LAZY)
-    @MapKeyColumn(name="NAME")
-    @Column(name="VALUE", columnDefinition = "TEXT")
-    @CollectionTable(name="POLICY_CONFIG", joinColumns={ @JoinColumn(name="POLICY_ID") })
+    @MapKeyColumn(name = "NAME")
+    @Column(name = "VALUE", columnDefinition = "TEXT")
+    @CollectionTable(name = "POLICY_CONFIG", joinColumns = {@JoinColumn(name = "POLICY_ID")})
     private Map<String, String> config = new HashMap();
 
     @ManyToOne(optional = false, fetch = FetchType.LAZY)
@@ -96,7 +112,6 @@ public class PolicyEntity implements Policy {
     @JoinTable(name = "SCOPE_POLICY", joinColumns = @JoinColumn(name = "POLICY_ID"), inverseJoinColumns = @JoinColumn(name = "SCOPE_ID"))
     private Set<ScopeEntity> scopes = new HashSet<>();
 
-    @Override
     public String getId() {
         return this.id;
     }
@@ -105,7 +120,6 @@ public class PolicyEntity implements Policy {
         this.id = id;
     }
 
-    @Override
     public String getType() {
         return this.type;
     }
@@ -114,57 +128,46 @@ public class PolicyEntity implements Policy {
         this.type = type;
     }
 
-    @Override
     public DecisionStrategy getDecisionStrategy() {
         return this.decisionStrategy;
     }
 
-    @Override
     public void setDecisionStrategy(DecisionStrategy decisionStrategy) {
         this.decisionStrategy = decisionStrategy;
     }
 
-    @Override
     public Logic getLogic() {
         return this.logic;
     }
 
-    @Override
     public void setLogic(Logic logic) {
         this.logic = logic;
     }
 
-    @Override
     public Map<String, String> getConfig() {
         return this.config;
     }
 
-    @Override
     public void setConfig(Map<String, String> config) {
         this.config = config;
     }
 
-    @Override
     public String getName() {
         return this.name;
     }
 
-    @Override
     public void setName(String name) {
         this.name = name;
     }
 
-    @Override
     public String getDescription() {
         return this.description;
     }
 
-    @Override
     public void setDescription(String description) {
         this.description = description;
     }
 
-    @Override
     public ResourceServerEntity getResourceServer() {
         return this.resourceServer;
     }
@@ -173,16 +176,6 @@ public class PolicyEntity implements Policy {
         this.resourceServer = resourceServer;
     }
 
-    @Override
-    public <P extends Policy> Set<P> getAssociatedPolicies() {
-        return (Set<P>) this.associatedPolicies;
-    }
-
-    public void setAssociatedPolicies(Set<PolicyEntity> associatedPolicies) {
-        this.associatedPolicies = associatedPolicies;
-    }
-
-    @Override
     public Set<ResourceEntity> getResources() {
         return this.resources;
     }
@@ -191,7 +184,6 @@ public class PolicyEntity implements Policy {
         this.resources = resources;
     }
 
-    @Override
     public Set<ScopeEntity> getScopes() {
         return this.scopes;
     }
@@ -200,54 +192,26 @@ public class PolicyEntity implements Policy {
         this.scopes = scopes;
     }
 
-    @Override
-    public void addScope(Scope scope) {
-        getScopes().add((ScopeEntity) scope);
-    }
-
-    @Override
-    public void removeScope(Scope scope) {
-        getScopes().remove(scope);
-    }
-
-    @Override
-    public void addAssociatedPolicy(Policy associatedPolicy) {
-        getAssociatedPolicies().add(associatedPolicy);
-    }
-
-    @Override
-    public void removeAssociatedPolicy(Policy associatedPolicy) {
-        getAssociatedPolicies().remove(associatedPolicy);
+    public Set<PolicyEntity> getAssociatedPolicies() {
+        return associatedPolicies;
     }
 
-    @Override
-    public void addResource(Resource resource) {
-        getResources().add((ResourceEntity) resource);
-    }
-
-    @Override
-    public void removeResource(Resource resource) {
-        getResources().remove(resource);
+    public void setAssociatedPolicies(Set<PolicyEntity> associatedPolicies) {
+        this.associatedPolicies = associatedPolicies;
     }
 
     @Override
     public boolean equals(Object o) {
-        if (o == this) return true;
-
-        if (this.id == null) return false;
-
-        if (!Policy.class.isInstance(o)) return false;
-
-        Policy that = (Policy) o;
-
-        if (!getId().equals(that.getId())) return false;
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
 
-        return true;
+        PolicyEntity that = (PolicyEntity) o;
 
+        return getId().equals(that.getId());
     }
 
     @Override
     public int hashCode() {
-        return id!=null ? id.hashCode() : super.hashCode();
+        return getId().hashCode();
     }
 }
diff --git a/model/jpa/src/main/java/org/keycloak/authorization/jpa/entities/ResourceEntity.java b/model/jpa/src/main/java/org/keycloak/authorization/jpa/entities/ResourceEntity.java
index 29b5740..a717457 100644
--- a/model/jpa/src/main/java/org/keycloak/authorization/jpa/entities/ResourceEntity.java
+++ b/model/jpa/src/main/java/org/keycloak/authorization/jpa/entities/ResourceEntity.java
@@ -31,10 +31,13 @@ import javax.persistence.JoinColumn;
 import javax.persistence.JoinTable;
 import javax.persistence.ManyToMany;
 import javax.persistence.ManyToOne;
+import javax.persistence.NamedQueries;
+import javax.persistence.NamedQuery;
 import javax.persistence.Table;
 import javax.persistence.UniqueConstraint;
 import java.util.ArrayList;
 import java.util.HashSet;
+import java.util.LinkedList;
 import java.util.List;
 import java.util.Set;
 
@@ -45,7 +48,18 @@ import java.util.Set;
 @Table(name = "RESOURCE_SERVER_RESOURCE", uniqueConstraints = {
         @UniqueConstraint(columnNames = {"NAME", "RESOURCE_SERVER_ID", "OWNER"})
 })
-public class ResourceEntity implements Resource {
+@NamedQueries(
+        {
+                @NamedQuery(name="findResourceIdByOwner", query="select r.id from ResourceEntity r where r.resourceServer.id = :serverId and r.owner = :owner"),
+                @NamedQuery(name="findResourceIdByUri", query="select r.id from ResourceEntity r where  r.resourceServer.id = :serverId  and r.uri = :uri"),
+                @NamedQuery(name="findResourceIdByName", query="select r.id from ResourceEntity r where  r.resourceServer.id = :serverId  and r.name = :name"),
+                @NamedQuery(name="findResourceIdByType", query="select r.id from ResourceEntity r where  r.resourceServer.id = :serverId  and r.type = :type"),
+                @NamedQuery(name="findResourceIdByServerId", query="select r.id from ResourceEntity r where  r.resourceServer.id = :serverId "),
+                @NamedQuery(name="findResourceIdByScope", query="select r.id from ResourceEntity r inner join r.scopes s where r.resourceServer.id = :serverId and (s.resourceServer.id = :serverId and s.id in (:scopeIds))"),
+                @NamedQuery(name="deleteResourceByResourceServer", query="delete from ResourceEntity r where r.resourceServer.id = :serverId")
+        }
+)
+public class ResourceEntity {
 
     @Id
     @Column(name="ID", length = 36)
@@ -73,13 +87,12 @@ public class ResourceEntity implements Resource {
 
     @ManyToMany(fetch = FetchType.LAZY, cascade = {})
     @JoinTable(name = "RESOURCE_SCOPE", joinColumns = @JoinColumn(name = "RESOURCE_ID"), inverseJoinColumns = @JoinColumn(name = "SCOPE_ID"))
-    private List<ScopeEntity> scopes = new ArrayList<>();
+    private List<ScopeEntity> scopes = new LinkedList<>();
 
     @ManyToMany(fetch = FetchType.LAZY, cascade = {})
     @JoinTable(name = "RESOURCE_POLICY", joinColumns = @JoinColumn(name = "RESOURCE_ID"), inverseJoinColumns = @JoinColumn(name = "POLICY_ID"))
-    private List<PolicyEntity> policies = new ArrayList<>();
+    private List<PolicyEntity> policies = new LinkedList<>();
 
-    @Override
     public String getId() {
         return id;
     }
@@ -88,52 +101,42 @@ public class ResourceEntity implements Resource {
         this.id = id;
     }
 
-    @Override
     public String getName() {
         return name;
     }
 
-    @Override
     public void setName(String name) {
         this.name = name;
     }
 
-    @Override
     public String getUri() {
         return uri;
     }
 
-    @Override
     public void setUri(String uri) {
         this.uri = uri;
     }
 
-    @Override
     public String getType() {
         return type;
     }
 
-    @Override
     public void setType(String type) {
         this.type = type;
     }
 
-    @Override
     public List<ScopeEntity> getScopes() {
         return this.scopes;
     }
 
-    @Override
     public String getIconUri() {
         return iconUri;
     }
 
-    @Override
     public void setIconUri(String iconUri) {
         this.iconUri = iconUri;
     }
 
-    @Override
     public ResourceServerEntity getResourceServer() {
         return resourceServer;
     }
@@ -154,37 +157,23 @@ public class ResourceEntity implements Resource {
         return this.policies;
     }
 
-    public void updateScopes(Set<Scope> toUpdate) {
-        for (Scope scope : toUpdate) {
-            boolean hasScope = false;
-
-            for (Scope existingScope : this.scopes) {
-                if (existingScope.equals(scope)) {
-                    hasScope = true;
-                }
-            }
 
-            if (!hasScope) {
-                this.scopes.add((ScopeEntity) scope);
-            }
-        }
+    public void setPolicies(List<PolicyEntity> policies) {
+        this.policies = policies;
+    }
 
-        for (Scope scopeModel : new HashSet<Scope>(this.scopes)) {
-            boolean hasScope = false;
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
 
-            for (Scope scope : toUpdate) {
-                if (scopeModel.equals(scope)) {
-                    hasScope = true;
-                }
-            }
+        ResourceEntity that = (ResourceEntity) o;
 
-            if (!hasScope) {
-                this.scopes.remove(scopeModel);
-            }
-        }
+        return getId().equals(that.getId());
     }
 
-    public void setPolicies(List<PolicyEntity> policies) {
-        this.policies = policies;
+    @Override
+    public int hashCode() {
+        return getId().hashCode();
     }
 }
diff --git a/model/jpa/src/main/java/org/keycloak/authorization/jpa/entities/ResourceServerEntity.java b/model/jpa/src/main/java/org/keycloak/authorization/jpa/entities/ResourceServerEntity.java
index a0be18a..9ee63b6 100644
--- a/model/jpa/src/main/java/org/keycloak/authorization/jpa/entities/ResourceServerEntity.java
+++ b/model/jpa/src/main/java/org/keycloak/authorization/jpa/entities/ResourceServerEntity.java
@@ -26,6 +26,8 @@ import javax.persistence.AccessType;
 import javax.persistence.Column;
 import javax.persistence.Entity;
 import javax.persistence.Id;
+import javax.persistence.NamedQueries;
+import javax.persistence.NamedQuery;
 import javax.persistence.OneToMany;
 import javax.persistence.Table;
 import javax.persistence.UniqueConstraint;
@@ -36,7 +38,12 @@ import java.util.List;
  */
 @Entity
 @Table(name = "RESOURCE_SERVER", uniqueConstraints = {@UniqueConstraint(columnNames = "CLIENT_ID")})
-public class ResourceServerEntity implements ResourceServer {
+@NamedQueries(
+        {
+                @NamedQuery(name="findResourceServerIdByClient", query="select r.id from ResourceServerEntity r where r.clientId = :clientId"),
+        }
+)
+public class ResourceServerEntity {
 
     @Id
     @Column(name="ID", length = 36)
@@ -58,7 +65,6 @@ public class ResourceServerEntity implements ResourceServer {
     @OneToMany (mappedBy = "resourceServer")
     private List<ScopeEntity> scopes;
 
-    @Override
     public String getId() {
         return this.id;
     }
@@ -67,7 +73,6 @@ public class ResourceServerEntity implements ResourceServer {
         this.id = id;
     }
 
-    @Override
     public String getClientId() {
         return this.clientId;
     }
@@ -76,22 +81,18 @@ public class ResourceServerEntity implements ResourceServer {
         this.clientId = clientId;
     }
 
-    @Override
     public boolean isAllowRemoteResourceManagement() {
         return this.allowRemoteResourceManagement;
     }
 
-    @Override
     public void setAllowRemoteResourceManagement(boolean allowRemoteResourceManagement) {
         this.allowRemoteResourceManagement = allowRemoteResourceManagement;
     }
 
-    @Override
     public PolicyEnforcementMode getPolicyEnforcementMode() {
         return this.policyEnforcementMode;
     }
 
-    @Override
     public void setPolicyEnforcementMode(PolicyEnforcementMode policyEnforcementMode) {
         this.policyEnforcementMode = policyEnforcementMode;
     }
@@ -111,4 +112,19 @@ public class ResourceServerEntity implements ResourceServer {
     public void setScopes(final List<ScopeEntity> scopes) {
         this.scopes = scopes;
     }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        ResourceServerEntity that = (ResourceServerEntity) o;
+
+        return getId().equals(that.getId());
+    }
+
+    @Override
+    public int hashCode() {
+        return getId().hashCode();
+    }
 }
diff --git a/model/jpa/src/main/java/org/keycloak/authorization/jpa/entities/ScopeEntity.java b/model/jpa/src/main/java/org/keycloak/authorization/jpa/entities/ScopeEntity.java
index 523f38a..c1619f9 100644
--- a/model/jpa/src/main/java/org/keycloak/authorization/jpa/entities/ScopeEntity.java
+++ b/model/jpa/src/main/java/org/keycloak/authorization/jpa/entities/ScopeEntity.java
@@ -31,6 +31,8 @@ import javax.persistence.JoinColumn;
 import javax.persistence.JoinTable;
 import javax.persistence.ManyToMany;
 import javax.persistence.ManyToOne;
+import javax.persistence.NamedQueries;
+import javax.persistence.NamedQuery;
 import javax.persistence.Table;
 import javax.persistence.UniqueConstraint;
 import java.util.ArrayList;
@@ -44,7 +46,14 @@ import java.util.Objects;
 @Table(name = "RESOURCE_SERVER_SCOPE", uniqueConstraints = {
         @UniqueConstraint(columnNames = {"NAME", "RESOURCE_SERVER_ID"})
 })
-public class ScopeEntity implements Scope {
+@NamedQueries(
+        {
+                @NamedQuery(name="findScopeIdByName", query="select s.id from ScopeEntity s where s.resourceServer.id = :serverId and s.name = :name"),
+                @NamedQuery(name="findScopeIdByResourceServer", query="select s.id from ScopeEntity s where s.resourceServer.id = :serverId"),
+                @NamedQuery(name="deleteScopeByResourceServer", query="delete from ScopeEntity s where s.resourceServer.id = :serverId")
+        }
+)
+public class ScopeEntity {
 
     @Id
     @Column(name="ID", length = 36)
@@ -65,7 +74,6 @@ public class ScopeEntity implements Scope {
     @JoinTable(name = "SCOPE_POLICY", joinColumns = @JoinColumn(name = "SCOPE_ID"), inverseJoinColumns = @JoinColumn(name = "POLICY_ID"))
     private List<PolicyEntity> policies = new ArrayList<>();
 
-    @Override
     public String getId() {
         return id;
     }
@@ -74,33 +82,28 @@ public class ScopeEntity implements Scope {
         this.id = id;
     }
 
-    @Override
     public String getName() {
         return name;
     }
 
-    @Override
     public void setName(String name) {
         this.name = name;
     }
 
-    @Override
     public String getIconUri() {
         return iconUri;
     }
 
-    @Override
     public void setIconUri(String iconUri) {
         this.iconUri = iconUri;
     }
 
-    @Override
     public ResourceServerEntity getResourceServer() {
         return resourceServer;
     }
 
-    public List<? extends Policy> getPolicies() {
-        return this.policies;
+    public List<PolicyEntity> getPolicies() {
+        return policies;
     }
 
     public void setPolicies(List<PolicyEntity> policies) {
@@ -114,13 +117,15 @@ public class ScopeEntity implements Scope {
     @Override
     public boolean equals(Object o) {
         if (this == o) return true;
-        if (o == null || !Scope.class.isInstance(o)) return false;
-        Scope that = (Scope) o;
-        return Objects.equals(id, that.getId());
+        if (o == null || getClass() != o.getClass()) return false;
+
+        ScopeEntity that = (ScopeEntity) o;
+
+        return getId().equals(that.getId());
     }
 
     @Override
     public int hashCode() {
-        return Objects.hash(id);
+        return getId().hashCode();
     }
 }
diff --git a/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/JPAAuthorizationStoreFactory.java b/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/JPAAuthorizationStoreFactory.java
index 8750807..9f17606 100644
--- a/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/JPAAuthorizationStoreFactory.java
+++ b/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/JPAAuthorizationStoreFactory.java
@@ -32,8 +32,9 @@ import org.keycloak.models.KeycloakSession;
  */
 public class JPAAuthorizationStoreFactory implements AuthorizationStoreFactory {
     @Override
-    public StoreFactory  create(KeycloakSession session) {
-        return new JPAStoreFactory(getEntityManager(session));
+    public StoreFactory create(KeycloakSession session) {
+        AuthorizationProvider provider = session.getProvider(AuthorizationProvider.class);
+        return new JPAStoreFactory(getEntityManager(session), provider);
     }
 
     @Override
diff --git a/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/JPAPolicyStore.java b/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/JPAPolicyStore.java
index c6671de..eb350be 100644
--- a/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/JPAPolicyStore.java
+++ b/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/JPAPolicyStore.java
@@ -19,23 +19,29 @@ package org.keycloak.authorization.jpa.store;
 
 import java.util.ArrayList;
 import java.util.Collections;
+import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 
 import javax.persistence.EntityManager;
 import javax.persistence.NoResultException;
 import javax.persistence.Query;
+import javax.persistence.TypedQuery;
 import javax.persistence.criteria.CriteriaBuilder;
 import javax.persistence.criteria.CriteriaQuery;
 import javax.persistence.criteria.Predicate;
 import javax.persistence.criteria.Root;
 
+import org.keycloak.authorization.AuthorizationProvider;
 import org.keycloak.authorization.jpa.entities.PolicyEntity;
 import org.keycloak.authorization.jpa.entities.ResourceServerEntity;
 import org.keycloak.authorization.model.Policy;
+import org.keycloak.authorization.model.Resource;
 import org.keycloak.authorization.model.ResourceServer;
 import org.keycloak.authorization.store.PolicyStore;
+import org.keycloak.authorization.store.StoreFactory;
 import org.keycloak.models.utils.KeycloakModelUtils;
+import org.keycloak.models.utils.RepresentationToModel;
 import org.keycloak.representations.idm.authorization.AbstractPolicyRepresentation;
 
 /**
@@ -44,9 +50,10 @@ import org.keycloak.representations.idm.authorization.AbstractPolicyRepresentati
 public class JPAPolicyStore implements PolicyStore {
 
     private final EntityManager entityManager;
-
-    public JPAPolicyStore(EntityManager entityManager) {
+    private final AuthorizationProvider provider;
+    public JPAPolicyStore(EntityManager entityManager, AuthorizationProvider provider) {
         this.entityManager = entityManager;
+        this.provider = provider;
     }
 
     @Override
@@ -56,17 +63,17 @@ public class JPAPolicyStore implements PolicyStore {
         entity.setId(KeycloakModelUtils.generateId());
         entity.setType(representation.getType());
         entity.setName(representation.getName());
-        entity.setResourceServer((ResourceServerEntity) resourceServer);
+        entity.setResourceServer(ResourceServerAdapter.toEntity(entityManager, resourceServer));
 
         this.entityManager.persist(entity);
         this.entityManager.flush();
-        return entity;
+        Policy model = new PolicyAdapter(entity, entityManager, provider.getStoreFactory());
+        return model;
     }
 
     @Override
     public void delete(String id) {
-        Policy policy = entityManager.find(PolicyEntity.class, id);
-
+        PolicyEntity policy = entityManager.find(PolicyEntity.class, id);
         if (policy != null) {
             this.entityManager.remove(policy);
         }
@@ -79,39 +86,38 @@ public class JPAPolicyStore implements PolicyStore {
             return null;
         }
 
-        if (resourceServerId == null) {
-            return entityManager.find(PolicyEntity.class, id);
-        }
-
-        Query query = entityManager.createQuery("from PolicyEntity where resourceServer.id = :serverId and id = :id");
-
-        query.setParameter("serverId", resourceServerId);
-        query.setParameter("id", id);
+        PolicyEntity entity = entityManager.find(PolicyEntity.class, id);
+        if (entity == null) return null;
 
-        return entityManager.find(PolicyEntity.class, id);
+        return new PolicyAdapter(entity, entityManager, provider.getStoreFactory());
     }
 
     @Override
     public Policy findByName(String name, String resourceServerId) {
-        try {
-            Query query = entityManager.createQuery("from PolicyEntity where name = :name and resourceServer.id = :serverId");
-
-            query.setParameter("name", name);
-            query.setParameter("serverId", resourceServerId);
+        TypedQuery<String> query = entityManager.createNamedQuery("findPolicyIdByName", String.class);
 
-            return (Policy) query.getSingleResult();
-        } catch (NoResultException nre) {
+        query.setParameter("serverId", resourceServerId);
+        query.setParameter("name", name);
+        try {
+            String id = query.getSingleResult();
+            return provider.getStoreFactory().getPolicyStore().findById(id, resourceServerId);
+        } catch (NoResultException ex) {
             return null;
         }
     }
 
     @Override
     public List<Policy> findByResourceServer(final String resourceServerId) {
-        Query query = entityManager.createQuery("from PolicyEntity where resourceServer.id = :serverId");
+        TypedQuery<String> query = entityManager.createNamedQuery("findPolicyIdByServerId", String.class);
 
         query.setParameter("serverId", resourceServerId);
 
-        return query.getResultList();
+        List<String> result = query.getResultList();
+        List<Policy> list = new LinkedList<>();
+        for (String id : result) {
+            list.add(provider.getStoreFactory().getPolicyStore().findById(id, resourceServerId));
+        }
+        return list;
     }
 
     @Override
@@ -120,6 +126,7 @@ public class JPAPolicyStore implements PolicyStore {
         CriteriaQuery<PolicyEntity> querybuilder = builder.createQuery(PolicyEntity.class);
         Root<PolicyEntity> root = querybuilder.from(PolicyEntity.class);
         List<Predicate> predicates = new ArrayList();
+        querybuilder.select(root.get("id"));
 
         predicates.add(builder.equal(root.get("resourceServer").get("id"), resourceServerId));
 
@@ -148,27 +155,42 @@ public class JPAPolicyStore implements PolicyStore {
             query.setMaxResults(maxResult);
         }
 
-        return query.getResultList();
+        List<String> result = query.getResultList();
+        List<Policy> list = new LinkedList<>();
+        for (String id : result) {
+            list.add(provider.getStoreFactory().getPolicyStore().findById(id, resourceServerId));
+        }
+        return list;
     }
 
     @Override
     public List<Policy> findByResource(final String resourceId, String resourceServerId) {
-        Query query = entityManager.createQuery("select p from PolicyEntity p inner join p.resources r where p.resourceServer.id = :serverId and (r.resourceServer.id = :serverId and r.id = :resourceId)");
+        TypedQuery<String> query = entityManager.createNamedQuery("findPolicyIdByResource", String.class);
 
         query.setParameter("resourceId", resourceId);
         query.setParameter("serverId", resourceServerId);
 
-        return query.getResultList();
+        List<String> result = query.getResultList();
+        List<Policy> list = new LinkedList<>();
+        for (String id : result) {
+            list.add(provider.getStoreFactory().getPolicyStore().findById(id, resourceServerId));
+        }
+        return list;
     }
 
     @Override
     public List<Policy> findByResourceType(final String resourceType, String resourceServerId) {
-        Query query = entityManager.createQuery("select p from PolicyEntity p inner join p.config c where p.resourceServer.id = :serverId and KEY(c) = 'defaultResourceType' and c like :type");
+        TypedQuery<String> query = entityManager.createNamedQuery("findPolicyIdByResourceType", String.class);
 
-        query.setParameter("serverId", resourceServerId);
         query.setParameter("type", resourceType);
+        query.setParameter("serverId", resourceServerId);
 
-        return query.getResultList();
+        List<String> result = query.getResultList();
+        List<Policy> list = new LinkedList<>();
+        for (String id : result) {
+            list.add(provider.getStoreFactory().getPolicyStore().findById(id, resourceServerId));
+        }
+        return list;
     }
 
     @Override
@@ -178,31 +200,47 @@ public class JPAPolicyStore implements PolicyStore {
         }
 
         // Use separate subquery to handle DB2 and MSSSQL
-        Query query = entityManager.createQuery("select pe from PolicyEntity pe where pe.resourceServer.id = :serverId and pe.id IN (select p.id from ScopeEntity s inner join s.policies p where s.resourceServer.id = :serverId and (p.resourceServer.id = :serverId and p.type = 'scope' and s.id in (:scopeIds)))");
+        TypedQuery<String> query = entityManager.createNamedQuery("findPolicyIdByScope", String.class);
 
-        query.setParameter("serverId", resourceServerId);
         query.setParameter("scopeIds", scopeIds);
+        query.setParameter("serverId", resourceServerId);
 
-        return query.getResultList();
+        List<String> result = query.getResultList();
+        List<Policy> list = new LinkedList<>();
+        for (String id : result) {
+            list.add(provider.getStoreFactory().getPolicyStore().findById(id, resourceServerId));
+        }
+        return list;
     }
 
     @Override
     public List<Policy> findByType(String type, String resourceServerId) {
-        Query query = entityManager.createQuery("select p from PolicyEntity p where p.resourceServer.id = :serverId and p.type = :type");
+        TypedQuery<String> query = entityManager.createNamedQuery("findPolicyIdByType", String.class);
 
         query.setParameter("serverId", resourceServerId);
         query.setParameter("type", type);
 
-        return query.getResultList();
+        List<String> result = query.getResultList();
+        List<Policy> list = new LinkedList<>();
+        for (String id : result) {
+            list.add(provider.getStoreFactory().getPolicyStore().findById(id, resourceServerId));
+        }
+        return list;
     }
 
     @Override
     public List<Policy> findDependentPolicies(String policyId, String resourceServerId) {
-        Query query = entityManager.createQuery("select p from PolicyEntity p inner join p.associatedPolicies ap where p.resourceServer.id = :serverId and (ap.resourceServer.id = :serverId and ap.id = :policyId)");
+
+        TypedQuery<String> query = entityManager.createNamedQuery("findPolicyIdByDependentPolices", String.class);
 
         query.setParameter("serverId", resourceServerId);
         query.setParameter("policyId", policyId);
 
-        return query.getResultList();
+        List<String> result = query.getResultList();
+        List<Policy> list = new LinkedList<>();
+        for (String id : result) {
+            list.add(provider.getStoreFactory().getPolicyStore().findById(id, resourceServerId));
+        }
+        return list;
     }
 }
diff --git a/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/JPAResourceServerStore.java b/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/JPAResourceServerStore.java
index 51d0369..20404e5 100644
--- a/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/JPAResourceServerStore.java
+++ b/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/JPAResourceServerStore.java
@@ -17,13 +17,19 @@
  */
 package org.keycloak.authorization.jpa.store;
 
+import org.keycloak.authorization.AuthorizationProvider;
+import org.keycloak.authorization.jpa.entities.PolicyEntity;
 import org.keycloak.authorization.jpa.entities.ResourceServerEntity;
+import org.keycloak.authorization.model.Policy;
 import org.keycloak.authorization.model.ResourceServer;
 import org.keycloak.authorization.store.ResourceServerStore;
 import org.keycloak.models.utils.KeycloakModelUtils;
 
 import javax.persistence.EntityManager;
+import javax.persistence.NoResultException;
 import javax.persistence.Query;
+import javax.persistence.TypedQuery;
+import java.util.LinkedList;
 import java.util.List;
 
 /**
@@ -32,9 +38,11 @@ import java.util.List;
 public class JPAResourceServerStore implements ResourceServerStore {
 
     private final EntityManager entityManager;
+    private final AuthorizationProvider provider;
 
-    public JPAResourceServerStore(EntityManager entityManager) {
+    public JPAResourceServerStore(EntityManager entityManager, AuthorizationProvider provider) {
         this.entityManager = entityManager;
+        this.provider = provider;
     }
 
     @Override
@@ -46,30 +54,54 @@ public class JPAResourceServerStore implements ResourceServerStore {
 
         this.entityManager.persist(entity);
 
-        return entity;
+        return new ResourceServerAdapter(entity, entityManager, provider.getStoreFactory());
     }
 
     @Override
     public void delete(String id) {
-        this.entityManager.remove(findById(id));
+        ResourceServerEntity entity = entityManager.find(ResourceServerEntity.class, id);
+        if (entity == null) return;
+        //This didn't work, had to loop through and remove each policy individually
+        //entityManager.createNamedQuery("deletePolicyByResourceServer")
+        //        .setParameter("serverId", id).executeUpdate();
+
+        TypedQuery<String> query = entityManager.createNamedQuery("findPolicyIdByServerId", String.class);
+        query.setParameter("serverId", id);
+        List<String> result = query.getResultList();
+        List<Policy> list = new LinkedList<>();
+        for (String policyId : result) {
+            entityManager.remove(entityManager.getReference(PolicyEntity.class, policyId));
+        }
+
+        entityManager.flush();
+        entityManager.createNamedQuery("deleteResourceByResourceServer")
+                .setParameter("serverId", id).executeUpdate();
+        entityManager.flush();
+        entityManager.createNamedQuery("deleteScopeByResourceServer")
+                .setParameter("serverId", id).executeUpdate();
+        entityManager.flush();
+
+        this.entityManager.remove(entity);
+        entityManager.flush();
     }
 
     @Override
     public ResourceServer findById(String id) {
-        return entityManager.find(ResourceServerEntity.class, id);
+        ResourceServerEntity entity = entityManager.find(ResourceServerEntity.class, id);
+        if (entity == null) return null;
+        return new ResourceServerAdapter(entity, entityManager, provider.getStoreFactory());
     }
 
     @Override
     public ResourceServer findByClient(final String clientId) {
-        Query query = entityManager.createQuery("from ResourceServerEntity where clientId = :clientId");
+        TypedQuery<String> query = entityManager.createNamedQuery("findResourceServerIdByClient", String.class);
 
         query.setParameter("clientId", clientId);
-        List result = query.getResultList();
-
-        if (result.isEmpty()) {
+        try {
+            String id = query.getSingleResult();
+            return provider.getStoreFactory().getResourceServerStore().findById(id);
+        } catch (NoResultException ex) {
             return null;
         }
-
-        return (ResourceServer) result.get(0);
     }
 }
diff --git a/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/JPAResourceStore.java b/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/JPAResourceStore.java
index 0b04388..8a647d8 100644
--- a/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/JPAResourceStore.java
+++ b/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/JPAResourceStore.java
@@ -17,6 +17,7 @@
  */
 package org.keycloak.authorization.jpa.store;
 
+import org.keycloak.authorization.AuthorizationProvider;
 import org.keycloak.authorization.jpa.entities.ResourceEntity;
 import org.keycloak.authorization.jpa.entities.ResourceServerEntity;
 import org.keycloak.authorization.model.Resource;
@@ -25,13 +26,16 @@ import org.keycloak.authorization.store.ResourceStore;
 import org.keycloak.models.utils.KeycloakModelUtils;
 
 import javax.persistence.EntityManager;
+import javax.persistence.NoResultException;
 import javax.persistence.Query;
+import javax.persistence.TypedQuery;
 import javax.persistence.criteria.CriteriaBuilder;
 import javax.persistence.criteria.CriteriaQuery;
 import javax.persistence.criteria.Predicate;
 import javax.persistence.criteria.Root;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 
@@ -41,38 +45,34 @@ import java.util.Map;
 public class JPAResourceStore implements ResourceStore {
 
     private final EntityManager entityManager;
+    private final AuthorizationProvider provider;
 
-    public JPAResourceStore(EntityManager entityManager) {
+    public JPAResourceStore(EntityManager entityManager, AuthorizationProvider provider) {
         this.entityManager = entityManager;
+        this.provider = provider;
     }
 
     @Override
     public Resource create(String name, ResourceServer resourceServer, String owner) {
-        if (!(resourceServer instanceof ResourceServerEntity)) {
-            throw new RuntimeException("Unexpected type [" + resourceServer.getClass() + "].");
-        }
-
         ResourceEntity entity = new ResourceEntity();
 
         entity.setId(KeycloakModelUtils.generateId());
         entity.setName(name);
-        entity.setResourceServer((ResourceServerEntity) resourceServer);
+        entity.setResourceServer(ResourceServerAdapter.toEntity(entityManager, resourceServer));
         entity.setOwner(owner);
 
         this.entityManager.persist(entity);
 
-        return entity;
+        return new ResourceAdapter(entity, entityManager, provider.getStoreFactory());
     }
 
     @Override
     public void delete(String id) {
-        Resource resource = entityManager.find(ResourceEntity.class, id);
+        ResourceEntity resource = entityManager.find(ResourceEntity.class, id);
+        if (resource == null) return;
 
         resource.getScopes().clear();
-
-        if (resource != null) {
-            this.entityManager.remove(resource);
-        }
+        this.entityManager.remove(resource);
     }
 
     @Override
@@ -81,52 +81,61 @@ public class JPAResourceStore implements ResourceStore {
             return null;
         }
 
-        if (resourceServerId == null) {
-            return entityManager.find(ResourceEntity.class, id);
-        }
-
-        Query query = entityManager.createQuery("from ResourceEntity where resourceServer.id = :serverId and id = :id");
-
-        query.setParameter("serverId", resourceServerId);
-        query.setParameter("id", id);
-
-        return entityManager.find(ResourceEntity.class, id);
+        ResourceEntity entity = entityManager.find(ResourceEntity.class, id);
+        if (entity == null) return null;
+        return new ResourceAdapter(entity, entityManager, provider.getStoreFactory());
     }
 
     @Override
     public List<Resource> findByOwner(String ownerId, String resourceServerId) {
-        Query query = entityManager.createQuery("from ResourceEntity where resourceServer.id = :serverId and owner = :ownerId");
+        TypedQuery<String> query = entityManager.createNamedQuery("findResourceIdByOwner", String.class);
 
-        query.setParameter("ownerId", ownerId);
+        query.setParameter("owner", ownerId);
         query.setParameter("serverId", resourceServerId);
 
-        return query.getResultList();
+        List<String> result = query.getResultList();
+        List<Resource> list = new LinkedList<>();
+        for (String id : result) {
+            list.add(provider.getStoreFactory().getResourceStore().findById(id, resourceServerId));
+        }
+        return list;
     }
 
     @Override
     public List<Resource> findByUri(String uri, String resourceServerId) {
-        Query query = entityManager.createQuery("from ResourceEntity where resourceServer.id = :serverId and uri = :uri");
+        TypedQuery<String> query = entityManager.createNamedQuery("findResourceIdByUri", String.class);
 
         query.setParameter("uri", uri);
         query.setParameter("serverId", resourceServerId);
 
-        return query.getResultList();
+        List<String> result = query.getResultList();
+        List<Resource> list = new LinkedList<>();
+        for (String id : result) {
+            list.add(provider.getStoreFactory().getResourceStore().findById(id, resourceServerId));
+        }
+        return list;
     }
 
     @Override
-    public List findByResourceServer(String resourceServerId) {
-        Query query = entityManager.createQuery("from ResourceEntity where resourceServer.id = :serverId");
+    public List<Resource> findByResourceServer(String resourceServerId) {
+        TypedQuery<String> query = entityManager.createNamedQuery("findResourceIdByServerId", String.class);
 
         query.setParameter("serverId", resourceServerId);
 
-        return query.getResultList();
+        List<String> result = query.getResultList();
+        List<Resource> list = new LinkedList<>();
+        for (String id : result) {
+            list.add(provider.getStoreFactory().getResourceStore().findById(id, resourceServerId));
+        }
+        return list;
     }
 
     @Override
-    public List findByResourceServer(Map<String, String[]> attributes, String resourceServerId, int firstResult, int maxResult) {
+    public List<Resource> findByResourceServer(Map<String, String[]> attributes, String resourceServerId, int firstResult, int maxResult) {
         CriteriaBuilder builder = entityManager.getCriteriaBuilder();
         CriteriaQuery<ResourceEntity> querybuilder = builder.createQuery(ResourceEntity.class);
         Root<ResourceEntity> root = querybuilder.from(ResourceEntity.class);
+        querybuilder.select(root.get("id"));
         List<Predicate> predicates = new ArrayList();
 
         predicates.add(builder.equal(root.get("resourceServer").get("id"), resourceServerId));
@@ -152,42 +161,55 @@ public class JPAResourceStore implements ResourceStore {
             query.setMaxResults(maxResult);
         }
 
-        return query.getResultList();
+        List<String> result = query.getResultList();
+        List<Resource> list = new LinkedList<>();
+        for (String id : result) {
+            list.add(provider.getStoreFactory().getResourceStore().findById(id, resourceServerId));
+        }
+        return list;
     }
 
     @Override
-    public List<Resource> findByScope(List<String> id, String resourceServerId) {
-        Query query = entityManager.createQuery("select r from ResourceEntity r inner join r.scopes s where r.resourceServer.id = :serverId and (s.resourceServer.id = :serverId and s.id in (:scopeIds))");
+    public List<Resource> findByScope(List<String> scopes, String resourceServerId) {
+        TypedQuery<String> query = entityManager.createNamedQuery("findResourceIdByScope", String.class);
 
-        query.setParameter("scopeIds", id);
+        query.setParameter("scopeIds", scopes);
         query.setParameter("serverId", resourceServerId);
 
-        return query.getResultList();
+        List<String> result = query.getResultList();
+        List<Resource> list = new LinkedList<>();
+        for (String id : result) {
+            list.add(provider.getStoreFactory().getResourceStore().findById(id, resourceServerId));
+        }
+        return list;
     }
 
     @Override
     public Resource findByName(String name, String resourceServerId) {
-        Query query = entityManager.createQuery("from ResourceEntity where resourceServer.id = :serverId and name = :name");
+        TypedQuery<String> query = entityManager.createNamedQuery("findResourceIdByName", String.class);
 
         query.setParameter("serverId", resourceServerId);
         query.setParameter("name", name);
-
-        List<Resource> result = query.getResultList();
-
-        if (!result.isEmpty()) {
-            return result.get(0);
+        try {
+            String id = query.getSingleResult();
+            return provider.getStoreFactory().getResourceStore().findById(id, resourceServerId);
+        } catch (NoResultException ex) {
+            return null;
         }
-
-        return null;
     }
 
     @Override
     public List<Resource> findByType(String type, String resourceServerId) {
-        Query query = entityManager.createQuery("from ResourceEntity r where r.resourceServer.id = :serverId and type = :type");
+        TypedQuery<String> query = entityManager.createNamedQuery("findResourceIdByType", String.class);
 
         query.setParameter("type", type);
         query.setParameter("serverId", resourceServerId);
 
-        return query.getResultList();
+        List<String> result = query.getResultList();
+        List<Resource> list = new LinkedList<>();
+        for (String id : result) {
+            list.add(provider.getStoreFactory().getResourceStore().findById(id, resourceServerId));
+        }
+        return list;
     }
 }
diff --git a/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/JPAScopeStore.java b/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/JPAScopeStore.java
index 031eb4a..f8a9350 100644
--- a/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/JPAScopeStore.java
+++ b/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/JPAScopeStore.java
@@ -18,17 +18,20 @@
 package org.keycloak.authorization.jpa.store;
 
 import java.util.ArrayList;
+import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 
 import javax.persistence.EntityManager;
 import javax.persistence.NoResultException;
 import javax.persistence.Query;
+import javax.persistence.TypedQuery;
 import javax.persistence.criteria.CriteriaBuilder;
 import javax.persistence.criteria.CriteriaQuery;
 import javax.persistence.criteria.Predicate;
 import javax.persistence.criteria.Root;
 
+import org.keycloak.authorization.AuthorizationProvider;
 import org.keycloak.authorization.jpa.entities.ResourceServerEntity;
 import org.keycloak.authorization.jpa.entities.ScopeEntity;
 import org.keycloak.authorization.model.ResourceServer;
@@ -42,9 +45,11 @@ import org.keycloak.models.utils.KeycloakModelUtils;
 public class JPAScopeStore implements ScopeStore {
 
     private final EntityManager entityManager;
+    private final AuthorizationProvider provider;
 
-    public JPAScopeStore(EntityManager entityManager) {
+    public JPAScopeStore(EntityManager entityManager, AuthorizationProvider provider) {
         this.entityManager = entityManager;
+        this.provider = provider;
     }
 
     @Override
@@ -53,16 +58,16 @@ public class JPAScopeStore implements ScopeStore {
 
         entity.setId(KeycloakModelUtils.generateId());
         entity.setName(name);
-        entity.setResourceServer((ResourceServerEntity) resourceServer);
+        entity.setResourceServer(ResourceServerAdapter.toEntity(entityManager, resourceServer));
 
         this.entityManager.persist(entity);
 
-        return entity;
+        return new ScopeAdapter(entity, entityManager, provider.getStoreFactory());
     }
 
     @Override
     public void delete(String id) {
-        Scope scope = entityManager.find(ScopeEntity.class, id);
+        ScopeEntity scope = entityManager.find(ScopeEntity.class, id);
 
         if (scope != null) {
             this.entityManager.remove(scope);
@@ -75,28 +80,21 @@ public class JPAScopeStore implements ScopeStore {
             return null;
         }
 
-        if (resourceServerId == null) {
-            return entityManager.find(ScopeEntity.class, id);
-        }
-
-        Query query = entityManager.createQuery("from ScopeEntity where resourceServer.id = :serverId and id = :id");
-
-        query.setParameter("serverId", resourceServerId);
-        query.setParameter("id", id);
-
-        return entityManager.find(ScopeEntity.class, id);
+        ScopeEntity entity = entityManager.find(ScopeEntity.class, id);
+        if (entity == null) return null;
 
+        return new ScopeAdapter(entity, entityManager, provider.getStoreFactory());
     }
 
     @Override
     public Scope findByName(String name, String resourceServerId) {
         try {
-            Query query = entityManager.createQuery("select s from ScopeEntity s inner join s.resourceServer rs where rs.id = :resourceServerId and name = :name");
+            TypedQuery<String> query = entityManager.createNamedQuery("findScopeIdByName", String.class);
 
-            query.setParameter("resourceServerId", resourceServerId);
+            query.setParameter("serverId", resourceServerId);
             query.setParameter("name", name);
-
-            return (Scope) query.getSingleResult();
+            String id = query.getSingleResult();
+            return provider.getStoreFactory().getScopeStore().findById(id, resourceServerId);
         } catch (NoResultException nre) {
             return null;
         }
@@ -104,11 +102,16 @@ public class JPAScopeStore implements ScopeStore {
 
     @Override
     public List<Scope> findByResourceServer(final String serverId) {
-        Query query = entityManager.createQuery("from ScopeEntity where resourceServer.id = :serverId");
+        TypedQuery<String> query = entityManager.createNamedQuery("findScopeIdByResourceServer", String.class);
 
         query.setParameter("serverId", serverId);
 
-        return query.getResultList();
+        List<String> result = query.getResultList();
+        List<Scope> list = new LinkedList<>();
+        for (String id : result) {
+            list.add(provider.getStoreFactory().getScopeStore().findById(id, serverId));
+        }
+        return list;
     }
 
     @Override
@@ -116,6 +119,7 @@ public class JPAScopeStore implements ScopeStore {
         CriteriaBuilder builder = entityManager.getCriteriaBuilder();
         CriteriaQuery<ScopeEntity> querybuilder = builder.createQuery(ScopeEntity.class);
         Root<ScopeEntity> root = querybuilder.from(ScopeEntity.class);
+        querybuilder.select(root.get("id"));
         List<Predicate> predicates = new ArrayList();
 
         predicates.add(builder.equal(root.get("resourceServer").get("id"), resourceServerId));
@@ -139,6 +143,12 @@ public class JPAScopeStore implements ScopeStore {
             query.setMaxResults(maxResult);
         }
 
-        return query.getResultList();
+        List result = query.getResultList();
+        List<Scope> list = new LinkedList<>();
+        for (Object id : result) {
+            list.add(provider.getStoreFactory().getScopeStore().findById((String)id, resourceServerId));
+        }
+        return list;
+
     }
 }
diff --git a/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/JPAStoreFactory.java b/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/JPAStoreFactory.java
index e45d343..855f66a 100644
--- a/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/JPAStoreFactory.java
+++ b/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/JPAStoreFactory.java
@@ -20,6 +20,7 @@ package org.keycloak.authorization.jpa.store;
 
 import javax.persistence.EntityManager;
 
+import org.keycloak.authorization.AuthorizationProvider;
 import org.keycloak.authorization.store.PolicyStore;
 import org.keycloak.authorization.store.ResourceServerStore;
 import org.keycloak.authorization.store.ResourceStore;
@@ -36,11 +37,11 @@ public class JPAStoreFactory implements StoreFactory {
     private final ResourceStore resourceStore;
     private final ScopeStore scopeStore;
 
-    public JPAStoreFactory(EntityManager entityManager) {
-        policyStore = new JPAPolicyStore(entityManager);
-        resourceServerStore = new JPAResourceServerStore(entityManager);
-        resourceStore = new JPAResourceStore(entityManager);
-        scopeStore = new JPAScopeStore(entityManager);
+    public JPAStoreFactory(EntityManager entityManager, AuthorizationProvider provider) {
+        policyStore = new JPAPolicyStore(entityManager, provider);
+        resourceServerStore = new JPAResourceServerStore(entityManager, provider);
+        resourceStore = new JPAResourceStore(entityManager, provider);
+        scopeStore = new JPAScopeStore(entityManager, provider);
     }
 
     @Override
diff --git a/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/PolicyAdapter.java b/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/PolicyAdapter.java
new file mode 100644
index 0000000..6fc2d1e
--- /dev/null
+++ b/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/PolicyAdapter.java
@@ -0,0 +1,235 @@
+/*
+ * 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.authorization.jpa.store;
+
+import org.keycloak.authorization.AuthorizationProvider;
+import org.keycloak.authorization.jpa.entities.PolicyEntity;
+import org.keycloak.authorization.jpa.entities.ResourceEntity;
+import org.keycloak.authorization.jpa.entities.ScopeEntity;
+import org.keycloak.authorization.model.Policy;
+import org.keycloak.authorization.model.Resource;
+import org.keycloak.authorization.model.ResourceServer;
+import org.keycloak.authorization.model.Scope;
+import org.keycloak.authorization.store.StoreFactory;
+import org.keycloak.models.jpa.JpaModel;
+import org.keycloak.representations.idm.authorization.DecisionStrategy;
+import org.keycloak.representations.idm.authorization.Logic;
+
+import javax.persistence.EntityManager;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class PolicyAdapter implements Policy, JpaModel<PolicyEntity> {
+    private PolicyEntity entity;
+    private EntityManager em;
+    private StoreFactory storeFactory;
+
+    public PolicyAdapter(PolicyEntity entity, EntityManager em, StoreFactory storeFactory) {
+        this.entity = entity;
+        this.em = em;
+        this.storeFactory = storeFactory;
+    }
+
+    @Override
+    public PolicyEntity getEntity() {
+        return entity;
+    }
+
+    @Override
+    public String getId() {
+        return entity.getId();
+    }
+
+    @Override
+    public String getType() {
+        return entity.getType();
+    }
+
+    @Override
+    public DecisionStrategy getDecisionStrategy() {
+        return entity.getDecisionStrategy();
+    }
+
+    @Override
+    public void setDecisionStrategy(DecisionStrategy decisionStrategy) {
+        entity.setDecisionStrategy(decisionStrategy);
+
+    }
+
+    @Override
+    public Logic getLogic() {
+        return entity.getLogic();
+    }
+
+    @Override
+    public void setLogic(Logic logic) {
+        entity.setLogic(logic);
+    }
+
+    @Override
+    public Map<String, String> getConfig() {
+        Map<String, String> result = new HashMap<String, String>();
+        if (entity.getConfig() != null) result.putAll(entity.getConfig());
+        return Collections.unmodifiableMap(result);
+    }
+
+    @Override
+    public void setConfig(Map<String, String> config) {
+        if (entity.getConfig() == null) {
+            entity.setConfig(new HashMap<>());
+        } else {
+            entity.getConfig().clear();
+        }
+        entity.getConfig().putAll(config);
+    }
+
+    @Override
+    public void removeConfig(String name) {
+        if (entity.getConfig() == null) {
+            return;
+        }
+        entity.getConfig().remove(name);
+    }
+
+    @Override
+    public void putConfig(String name, String value) {
+        if (entity.getConfig() == null) {
+            entity.setConfig(new HashMap<>());
+        }
+        entity.getConfig().put(name, value);
+
+    }
+
+    @Override
+    public String getName() {
+        return entity.getName();
+    }
+
+    @Override
+    public void setName(String name) {
+        entity.setName(name);
+
+    }
+
+    @Override
+    public String getDescription() {
+        return entity.getDescription();
+    }
+
+    @Override
+    public void setDescription(String description) {
+        entity.setDescription(description);
+
+    }
+
+    @Override
+    public ResourceServer getResourceServer() {
+        return storeFactory.getResourceServerStore().findById(entity.getResourceServer().getId());
+    }
+
+    @Override
+    public Set<Policy> getAssociatedPolicies() {
+        Set<Policy> result = new HashSet<>();
+        for (PolicyEntity policy : entity.getAssociatedPolicies()) {
+            Policy p = storeFactory.getPolicyStore().findById(policy.getId(), entity.getResourceServer().getId());
+            result.add(p);
+        }
+        return Collections.unmodifiableSet(result);
+    }
+
+    @Override
+    public Set<Resource> getResources() {
+        Set<Resource> set = new HashSet<>();
+        for (ResourceEntity res : entity.getResources()) {
+            set.add(storeFactory.getResourceStore().findById(res.getId(), entity.getResourceServer().getId()));
+        }
+        return Collections.unmodifiableSet(set);
+    }
+
+    @Override
+    public Set<Scope> getScopes() {
+        Set<Scope> set = new HashSet<>();
+        for (ScopeEntity res : entity.getScopes()) {
+            set.add(storeFactory.getScopeStore().findById(res.getId(), entity.getResourceServer().getId()));
+        }
+        return Collections.unmodifiableSet(set);
+    }
+
+    @Override
+    public void addScope(Scope scope) {
+        entity.getScopes().add(ScopeAdapter.toEntity(em, scope));
+    }
+
+    @Override
+    public void removeScope(Scope scope) {
+        entity.getScopes().remove(ScopeAdapter.toEntity(em, scope));
+
+    }
+
+    @Override
+    public void addAssociatedPolicy(Policy associatedPolicy) {
+        entity.getAssociatedPolicies().add(toEntity(em, associatedPolicy));
+    }
+
+    @Override
+    public void removeAssociatedPolicy(Policy associatedPolicy) {
+        entity.getAssociatedPolicies().remove(toEntity(em, associatedPolicy));
+
+    }
+
+    @Override
+    public void addResource(Resource resource) {
+        entity.getResources().add(ResourceAdapter.toEntity(em, resource));
+    }
+
+    @Override
+    public void removeResource(Resource resource) {
+        entity.getResources().remove(ResourceAdapter.toEntity(em, resource));
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || !(o instanceof Policy)) return false;
+
+        Policy that = (Policy) o;
+        return that.getId().equals(getId());
+    }
+
+    @Override
+    public int hashCode() {
+        return getId().hashCode();
+    }
+
+    public static PolicyEntity toEntity(EntityManager em, Policy policy) {
+        if (policy instanceof PolicyAdapter) {
+            return ((PolicyAdapter)policy).getEntity();
+        } else {
+            return em.getReference(PolicyEntity.class, policy.getId());
+        }
+    }
+
+
+
+}
diff --git a/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/ResourceAdapter.java b/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/ResourceAdapter.java
new file mode 100644
index 0000000..5c55114
--- /dev/null
+++ b/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/ResourceAdapter.java
@@ -0,0 +1,166 @@
+/*
+ * 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.authorization.jpa.store;
+
+import org.keycloak.authorization.AuthorizationProvider;
+import org.keycloak.authorization.jpa.entities.ResourceEntity;
+import org.keycloak.authorization.jpa.entities.ScopeEntity;
+import org.keycloak.authorization.model.Resource;
+import org.keycloak.authorization.model.ResourceServer;
+import org.keycloak.authorization.model.Scope;
+import org.keycloak.authorization.store.StoreFactory;
+import org.keycloak.models.jpa.JpaModel;
+
+import javax.persistence.EntityManager;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class ResourceAdapter implements Resource, JpaModel<ResourceEntity> {
+    private ResourceEntity entity;
+    private EntityManager em;
+    private StoreFactory storeFactory;
+
+    public ResourceAdapter(ResourceEntity entity, EntityManager em, StoreFactory storeFactory) {
+        this.entity = entity;
+        this.em = em;
+        this.storeFactory = storeFactory;
+    }
+
+    @Override
+    public ResourceEntity getEntity() {
+        return entity;
+    }
+
+    @Override
+    public String getId() {
+        return entity.getId();
+    }
+
+    @Override
+    public String getName() {
+        return entity.getName();
+    }
+
+    @Override
+    public void setName(String name) {
+        entity.setName(name);
+
+    }
+
+    @Override
+    public String getUri() {
+        return entity.getUri();
+    }
+
+    @Override
+    public void setUri(String uri) {
+        entity.setUri(uri);
+
+    }
+
+    @Override
+    public String getType() {
+        return entity.getType();
+    }
+
+    @Override
+    public void setType(String type) {
+        entity.setType(type);
+
+    }
+
+    @Override
+    public List<Scope> getScopes() {
+        List<Scope> scopes = new LinkedList<>();
+        for (ScopeEntity scope : entity.getScopes()) {
+            scopes.add(storeFactory.getScopeStore().findById(scope.getId(), entity.getResourceServer().getId()));
+        }
+
+        return Collections.unmodifiableList(scopes);
+    }
+
+    @Override
+    public String getIconUri() {
+        return entity.getIconUri();
+    }
+
+    @Override
+    public void setIconUri(String iconUri) {
+        entity.setIconUri(iconUri);
+
+    }
+
+    @Override
+    public ResourceServer getResourceServer() {
+        return storeFactory.getResourceServerStore().findById(entity.getResourceServer().getId());
+    }
+
+    @Override
+    public String getOwner() {
+        return entity.getOwner();
+    }
+
+    @Override
+    public void updateScopes(Set<Scope> toUpdate) {
+        Set<String> ids = new HashSet<>();
+        for (Scope scope : toUpdate) {
+            ids.add(scope.getId());
+        }
+        Iterator<ScopeEntity> it = entity.getScopes().iterator();
+        while (it.hasNext()) {
+            ScopeEntity next = it.next();
+            if (!ids.contains(next.getId())) it.remove();
+            else ids.remove(next.getId());
+        }
+        for (String addId : ids) {
+            entity.getScopes().add(em.getReference(ScopeEntity.class, addId));
+        }
+    }
+
+
+    public static ResourceEntity toEntity(EntityManager em, Resource resource) {
+        if (resource instanceof ResourceAdapter) {
+            return ((ResourceAdapter)resource).getEntity();
+        } else {
+            return em.getReference(ResourceEntity.class, resource.getId());
+        }
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || !(o instanceof Resource)) return false;
+
+        Resource that = (Resource) o;
+        return that.getId().equals(getId());
+    }
+
+    @Override
+    public int hashCode() {
+        return getId().hashCode();
+    }
+
+
+}
diff --git a/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/ResourceServerAdapter.java b/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/ResourceServerAdapter.java
new file mode 100644
index 0000000..56d5856
--- /dev/null
+++ b/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/ResourceServerAdapter.java
@@ -0,0 +1,106 @@
+/*
+ * 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.authorization.jpa.store;
+
+import org.keycloak.authorization.AuthorizationProvider;
+import org.keycloak.authorization.jpa.entities.ResourceEntity;
+import org.keycloak.authorization.jpa.entities.ResourceServerEntity;
+import org.keycloak.authorization.model.Policy;
+import org.keycloak.authorization.model.Resource;
+import org.keycloak.authorization.model.ResourceServer;
+import org.keycloak.authorization.store.StoreFactory;
+import org.keycloak.models.jpa.JpaModel;
+import org.keycloak.representations.idm.authorization.PolicyEnforcementMode;
+
+import javax.persistence.EntityManager;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class ResourceServerAdapter implements ResourceServer, JpaModel<ResourceServerEntity> {
+    private ResourceServerEntity entity;
+    private EntityManager em;
+    private StoreFactory storeFactory;
+
+    public ResourceServerAdapter(ResourceServerEntity entity, EntityManager em, StoreFactory storeFactory) {
+        this.entity = entity;
+        this.em = em;
+        this.storeFactory = storeFactory;
+    }
+
+    @Override
+    public ResourceServerEntity getEntity() {
+        return entity;
+    }
+
+    @Override
+    public String getId() {
+        return entity.getId();
+    }
+
+    @Override
+    public String getClientId() {
+        return entity.getClientId();
+    }
+
+    @Override
+    public boolean isAllowRemoteResourceManagement() {
+        return entity.isAllowRemoteResourceManagement();
+    }
+
+    @Override
+    public void setAllowRemoteResourceManagement(boolean allowRemoteResourceManagement) {
+        entity.setAllowRemoteResourceManagement(allowRemoteResourceManagement);
+
+    }
+
+    @Override
+    public PolicyEnforcementMode getPolicyEnforcementMode() {
+        return entity.getPolicyEnforcementMode();
+    }
+
+    @Override
+    public void setPolicyEnforcementMode(PolicyEnforcementMode enforcementMode) {
+        entity.setPolicyEnforcementMode(enforcementMode);
+
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || !(o instanceof ResourceServer)) return false;
+
+        ResourceServer that = (ResourceServer) o;
+        return that.getId().equals(getId());
+    }
+
+    @Override
+    public int hashCode() {
+        return getId().hashCode();
+    }
+
+    public static ResourceServerEntity toEntity(EntityManager em, ResourceServer resource) {
+        if (resource instanceof ResourceAdapter) {
+            return ((ResourceServerAdapter)resource).getEntity();
+        } else {
+            return em.getReference(ResourceServerEntity.class, resource.getId());
+        }
+    }
+
+
+}
diff --git a/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/ScopeAdapter.java b/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/ScopeAdapter.java
new file mode 100644
index 0000000..6b59dc8
--- /dev/null
+++ b/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/ScopeAdapter.java
@@ -0,0 +1,103 @@
+/*
+ * 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.authorization.jpa.store;
+
+import org.keycloak.authorization.AuthorizationProvider;
+import org.keycloak.authorization.jpa.entities.ScopeEntity;
+import org.keycloak.authorization.model.ResourceServer;
+import org.keycloak.authorization.model.Scope;
+import org.keycloak.authorization.store.StoreFactory;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.jpa.JpaModel;
+
+import javax.persistence.EntityManager;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class ScopeAdapter implements Scope, JpaModel<ScopeEntity> {
+    private ScopeEntity entity;
+    private EntityManager em;
+    private StoreFactory storeFactory;
+
+    public ScopeAdapter(ScopeEntity entity, EntityManager em, StoreFactory storeFactory) {
+        this.entity = entity;
+        this.em = em;
+        this.storeFactory = storeFactory;
+    }
+
+    @Override
+    public ScopeEntity getEntity() {
+        return entity;
+    }
+
+    @Override
+    public String getId() {
+        return entity.getId();
+    }
+
+    @Override
+    public String getName() {
+        return entity.getName();
+    }
+
+    @Override
+    public void setName(String name) {
+        entity.setName(name);
+
+    }
+
+    @Override
+    public String getIconUri() {
+        return entity.getIconUri();
+    }
+
+    @Override
+    public void setIconUri(String iconUri) {
+        entity.setIconUri(iconUri);
+
+    }
+
+    @Override
+    public ResourceServer getResourceServer() {
+        return storeFactory.getResourceServerStore().findById(entity.getResourceServer().getId());
+    }
+
+    public static ScopeEntity toEntity(EntityManager em, Scope scope) {
+        if (scope instanceof ScopeAdapter) {
+            return ((ScopeAdapter)scope).getEntity();
+        } else {
+            return em.getReference(ScopeEntity.class, scope.getId());
+        }
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || !(o instanceof Scope)) return false;
+
+        Scope that = (Scope) o;
+        return that.getId().equals(getId());
+    }
+
+    @Override
+    public int hashCode() {
+        return getId().hashCode();
+    }
+
+}
diff --git a/server-spi-private/src/main/java/org/keycloak/authorization/AuthorizationProvider.java b/server-spi-private/src/main/java/org/keycloak/authorization/AuthorizationProvider.java
index c5b75d3..8a55ff1 100644
--- a/server-spi-private/src/main/java/org/keycloak/authorization/AuthorizationProvider.java
+++ b/server-spi-private/src/main/java/org/keycloak/authorization/AuthorizationProvider.java
@@ -28,6 +28,7 @@ import org.keycloak.authorization.permission.evaluator.Evaluators;
 import org.keycloak.authorization.policy.evaluation.DefaultPolicyEvaluator;
 import org.keycloak.authorization.policy.provider.PolicyProvider;
 import org.keycloak.authorization.policy.provider.PolicyProviderFactory;
+import org.keycloak.authorization.store.AuthorizationStoreFactory;
 import org.keycloak.authorization.store.PolicyStore;
 import org.keycloak.authorization.store.ResourceServerStore;
 import org.keycloak.authorization.store.ResourceStore;
@@ -35,13 +36,15 @@ import org.keycloak.authorization.store.ScopeStore;
 import org.keycloak.authorization.store.StoreFactory;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.RealmModel;
+import org.keycloak.models.cache.authorization.CachedStoreFactoryProvider;
+import org.keycloak.models.cache.authorization.CachedStoreProviderFactory;
 import org.keycloak.models.utils.RepresentationToModel;
 import org.keycloak.provider.Provider;
 import org.keycloak.representations.idm.authorization.AbstractPolicyRepresentation;
 
 /**
  * <p>The main contract here is the creation of {@link org.keycloak.authorization.permission.evaluator.PermissionEvaluator} instances.  Usually
- * an application has a single {@link AuthorizationProvider} instance and threads servicing client requests obtain {@link org.keycloak.authorization.core.permission.evaluator.PermissionEvaluator}
+ * an application has a single {@link AuthorizationProvider} instance and threads servicing client requests obtain {@link org.keycloak.authorization.permission.evaluator.PermissionEvaluator}
  * from the {@link #evaluators()} method.
  *
  * <p>The internal state of a {@link AuthorizationProvider} is immutable.  This internal state includes all of the metadata
@@ -69,14 +72,14 @@ public final class AuthorizationProvider implements Provider {
 
     private final DefaultPolicyEvaluator policyEvaluator;
     private StoreFactory storeFactory;
+    private StoreFactory storeFactoryDelegate;
     private final Map<String, PolicyProviderFactory> policyProviderFactories;
     private final KeycloakSession keycloakSession;
     private final RealmModel realm;
 
-    public AuthorizationProvider(KeycloakSession session, RealmModel realm, StoreFactory storeFactory, Map<String, PolicyProviderFactory> policyProviderFactories) {
+    public AuthorizationProvider(KeycloakSession session, RealmModel realm, Map<String, PolicyProviderFactory> policyProviderFactories) {
         this.keycloakSession = session;
         this.realm = realm;
-        this.storeFactory = storeFactory;
         this.policyProviderFactories = policyProviderFactories;
         this.policyEvaluator = new DefaultPolicyEvaluator(this);
     }
@@ -92,15 +95,32 @@ public final class AuthorizationProvider implements Provider {
     }
 
     /**
+     * Cache sits in front of this
+     *
      * Returns a {@link StoreFactory}.
      *
      * @return the {@link StoreFactory}
      */
     public StoreFactory getStoreFactory() {
-        return createStoreFactory();
+        if (storeFactory != null) return storeFactory;
+        storeFactory = keycloakSession.getProvider(CachedStoreFactoryProvider.class);
+        if (storeFactory == null) storeFactory = getLocalStoreFactory();
+        storeFactory = createStoreFactory(storeFactory);
+        return storeFactory;
     }
 
-    private StoreFactory createStoreFactory() {
+    /**
+     * No cache sits in front of this
+     *
+     * @return
+     */
+    public StoreFactory getLocalStoreFactory() {
+        if (storeFactoryDelegate != null) return storeFactoryDelegate;
+        storeFactoryDelegate = keycloakSession.getProvider(StoreFactory.class);
+        return storeFactoryDelegate;
+    }
+
+    private StoreFactory createStoreFactory(StoreFactory storeFactory) {
         return new StoreFactory() {
             @Override
             public ResourceStore getResourceStore() {
@@ -222,7 +242,7 @@ public final class AuthorizationProvider implements Provider {
      * Returns a {@link PolicyProviderFactory} given a <code>type</code>.
      *
      * @param type the type of the policy provider
-     * @param <F> the expected type of the provider
+     * @param <P> the expected type of the provider
      * @return a {@link PolicyProvider} with the given <code>type</code>
      */
     public <P extends PolicyProvider> P getProvider(String type) {
diff --git a/server-spi-private/src/main/java/org/keycloak/authorization/model/CachedModel.java b/server-spi-private/src/main/java/org/keycloak/authorization/model/CachedModel.java
new file mode 100644
index 0000000..d908a84
--- /dev/null
+++ b/server-spi-private/src/main/java/org/keycloak/authorization/model/CachedModel.java
@@ -0,0 +1,45 @@
+/*
+ * 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.authorization.model;
+
+/**
+ * Cached authorization model classes will implement this interface.
+ *
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public interface CachedModel<Model> {
+    /**
+     * Invalidates the cache for this model and returns a delegate that represents the actual data provider
+     *
+     * @return
+     */
+    Model getDelegateForUpdate();
+
+    /**
+     * Invalidate the cache for this model
+     *
+     */
+    void invalidate();
+
+    /**
+     * When was the model was loaded from database.
+     *
+     * @return
+     */
+    long getCacheTimestamp();
+}
diff --git a/server-spi-private/src/main/java/org/keycloak/authorization/model/Policy.java b/server-spi-private/src/main/java/org/keycloak/authorization/model/Policy.java
index 03596d9..f46f61a 100644
--- a/server-spi-private/src/main/java/org/keycloak/authorization/model/Policy.java
+++ b/server-spi-private/src/main/java/org/keycloak/authorization/model/Policy.java
@@ -76,10 +76,11 @@ public interface Policy {
     /**
      * Returns a {@link Map} holding string-based key/value pairs representing any additional configuration for this policy.
      *
-     * @return a map with any additional configuration defined for this policy.
+     * @return a unmodifiable map with any additional configuration defined for this policy.
      */
     Map<String, String> getConfig();
 
+
     /**
      * Sets a {@link Map} with string-based key/value pairs representing any additional configuration for this policy.
      *
@@ -87,6 +88,9 @@ public interface Policy {
      */
     void setConfig(Map<String, String> config);
 
+    void removeConfig(String name);
+    void putConfig(String name, String value);
+
     /**
      * Returns the name of this policy.
      *
@@ -120,7 +124,7 @@ public interface Policy {
      *
      * @return a resource server
      */
-    <R extends ResourceServer> R getResourceServer();
+     ResourceServer getResourceServer();
 
     /**
      * Returns the {@link Policy} instances associated with this policy and used to evaluate authorization decisions when
@@ -128,21 +132,21 @@ public interface Policy {
      *
      * @return the associated policies or an empty set if no policy is associated with this policy
      */
-    <P extends Policy> Set<P> getAssociatedPolicies();
+    Set<Policy> getAssociatedPolicies();
 
     /**
      * Returns the {@link Resource} instances where this policy applies.
      *
      * @return a set with all resource instances where this policy applies. Or an empty set if there is no resource associated with this policy
      */
-    <R extends Resource> Set<R> getResources();
+    Set<Resource> getResources();
 
     /**
      * Returns the {@link Scope} instances where this policy applies.
      *
      * @return a set with all scope instances where this policy applies. Or an empty set if there is no scope associated with this policy
      */
-    <S extends Scope> Set<S> getScopes();
+    Set<Scope> getScopes();
 
     void addScope(Scope scope);
 
diff --git a/server-spi-private/src/main/java/org/keycloak/authorization/model/Resource.java b/server-spi-private/src/main/java/org/keycloak/authorization/model/Resource.java
index 2bf2c6f..4c2521c 100644
--- a/server-spi-private/src/main/java/org/keycloak/authorization/model/Resource.java
+++ b/server-spi-private/src/main/java/org/keycloak/authorization/model/Resource.java
@@ -82,7 +82,7 @@ public interface Resource {
      *
      * @return a list with all scopes associated with this resource
      */
-    <S extends Scope> List<S> getScopes();
+     List<Scope> getScopes();
 
     /**
      * Returns an icon {@link java.net.URI} for this resource.
@@ -103,7 +103,7 @@ public interface Resource {
      *
      * @return the resource server associated with this resource
      */
-    <R extends ResourceServer> R getResourceServer();
+     ResourceServer getResourceServer();
 
     /**
      * Returns the resource's owner, which is usually an identifier that uniquely identifies the resource's owner.
diff --git a/server-spi-private/src/main/java/org/keycloak/authorization/store/AuthorizationStoreFactory.java b/server-spi-private/src/main/java/org/keycloak/authorization/store/AuthorizationStoreFactory.java
index 76a3fab..1c9c0df 100644
--- a/server-spi-private/src/main/java/org/keycloak/authorization/store/AuthorizationStoreFactory.java
+++ b/server-spi-private/src/main/java/org/keycloak/authorization/store/AuthorizationStoreFactory.java
@@ -21,10 +21,12 @@ package org.keycloak.authorization.store;
 import java.util.HashMap;
 import java.util.Map;
 
+import org.keycloak.authorization.AuthorizationProvider;
 import org.keycloak.authorization.store.syncronization.ClientApplicationSynchronizer;
 import org.keycloak.authorization.store.syncronization.RealmSynchronizer;
 import org.keycloak.authorization.store.syncronization.Synchronizer;
 import org.keycloak.authorization.store.syncronization.UserSynchronizer;
+import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.KeycloakSessionFactory;
 import org.keycloak.models.RealmModel.ClientRemovedEvent;
 import org.keycloak.models.RealmModel.RealmRemovedEvent;
diff --git a/server-spi-private/src/main/java/org/keycloak/authorization/store/ResourceStore.java b/server-spi-private/src/main/java/org/keycloak/authorization/store/ResourceStore.java
index b55ec74..9a2ac51 100644
--- a/server-spi-private/src/main/java/org/keycloak/authorization/store/ResourceStore.java
+++ b/server-spi-private/src/main/java/org/keycloak/authorization/store/ResourceStore.java
@@ -66,7 +66,7 @@ public interface ResourceStore {
     /**
      * Finds all {@link Resource} instances with the given uri.
      *
-     * @param ownerId the identifier of the owner
+     * @param uri the identifier of the uri
      * @return a list with all resource instances owned by the given owner
      */
     List<Resource> findByUri(String uri, String resourceServerId);
diff --git a/server-spi-private/src/main/java/org/keycloak/authorization/store/syncronization/ClientApplicationSynchronizer.java b/server-spi-private/src/main/java/org/keycloak/authorization/store/syncronization/ClientApplicationSynchronizer.java
index 686eeef..aeb039d 100644
--- a/server-spi-private/src/main/java/org/keycloak/authorization/store/syncronization/ClientApplicationSynchronizer.java
+++ b/server-spi-private/src/main/java/org/keycloak/authorization/store/syncronization/ClientApplicationSynchronizer.java
@@ -41,9 +41,9 @@ public class ClientApplicationSynchronizer implements Synchronizer<ClientRemoved
 
         if (resourceServer != null) {
             String id = resourceServer.getId();
-            storeFactory.getResourceStore().findByResourceServer(id).forEach(resource -> storeFactory.getResourceStore().delete(resource.getId()));
-            storeFactory.getScopeStore().findByResourceServer(id).forEach(scope -> storeFactory.getScopeStore().delete(scope.getId()));
-            storeFactory.getPolicyStore().findByResourceServer(id).forEach(scope -> storeFactory.getPolicyStore().delete(scope.getId()));
+            //storeFactory.getResourceStore().findByResourceServer(id).forEach(resource -> storeFactory.getResourceStore().delete(resource.getId()));
+            //storeFactory.getScopeStore().findByResourceServer(id).forEach(scope -> storeFactory.getScopeStore().delete(scope.getId()));
+            //storeFactory.getPolicyStore().findByResourceServer(id).forEach(scope -> storeFactory.getPolicyStore().delete(scope.getId()));
             storeFactory.getResourceServerStore().delete(id);
         }
     }
diff --git a/server-spi-private/src/main/java/org/keycloak/migration/migrators/MigrateTo2_1_0.java b/server-spi-private/src/main/java/org/keycloak/migration/migrators/MigrateTo2_1_0.java
index f8844f1..d1e0ca2 100644
--- a/server-spi-private/src/main/java/org/keycloak/migration/migrators/MigrateTo2_1_0.java
+++ b/server-spi-private/src/main/java/org/keycloak/migration/migrators/MigrateTo2_1_0.java
@@ -71,7 +71,7 @@ public class MigrateTo2_1_0 implements Migration {
 
             if (resourceServer != null) {
                 policyStore.findByType("role", resourceServer.getId()).forEach(policy -> {
-                    Map<String, String> config = policy.getConfig();
+                    Map<String, String> config = new HashMap(policy.getConfig());
                     String roles = config.get("roles");
                     List roleConfig;
 
diff --git a/server-spi-private/src/main/java/org/keycloak/models/cache/authorization/CachedStoreProviderFactory.java b/server-spi-private/src/main/java/org/keycloak/models/cache/authorization/CachedStoreProviderFactory.java
index b8563cb..d466f7a 100644
--- a/server-spi-private/src/main/java/org/keycloak/models/cache/authorization/CachedStoreProviderFactory.java
+++ b/server-spi-private/src/main/java/org/keycloak/models/cache/authorization/CachedStoreProviderFactory.java
@@ -18,6 +18,9 @@
 
 package org.keycloak.models.cache.authorization;
 
+import org.keycloak.authorization.AuthorizationProvider;
+import org.keycloak.authorization.store.StoreFactory;
+import org.keycloak.models.KeycloakSession;
 import org.keycloak.provider.ProviderFactory;
 
 /**
diff --git a/server-spi-private/src/main/java/org/keycloak/models/utils/RepresentationToModel.java b/server-spi-private/src/main/java/org/keycloak/models/utils/RepresentationToModel.java
index 1c90b0f..7e528fb 100755
--- a/server-spi-private/src/main/java/org/keycloak/models/utils/RepresentationToModel.java
+++ b/server-spi-private/src/main/java/org/keycloak/models/utils/RepresentationToModel.java
@@ -2110,7 +2110,7 @@ public class RepresentationToModel {
             }
         }
 
-        policy.getConfig().remove("scopes");
+        policy.removeConfig("scopes");
     }
 
     private static void updateAssociatedPolicies(Set<String> policyIds, Policy policy, StoreFactory storeFactory) {
@@ -2163,7 +2163,7 @@ public class RepresentationToModel {
             }
         }
 
-        policy.getConfig().remove("applyPolicies");
+        policy.removeConfig("applyPolicies");
     }
 
     private static void updateResources(Set<String> resourceIds, Policy policy, StoreFactory storeFactory) {
@@ -2209,7 +2209,7 @@ public class RepresentationToModel {
             }
         }
 
-        policy.getConfig().remove("resources");
+        policy.removeConfig("resources");
     }
 
     public static Resource toModel(ResourceRepresentation resource, ResourceServer resourceServer, AuthorizationProvider authorization) {
diff --git a/services/src/main/java/org/keycloak/authorization/authorization/AuthorizationTokenService.java b/services/src/main/java/org/keycloak/authorization/authorization/AuthorizationTokenService.java
index fb28054..3a9337e 100644
--- a/services/src/main/java/org/keycloak/authorization/authorization/AuthorizationTokenService.java
+++ b/services/src/main/java/org/keycloak/authorization/authorization/AuthorizationTokenService.java
@@ -16,6 +16,7 @@
  */
 package org.keycloak.authorization.authorization;
 
+import org.jboss.logging.Logger;
 import org.jboss.resteasy.spi.HttpRequest;
 import org.keycloak.OAuth2Constants;
 import org.keycloak.OAuthErrorException;
@@ -46,6 +47,7 @@ import org.keycloak.representations.idm.authorization.Permission;
 import org.keycloak.representations.idm.authorization.ScopeRepresentation;
 import org.keycloak.services.ErrorResponseException;
 import org.keycloak.services.resources.Cors;
+import org.keycloak.services.resources.RealmsResource;
 
 import javax.ws.rs.Consumes;
 import javax.ws.rs.OPTIONS;
@@ -72,6 +74,7 @@ import java.util.stream.Stream;
  * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
  */
 public class AuthorizationTokenService {
+    protected static final Logger logger = Logger.getLogger(AuthorizationTokenService.class);
 
     private final AuthorizationProvider authorization;
 
@@ -131,6 +134,7 @@ public class AuthorizationTokenService {
 
             @Override
             public void onError(Throwable cause) {
+                logger.error("failed authorize", cause);
                 asyncResponse.resume(cause);
             }
         });
diff --git a/services/src/main/java/org/keycloak/authorization/DefaultAuthorizationProviderFactory.java b/services/src/main/java/org/keycloak/authorization/DefaultAuthorizationProviderFactory.java
index cc06284..d9d7b2d 100644
--- a/services/src/main/java/org/keycloak/authorization/DefaultAuthorizationProviderFactory.java
+++ b/services/src/main/java/org/keycloak/authorization/DefaultAuthorizationProviderFactory.java
@@ -65,11 +65,7 @@ public class DefaultAuthorizationProviderFactory implements AuthorizationProvide
 
     @Override
     public AuthorizationProvider create(KeycloakSession session, RealmModel realm) {
-        StoreFactory storeFactory = session.getProvider(CachedStoreFactoryProvider.class);
-        if (storeFactory == null) {
-            storeFactory = session.getProvider(StoreFactory.class);
-        }
-        return new AuthorizationProvider(session, realm, storeFactory, policyProviderFactories);
+        return new AuthorizationProvider(session, realm, policyProviderFactories);
     }
 
     private Map<String, PolicyProviderFactory> configurePolicyProviderFactories(KeycloakSessionFactory keycloakSessionFactory) {
diff --git a/services/src/main/java/org/keycloak/authorization/entitlement/EntitlementService.java b/services/src/main/java/org/keycloak/authorization/entitlement/EntitlementService.java
index 326deb6..463ff0b 100644
--- a/services/src/main/java/org/keycloak/authorization/entitlement/EntitlementService.java
+++ b/services/src/main/java/org/keycloak/authorization/entitlement/EntitlementService.java
@@ -41,10 +41,12 @@ import javax.ws.rs.core.Context;
 import javax.ws.rs.core.Response;
 import javax.ws.rs.core.Response.Status;
 
+import org.jboss.logging.Logger;
 import org.jboss.resteasy.spi.HttpRequest;
 import org.keycloak.OAuth2Constants;
 import org.keycloak.OAuthErrorException;
 import org.keycloak.authorization.AuthorizationProvider;
+import org.keycloak.authorization.authorization.AuthorizationTokenService;
 import org.keycloak.authorization.common.KeycloakEvaluationContext;
 import org.keycloak.authorization.common.KeycloakIdentity;
 import org.keycloak.authorization.entitlement.representation.EntitlementRequest;
@@ -79,6 +81,7 @@ import org.keycloak.services.resources.Cors;
  */
 public class EntitlementService {
 
+    protected static final Logger logger = Logger.getLogger(EntitlementService.class);
     private final AuthorizationProvider authorization;
 
     @Context
@@ -122,6 +125,7 @@ public class EntitlementService {
 
             @Override
             public void onError(Throwable cause) {
+                logger.error("failed", cause);
                 asyncResponse.resume(cause);
             }
 
@@ -175,6 +179,7 @@ public class EntitlementService {
             authorization.evaluators().from(createPermissions(entitlementRequest, resourceServer, authorization), new KeycloakEvaluationContext(this.authorization.getKeycloakSession())).evaluate(new DecisionResultCollector() {
                 @Override
                 public void onError(Throwable cause) {
+                    logger.error("failed", cause);
                     asyncResponse.resume(cause);
                 }
 
diff --git a/services/src/main/java/org/keycloak/authorization/util/Permissions.java b/services/src/main/java/org/keycloak/authorization/util/Permissions.java
index 2e2c4a8..a805fbc 100644
--- a/services/src/main/java/org/keycloak/authorization/util/Permissions.java
+++ b/services/src/main/java/org/keycloak/authorization/util/Permissions.java
@@ -21,6 +21,7 @@ package org.keycloak.authorization.util;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -61,8 +62,8 @@ public final class Permissions {
         StoreFactory storeFactory = authorization.getStoreFactory();
         ResourceStore resourceStore = storeFactory.getResourceStore();
 
-        resourceStore.findByOwner(resourceServer.getClientId(), resourceServer.getId()).stream().forEach(resource -> permissions.addAll(createResourcePermissionsWithScopes(resource, resource.getScopes(), authorization)));
-        resourceStore.findByOwner(identity.getId(), resourceServer.getId()).stream().forEach(resource -> permissions.addAll(createResourcePermissionsWithScopes(resource, resource.getScopes(), authorization)));
+        resourceStore.findByOwner(resourceServer.getClientId(), resourceServer.getId()).stream().forEach(resource -> permissions.addAll(createResourcePermissionsWithScopes(resource, new LinkedList(resource.getScopes()), authorization)));
+        resourceStore.findByOwner(identity.getId(), resourceServer.getId()).stream().forEach(resource -> permissions.addAll(createResourcePermissionsWithScopes(resource, new LinkedList(resource.getScopes()), authorization)));
 
         return permissions;
     }
@@ -74,7 +75,7 @@ public final class Permissions {
         List<Scope> scopes;
 
         if (requestedScopes.isEmpty()) {
-            scopes = resource.getScopes();
+            scopes = new LinkedList<>(resource.getScopes());
             // check if there is a typed resource whose scopes are inherited by the resource being requested. In this case, we assume that parent resource
             // is owned by the resource server itself
             if (type != null && !resource.getOwner().equals(resourceServer.getClientId())) {
@@ -102,7 +103,6 @@ public final class Permissions {
                 return byName;
             }).collect(Collectors.toList());
         }
-
         permissions.add(new ResourcePermission(resource, scopes, resource.getResourceServer()));
 
         return permissions;
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/authz/ConflictingScopePermissionTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/authz/ConflictingScopePermissionTest.java
index 45a937c..450820e 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/authz/ConflictingScopePermissionTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/authz/ConflictingScopePermissionTest.java
@@ -213,7 +213,7 @@ public class ConflictingScopePermissionTest extends AbstractKeycloakTest {
         }
 
         representation.addScope(scopes.toArray(new String[scopes.size()]));
-        representation.addPolicy(scopes.toArray(new String[policies.size()]));
+        representation.addPolicy(policies.toArray(new String[policies.size()]));
 
         authorization.permissions().scope().create(representation);
     }
diff --git a/wildfly/server-subsystem/src/main/resources/subsystem-templates/keycloak-infinispan.xml b/wildfly/server-subsystem/src/main/resources/subsystem-templates/keycloak-infinispan.xml
index 0d3b4aa..818626a 100755
--- a/wildfly/server-subsystem/src/main/resources/subsystem-templates/keycloak-infinispan.xml
+++ b/wildfly/server-subsystem/src/main/resources/subsystem-templates/keycloak-infinispan.xml
@@ -37,7 +37,7 @@
                 <local-cache name="loginFailures"/>
                 <local-cache name="work"/>
                 <local-cache name="authorization">
-                    <eviction max-entries="100" strategy="LRU"/>
+                    <eviction max-entries="10000" strategy="LRU"/>
                 </local-cache>
                 <local-cache name="keys">
                     <eviction max-entries="1000" strategy="LRU"/>