keycloak-aplcache

Merge pull request #3561 from glavoie/KEYCLOAK-3990 KEYCLOAK-3990:

5/29/2017 4:39:40 AM

Details

diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/ClientAdapter.java b/model/jpa/src/main/java/org/keycloak/models/jpa/ClientAdapter.java
index 92d41d5..f3c41e7 100755
--- a/model/jpa/src/main/java/org/keycloak/models/jpa/ClientAdapter.java
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/ClientAdapter.java
@@ -29,18 +29,20 @@ import org.keycloak.models.jpa.entities.ClientEntity;
 import org.keycloak.models.jpa.entities.ClientTemplateEntity;
 import org.keycloak.models.jpa.entities.ProtocolMapperEntity;
 import org.keycloak.models.jpa.entities.RoleEntity;
-import org.keycloak.models.jpa.entities.ScopeMappingEntity;
 import org.keycloak.models.utils.KeycloakModelUtils;
 
 import javax.persistence.EntityManager;
 import javax.persistence.TypedQuery;
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 import java.util.Set;
+import java.util.stream.Collectors;
 
 /**
  * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
@@ -222,7 +224,7 @@ public class ClientAdapter implements ClientModel, JpaModel<ClientEntity> {
     }
 
     @Override
-         public Set<RoleModel> getRealmScopeMappings() {
+    public Set<RoleModel> getRealmScopeMappings() {
         Set<RoleModel> roleMappings = getScopeMappings();
 
         Set<RoleModel> appRoles = new HashSet<>();
@@ -240,47 +242,22 @@ public class ClientAdapter implements ClientModel, JpaModel<ClientEntity> {
 
     @Override
     public Set<RoleModel> getScopeMappings() {
-        TypedQuery<String> query = em.createNamedQuery("clientScopeMappingIds", String.class);
-        query.setParameter("client", getEntity());
-        List<String> ids = query.getResultList();
-        Set<RoleModel> roles = new HashSet<RoleModel>();
-        for (String roleId : ids) {
-            RoleModel role = realm.getRoleById(roleId);
-            if (role == null) continue;
-            roles.add(role);
-        }
-        return roles;
+        return getEntity().getScopeMapping().stream()
+                .map(RoleEntity::getId)
+                .map(realm::getRoleById)
+                .filter(Objects::nonNull)
+                .collect(Collectors.toSet());
     }
 
     @Override
     public void addScopeMapping(RoleModel role) {
-        Set<RoleModel> roles = getScopeMappings();
-        if (roles.contains(role)) return;
-        ScopeMappingEntity entity = new ScopeMappingEntity();
-        entity.setClient(getEntity());
         RoleEntity roleEntity = RoleAdapter.toRoleEntity(role, em);
-        entity.setRole(roleEntity);
-        em.persist(entity);
-        em.flush();
-        em.detach(entity);
+        getEntity().getScopeMapping().add(roleEntity);
     }
 
     @Override
     public void deleteScopeMapping(RoleModel role) {
-        TypedQuery<ScopeMappingEntity> query = getRealmScopeMappingQuery(role);
-        List<ScopeMappingEntity> results = query.getResultList();
-        if (results.size() == 0) return;
-        for (ScopeMappingEntity entity : results) {
-            em.remove(entity);
-        }
-    }
-
-    protected TypedQuery<ScopeMappingEntity> getRealmScopeMappingQuery(RoleModel role) {
-        TypedQuery<ScopeMappingEntity> query = em.createNamedQuery("hasScope", ScopeMappingEntity.class);
-        query.setParameter("client", getEntity());
-        RoleEntity roleEntity = RoleAdapter.toRoleEntity(role, em);
-        query.setParameter("role", roleEntity);
-        return query;
+        getEntity().getScopeMapping().remove(RoleAdapter.toRoleEntity(role, em));
     }
 
     @Override
@@ -689,7 +666,6 @@ public class ClientAdapter implements ClientModel, JpaModel<ClientEntity> {
         }
         RoleEntity roleEntity = RoleAdapter.toRoleEntity(role, em);
         entities.add(roleEntity);
-        em.flush();
     }
 
     @Override
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/AuthenticationExecutionEntity.java b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/AuthenticationExecutionEntity.java
index 8e759a4..c46b1cd 100755
--- a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/AuthenticationExecutionEntity.java
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/AuthenticationExecutionEntity.java
@@ -37,11 +37,6 @@ import javax.persistence.Table;
  */
 @Table(name="AUTHENTICATION_EXECUTION")
 @Entity
-@NamedQueries({
-        @NamedQuery(name="getAuthenticationExecutionsByFlow", query="select authenticator from AuthenticationExecutionEntity authenticator where authenticator.realm = :realm and authenticator.parentFlow = :parentFlow"),
-        @NamedQuery(name="deleteAuthenticationExecutionsByRealm", query="delete from AuthenticationExecutionEntity authenticator where authenticator.realm = :realm"),
-        @NamedQuery(name="deleteAuthenticationExecutionsByRealmAndFlow", query="delete from AuthenticationExecutionEntity authenticator where authenticator.realm = :realm and authenticator.parentFlow = :parentFlow"),
-})
 public class AuthenticationExecutionEntity {
     @Id
     @Column(name="ID", length = 36)
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/AuthenticationFlowEntity.java b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/AuthenticationFlowEntity.java
index 402acf1..b9927b9 100755
--- a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/AuthenticationFlowEntity.java
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/AuthenticationFlowEntity.java
@@ -39,10 +39,6 @@ import java.util.Collection;
  */
 @Table(name="AUTHENTICATION_FLOW")
 @Entity
-@NamedQueries({
-        @NamedQuery(name="getAuthenticationFlowsByRealm", query="select flow from AuthenticationFlowEntity flow where flow.realm = :realm"),
-        @NamedQuery(name="deleteAuthenticationFlowByRealm", query="delete from AuthenticationFlowEntity flow where flow.realm = :realm")
-})
 public class AuthenticationFlowEntity {
     @Id
     @Column(name="ID", length = 36)
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/ClientEntity.java b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/ClientEntity.java
index efbd154..ececf70 100755
--- a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/ClientEntity.java
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/ClientEntity.java
@@ -162,6 +162,10 @@ public class ClientEntity {
     @JoinTable(name="CLIENT_DEFAULT_ROLES", joinColumns = { @JoinColumn(name="CLIENT_ID")}, inverseJoinColumns = { @JoinColumn(name="ROLE_ID")})
     Collection<RoleEntity> defaultRoles = new ArrayList<RoleEntity>();
 
+    @OneToMany(fetch = FetchType.LAZY)
+    @JoinTable(name="SCOPE_MAPPING", joinColumns = { @JoinColumn(name="CLIENT_ID")}, inverseJoinColumns = { @JoinColumn(name="ROLE_ID")})
+    protected Set<RoleEntity> scopeMapping = new HashSet<>();
+
     @ElementCollection
     @MapKeyColumn(name="NAME")
     @Column(name="VALUE")
@@ -456,6 +460,14 @@ public class ClientEntity {
         this.useTemplateMappers = useTemplateMappers;
     }
 
+    public Set<RoleEntity> getScopeMapping() {
+        return scopeMapping;
+    }
+
+    public void setScopeMapping(Set<RoleEntity> scopeMapping) {
+        this.scopeMapping = scopeMapping;
+    }
+
     @Override
     public boolean equals(Object o) {
         if (this == o) return true;
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/ComponentConfigEntity.java b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/ComponentConfigEntity.java
index bf141a8..4dda333 100755
--- a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/ComponentConfigEntity.java
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/ComponentConfigEntity.java
@@ -33,12 +33,6 @@ import javax.persistence.Table;
  * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
  * @version $Revision: 1 $
  */
-@NamedQueries({
-        @NamedQuery(name="getComponentConfig", query="select attr from ComponentConfigEntity attr where attr.component = :component"),
-        @NamedQuery(name="deleteComponentConfigByComponent", query="delete from  ComponentConfigEntity attr where attr.component = :component"),
-        @NamedQuery(name="deleteComponentConfigByRealm", query="delete from  ComponentConfigEntity attr where attr.component IN (select u from ComponentEntity u where u.realm=:realm)"),
-        @NamedQuery(name="deleteComponentConfigByParent", query="delete from  ComponentConfigEntity attr where attr.component IN (select u from ComponentEntity u where u.parentId=:parentId)"),
-})
 @Table(name="COMPONENT_CONFIG")
 @Entity
 public class ComponentConfigEntity {
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/ComponentEntity.java b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/ComponentEntity.java
index 0a7728e..d688f8e 100755
--- a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/ComponentEntity.java
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/ComponentEntity.java
@@ -17,8 +17,12 @@
 
 package org.keycloak.models.jpa.entities;
 
+import java.util.HashSet;
+import java.util.Set;
+
 import javax.persistence.Access;
 import javax.persistence.AccessType;
+import javax.persistence.CascadeType;
 import javax.persistence.Column;
 import javax.persistence.Entity;
 import javax.persistence.FetchType;
@@ -27,19 +31,12 @@ import javax.persistence.JoinColumn;
 import javax.persistence.ManyToOne;
 import javax.persistence.NamedQueries;
 import javax.persistence.NamedQuery;
+import javax.persistence.OneToMany;
 import javax.persistence.Table;
 
 /**
  * @author <a href="mailto:bburke@redhat.com">Bill Burke</a>
  */
-@NamedQueries({
-        @NamedQuery(name="getComponents", query="select attr from ComponentEntity attr where attr.realm = :realm"),
-        @NamedQuery(name="getComponentsByParentAndType", query="select attr from ComponentEntity attr where attr.realm = :realm and attr.providerType = :providerType and attr.parentId = :parentId"),
-        @NamedQuery(name="getComponentByParent", query="select attr from ComponentEntity attr where attr.realm = :realm and attr.parentId = :parentId"),
-        @NamedQuery(name="getComponentIdsByParent", query="select attr.id from ComponentEntity attr where attr.realm = :realm and attr.parentId = :parentId"),
-        @NamedQuery(name="deleteComponentByRealm", query="delete from  ComponentEntity c where c.realm = :realm"),
-        @NamedQuery(name="deleteComponentByParent", query="delete from  ComponentEntity c where c.parentId = :parentId")
-})
 @Entity
 @Table(name="COMPONENT")
 public class ComponentEntity {
@@ -68,6 +65,9 @@ public class ComponentEntity {
     @Column(name="SUB_TYPE")
     protected String subType;
 
+    @OneToMany(fetch = FetchType.LAZY, cascade ={ CascadeType.ALL}, orphanRemoval = true, mappedBy = "component")
+    Set<ComponentConfigEntity> componentConfigs = new HashSet<>();
+
     public String getId() {
         return id;
     }
@@ -124,6 +124,14 @@ public class ComponentEntity {
         this.realm = realm;
     }
 
+    public Set<ComponentConfigEntity> getComponentConfigs() {
+        return componentConfigs;
+    }
+
+    public void setComponentConfigs(Set<ComponentConfigEntity> componentConfigs) {
+        this.componentConfigs = componentConfigs;
+    }
+
     @Override
     public boolean equals(Object o) {
         if (this == o) return true;
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/GroupAttributeEntity.java b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/GroupAttributeEntity.java
index a5dbfc4..b65febd 100755
--- a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/GroupAttributeEntity.java
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/GroupAttributeEntity.java
@@ -35,8 +35,6 @@ import javax.persistence.Table;
  */
 @NamedQueries({
         @NamedQuery(name="getGroupAttributesByNameAndValue", query="select attr from GroupAttributeEntity attr where attr.name = :name and attr.value = :value"),
-        @NamedQuery(name="deleteGroupAttributesByGroup", query="delete from  GroupAttributeEntity attr where attr.group = :group"),
-        @NamedQuery(name="deleteGroupAttributesByRealm", query="delete from  GroupAttributeEntity attr where attr.group IN (select u from GroupEntity u where u.realm=:realm)")
 })
 @Table(name="GROUP_ATTRIBUTE")
 @Entity
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/GroupEntity.java b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/GroupEntity.java
index 6f4c1ec..98b130a 100755
--- a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/GroupEntity.java
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/GroupEntity.java
@@ -38,13 +38,7 @@ import java.util.Collection;
  * @version $Revision: 1 $
  */
 @NamedQueries({
-        @NamedQuery(name="getAllGroupsByRealm", query="select u from GroupEntity u where u.realm = :realm order by u.name"),
-        @NamedQuery(name="getAllGroupIdsByRealm", query="select u.id from GroupEntity u where u.realm.id = :realm order by u.name"),
-        @NamedQuery(name="getGroupById", query="select u from GroupEntity u where u.id = :id and u.realm = :realm"),
         @NamedQuery(name="getGroupIdsByParent", query="select u.id from GroupEntity u where u.parent = :parent"),
-        @NamedQuery(name="getTopLevelGroupIds", query="select u.id from GroupEntity u where u.parent is null and u.realm.id = :realm"),
-        @NamedQuery(name="getGroupCount", query="select count(u) from GroupEntity u where u.realm = :realm"),
-        @NamedQuery(name="deleteGroupsByRealm", query="delete from GroupEntity u where u.realm = :realm")
 })
 @Entity
 @Table(name="KEYCLOAK_GROUP")
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/RealmEntity.java b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/RealmEntity.java
index cc62c8a..13988dc 100755
--- a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/RealmEntity.java
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/RealmEntity.java
@@ -159,6 +159,9 @@ public class RealmEntity {
     @JoinTable(name="REALM_DEFAULT_GROUPS", joinColumns = { @JoinColumn(name="REALM_ID")}, inverseJoinColumns = { @JoinColumn(name="GROUP_ID")})
     protected Collection<GroupEntity> defaultGroups = new ArrayList<>();
 
+    @OneToMany(fetch = FetchType.LAZY, cascade ={CascadeType.REMOVE}, orphanRemoval = true, mappedBy = "realm")
+    protected Collection<GroupEntity> groups = new ArrayList<>();
+
     @Column(name="EVENTS_ENABLED")
     protected boolean eventsEnabled;
     @Column(name="EVENTS_EXPIRATION")
@@ -199,6 +202,9 @@ public class RealmEntity {
     @OneToMany(cascade ={CascadeType.REMOVE}, orphanRemoval = true, mappedBy = "realm")
     Collection<AuthenticationFlowEntity> authenticationFlows = new ArrayList<>();
 
+    @OneToMany(fetch = FetchType.LAZY, cascade ={CascadeType.ALL}, orphanRemoval = true, mappedBy = "realm")
+    Set<ComponentEntity> components = new HashSet<>();
+
     @Column(name="BROWSER_FLOW")
     protected String browserFlow;
 
@@ -426,6 +432,14 @@ public class RealmEntity {
         this.defaultGroups = defaultGroups;
     }
 
+    public Collection<GroupEntity> getGroups() {
+        return groups;
+    }
+
+    public void setGroups(Collection<GroupEntity> groups) {
+        this.groups = groups;
+    }
+
     public String getPasswordPolicy() {
         return passwordPolicy;
     }
@@ -623,6 +637,14 @@ public class RealmEntity {
         this.authenticationFlows = authenticationFlows;
     }
 
+    public Set<ComponentEntity> getComponents() {
+        return components;
+    }
+
+    public void setComponents(Set<ComponentEntity> components) {
+        this.components = components;
+    }
+
     public String getOtpPolicyType() {
         return otpPolicyType;
     }
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/JpaRealmProvider.java b/model/jpa/src/main/java/org/keycloak/models/jpa/JpaRealmProvider.java
index 55e4108..718d19a 100755
--- a/model/jpa/src/main/java/org/keycloak/models/jpa/JpaRealmProvider.java
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/JpaRealmProvider.java
@@ -43,6 +43,7 @@ import java.util.HashSet;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Set;
+import java.util.stream.Collectors;
 
 /**
  * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
@@ -133,14 +134,6 @@ public class JpaRealmProvider implements RealmProvider {
 
         int num = em.createNamedQuery("deleteGroupRoleMappingsByRealm")
                 .setParameter("realm", realm).executeUpdate();
-        num = em.createNamedQuery("deleteGroupAttributesByRealm")
-                .setParameter("realm", realm).executeUpdate();
-        num = em.createNamedQuery("deleteGroupsByRealm")
-                .setParameter("realm", realm).executeUpdate();
-        num = em.createNamedQuery("deleteComponentConfigByRealm")
-                .setParameter("realm", realm).executeUpdate();
-        num = em.createNamedQuery("deleteComponentByRealm")
-                .setParameter("realm", realm).executeUpdate();
 
         TypedQuery<String> query = em.createNamedQuery("getClientIdsByRealm", String.class);
         query.setParameter("realm", realm.getId());
@@ -228,7 +221,6 @@ public class JpaRealmProvider implements RealmProvider {
         roleEntity.setClientRole(true);
         roleEntity.setRealmId(realm.getId());
         em.persist(roleEntity);
-        em.flush();
         RoleAdapter adapter = new RoleAdapter(session, realm, em, roleEntity);
         return adapter;
     }
@@ -281,10 +273,11 @@ public class JpaRealmProvider implements RealmProvider {
         RoleEntity roleEntity = em.getReference(RoleEntity.class, role.getId());
         String compositeRoleTable = JpaUtils.getTableNameForNativeQuery("COMPOSITE_ROLE", em);
         em.createNativeQuery("delete from " + compositeRoleTable + " where CHILD_ROLE = :role").setParameter("role", roleEntity).executeUpdate();
-        em.createNamedQuery("deleteScopeMappingByRole").setParameter("role", roleEntity).executeUpdate();
+        realm.getClients().forEach(c -> c.deleteScopeMapping(role));
         em.createNamedQuery("deleteTemplateScopeMappingByRole").setParameter("role", roleEntity).executeUpdate();
         int val = em.createNamedQuery("deleteGroupRoleMappingsByRole").setParameter("roleId", roleEntity.getId()).executeUpdate();
 
+        em.flush();
         em.remove(roleEntity);
 
         session.getKeycloakSessionFactory().publish(new RoleContainerModel.RoleRemovedEvent() {
@@ -337,27 +330,23 @@ public class JpaRealmProvider implements RealmProvider {
 
     @Override
     public List<GroupModel> getGroups(RealmModel realm) {
-        List<String> groups =  em.createNamedQuery("getAllGroupIdsByRealm", String.class)
-                .setParameter("realm", realm.getId()).getResultList();
-        if (groups == null) return Collections.EMPTY_LIST;
-        List<GroupModel> list = new LinkedList<>();
-        for (String id : groups) {
-            list.add(session.realms().getGroupById(id, realm));
-        }
-        return Collections.unmodifiableList(list);
+        RealmEntity ref = em.getReference(RealmEntity.class, realm.getId());
+
+        return ref.getGroups().stream()
+                .map(g -> session.realms().getGroupById(g.getId(), realm))
+                .collect(Collectors.collectingAndThen(
+                        Collectors.toList(), Collections::unmodifiableList));
     }
 
     @Override
     public List<GroupModel> getTopLevelGroups(RealmModel realm) {
-        List<String> groups =  em.createNamedQuery("getTopLevelGroupIds", String.class)
-                .setParameter("realm", realm.getId())
-                .getResultList();
-        if (groups == null) return Collections.EMPTY_LIST;
-        List<GroupModel> list = new LinkedList<>();
-        for (String id : groups) {
-            list.add(session.realms().getGroupById(id, realm));
-        }
-        return Collections.unmodifiableList(list);
+        RealmEntity ref = em.getReference(RealmEntity.class, realm.getId());
+
+        return ref.getGroups().stream()
+                .filter(g -> g.getParent() == null)
+                .map(g -> session.realms().getGroupById(g.getId(), realm))
+                .collect(Collectors.collectingAndThen(
+                        Collectors.toList(), Collections::unmodifiableList));
     }
 
     @Override
@@ -377,9 +366,11 @@ public class JpaRealmProvider implements RealmProvider {
         if (!groupEntity.getRealm().getId().equals(realm.getId())) {
             return false;
         }
-        // I don't think we need this as GroupEntity has cascade removal.  It causes batch errors if you turn this on.
-        // em.createNamedQuery("deleteGroupAttributesByGroup").setParameter("group", groupEntity).executeUpdate();
         em.createNamedQuery("deleteGroupRoleMappingsByGroup").setParameter("group", groupEntity).executeUpdate();
+
+        RealmEntity realmEntity = em.getReference(RealmEntity.class, realm.getId());
+        realmEntity.getGroups().remove(groupEntity);
+
         em.remove(groupEntity);
         return true;
 
@@ -401,6 +392,7 @@ public class JpaRealmProvider implements RealmProvider {
         RealmEntity realmEntity = em.getReference(RealmEntity.class, realm.getId());
         groupEntity.setRealm(realmEntity);
         em.persist(groupEntity);
+        realmEntity.getGroups().add(groupEntity);
 
         GroupAdapter adapter = new GroupAdapter(realm, em, groupEntity);
         return adapter;
@@ -494,9 +486,6 @@ public class JpaRealmProvider implements RealmProvider {
 
         ClientEntity clientEntity = ((ClientAdapter)client).getEntity();
 
-        em.createNamedQuery("deleteScopeMappingByClient").setParameter("client", clientEntity).executeUpdate();
-        em.flush();
-
         session.getKeycloakSessionFactory().publish(new RealmModel.ClientRemovedEvent() {
             @Override
             public ClientModel getClient() {
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/RealmAdapter.java b/model/jpa/src/main/java/org/keycloak/models/jpa/RealmAdapter.java
index b3b4db2..33ca943 100755
--- a/model/jpa/src/main/java/org/keycloak/models/jpa/RealmAdapter.java
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/RealmAdapter.java
@@ -58,7 +58,6 @@ import org.keycloak.models.utils.ComponentUtil;
 import org.keycloak.models.utils.KeycloakModelUtils;
 
 import javax.persistence.EntityManager;
-import javax.persistence.TypedQuery;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
@@ -68,7 +67,10 @@ import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 import java.util.Set;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
 
 /**
  * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
@@ -1375,16 +1377,10 @@ public class RealmAdapter implements RealmModel, JpaModel<RealmEntity> {
 
     @Override
     public List<AuthenticationFlowModel> getAuthenticationFlows() {
-        TypedQuery<AuthenticationFlowEntity> query = em.createNamedQuery("getAuthenticationFlowsByRealm", AuthenticationFlowEntity.class);
-        query.setParameter("realm", realm);
-        List<AuthenticationFlowEntity> flows = query.getResultList();
-        if (flows.isEmpty()) return Collections.EMPTY_LIST;
-        List<AuthenticationFlowModel> models = new LinkedList<>();
-        for (AuthenticationFlowEntity entity : flows) {
-            AuthenticationFlowModel model = entityToModel(entity);
-            models.add(model);
-        }
-        return Collections.unmodifiableList(models);
+        return realm.getAuthenticationFlows().stream()
+                .map(this::entityToModel)
+                .collect(Collectors.collectingAndThen(
+                        Collectors.toList(), Collections::unmodifiableList));
     }
 
     @Override
@@ -1461,26 +1457,20 @@ public class RealmAdapter implements RealmModel, JpaModel<RealmEntity> {
         entity.setRealm(realm);
         realm.getAuthenticationFlows().add(entity);
         em.persist(entity);
-        em.flush();
         model.setId(entity.getId());
         return model;
     }
 
     @Override
     public List<AuthenticationExecutionModel> getAuthenticationExecutions(String flowId) {
-        TypedQuery<AuthenticationExecutionEntity> query = em.createNamedQuery("getAuthenticationExecutionsByFlow", AuthenticationExecutionEntity.class);
         AuthenticationFlowEntity flow = em.getReference(AuthenticationFlowEntity.class, flowId);
-        query.setParameter("realm", realm);
-        query.setParameter("parentFlow", flow);
-        List<AuthenticationExecutionEntity> queryResult = query.getResultList();
-        if (queryResult.isEmpty()) return Collections.EMPTY_LIST;
-        List<AuthenticationExecutionModel> executions = new LinkedList<>();
-        for (AuthenticationExecutionEntity entity : queryResult) {
-            AuthenticationExecutionModel model = entityToModel(entity);
-            executions.add(model);
-        }
-        Collections.sort(executions, AuthenticationExecutionModel.ExecutionComparator.SINGLETON);
-        return Collections.unmodifiableList(executions);
+
+        return flow.getExecutions().stream()
+                .filter(e -> getId().equals(e.getRealm().getId()))
+                .map(this::entityToModel)
+                .sorted(AuthenticationExecutionModel.ExecutionComparator.SINGLETON)
+                .collect(Collectors.collectingAndThen(
+                        Collectors.toList(), Collections::unmodifiableList));
     }
 
     public AuthenticationExecutionModel entityToModel(AuthenticationExecutionEntity entity) {
@@ -1519,7 +1509,6 @@ public class RealmAdapter implements RealmModel, JpaModel<RealmEntity> {
         entity.setRealm(realm);
         entity.setAutheticatorFlow(model.isAuthenticatorFlow());
         em.persist(entity);
-        em.flush();
         model.setId(entity.getId());
         return model;
 
@@ -1557,7 +1546,6 @@ public class RealmAdapter implements RealmModel, JpaModel<RealmEntity> {
         auth.setConfig(model.getConfig());
         realm.getAuthenticatorConfigs().add(auth);
         em.persist(auth);
-        em.flush();
         model.setId(auth.getId());
         return model;
     }
@@ -1850,12 +1838,14 @@ public class RealmAdapter implements RealmModel, JpaModel<RealmEntity> {
         c.setSubType(model.getSubType());
         c.setRealm(realm);
         em.persist(c);
+        realm.getComponents().add(c);
         setConfig(model, c);
         model.setId(c.getId());
         return model;
     }
 
     protected void setConfig(ComponentModel model, ComponentEntity c) {
+        c.getComponentConfigs().clear();
         for (String key : model.getConfig().keySet()) {
             List<String> vals = model.getConfig().get(key);
             if (vals == null) {
@@ -1867,7 +1857,7 @@ public class RealmAdapter implements RealmModel, JpaModel<RealmEntity> {
                 config.setName(key);
                 config.setValue(val);
                 config.setComponent(c);
-                em.persist(config);
+                c.getComponentConfigs().add(config);
             }
         }
     }
@@ -1884,8 +1874,6 @@ public class RealmAdapter implements RealmModel, JpaModel<RealmEntity> {
         c.setProviderType(component.getProviderType());
         c.setParentId(component.getParentId());
         c.setSubType(component.getSubType());
-        em.createNamedQuery("deleteComponentConfigByComponent").setParameter("component", c).executeUpdate();
-        em.flush();
         setConfig(component, c);
         ComponentUtil.notifyUpdated(session, this, old, component);
 
@@ -1898,55 +1886,39 @@ public class RealmAdapter implements RealmModel, JpaModel<RealmEntity> {
         if (c == null) return;
         session.users().preRemove(this, component);
         removeComponents(component.getId());
-        em.createNamedQuery("deleteComponentConfigByComponent").setParameter("component", c).executeUpdate();
-        em.remove(c);
+        getEntity().getComponents().remove(c);
     }
 
     @Override
     public void removeComponents(String parentId) {
-        TypedQuery<String> query = em.createNamedQuery("getComponentIdsByParent", String.class)
-                .setParameter("realm", realm)
-                .setParameter("parentId", parentId);
-        List<String> results = query.getResultList();
-        if (results.isEmpty()) return;
-        for (String id : results) {
-            session.users().preRemove(this, getComponent(id));
-        }
-        em.createNamedQuery("deleteComponentConfigByParent").setParameter("parentId", parentId).executeUpdate();
-        em.createNamedQuery("deleteComponentByParent").setParameter("parentId", parentId).executeUpdate();
+        Predicate<ComponentEntity> sameParent = c -> Objects.equals(parentId, c.getParentId());
+
+        getEntity().getComponents().stream()
+                .filter(sameParent)
+                .map(this::entityToModel)
+                .forEach(c -> session.users().preRemove(this, c));
 
+        getEntity().getComponents().removeIf(sameParent);
     }
 
     @Override
-    public List<ComponentModel> getComponents(String parentId, String providerType) {
+    public List<ComponentModel> getComponents(String parentId, final String providerType) {
         if (parentId == null) parentId = getId();
-        TypedQuery<ComponentEntity> query = em.createNamedQuery("getComponentsByParentAndType", ComponentEntity.class)
-                .setParameter("realm", realm)
-                .setParameter("parentId", parentId)
-                .setParameter("providerType", providerType);
-        List<ComponentEntity> results = query.getResultList();
-        List<ComponentModel> rtn = new LinkedList<>();
-        for (ComponentEntity c : results) {
-            ComponentModel model = entityToModel(c);
-            rtn.add(model);
+        final String parent = parentId;
 
-        }
-        return rtn;
+        return realm.getComponents().stream()
+                .filter(c -> parent.equals(c.getParentId())
+                        && providerType.equals(c.getProviderType()))
+                .map(this::entityToModel)
+                .collect(Collectors.toList());
     }
 
     @Override
-    public List<ComponentModel> getComponents(String parentId) {
-        TypedQuery<ComponentEntity> query = em.createNamedQuery("getComponentsByParent", ComponentEntity.class)
-                .setParameter("realm", realm)
-                .setParameter("parentId", parentId);
-        List<ComponentEntity> results = query.getResultList();
-        List<ComponentModel> rtn = new LinkedList<>();
-        for (ComponentEntity c : results) {
-            ComponentModel model = entityToModel(c);
-            rtn.add(model);
-
-        }
-        return rtn;
+    public List<ComponentModel> getComponents(final String parentId) {
+        return realm.getComponents().stream()
+                .filter(c -> parentId.equals(c.getParentId()))
+                .map(this::entityToModel)
+                .collect(Collectors.toList());
     }
 
     protected ComponentModel entityToModel(ComponentEntity c) {
@@ -1958,10 +1930,7 @@ public class RealmAdapter implements RealmModel, JpaModel<RealmEntity> {
         model.setSubType(c.getSubType());
         model.setParentId(c.getParentId());
         MultivaluedHashMap<String, String> config = new MultivaluedHashMap<>();
-        TypedQuery<ComponentConfigEntity> configQuery = em.createNamedQuery("getComponentConfig", ComponentConfigEntity.class)
-                .setParameter("component", c);
-        List<ComponentConfigEntity> configResults = configQuery.getResultList();
-        for (ComponentConfigEntity configEntity : configResults) {
+        for (ComponentConfigEntity configEntity : c.getComponentConfigs()) {
             config.add(configEntity.getName(), configEntity.getValue());
         }
         model.setConfig(config);
@@ -1970,16 +1939,7 @@ public class RealmAdapter implements RealmModel, JpaModel<RealmEntity> {
 
     @Override
     public List<ComponentModel> getComponents() {
-        TypedQuery<ComponentEntity> query = em.createNamedQuery("getComponents", ComponentEntity.class)
-                .setParameter("realm", realm);
-        List<ComponentEntity> results = query.getResultList();
-        List<ComponentModel> rtn = new LinkedList<>();
-        for (ComponentEntity c : results) {
-            ComponentModel model = entityToModel(c);
-            rtn.add(model);
-
-        }
-        return rtn;
+        return realm.getComponents().stream().map(this::entityToModel).collect(Collectors.toList());
     }
 
     @Override
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/RoleAdapter.java b/model/jpa/src/main/java/org/keycloak/models/jpa/RoleAdapter.java
index 0f409a8..7aa1da8 100755
--- a/model/jpa/src/main/java/org/keycloak/models/jpa/RoleAdapter.java
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/RoleAdapter.java
@@ -101,7 +101,6 @@ public class RoleAdapter implements RoleModel, JpaModel<RoleEntity> {
             if (composite.equals(entity)) return;
         }
         getEntity().getCompositeRoles().add(entity);
-        em.flush();
     }
 
     @Override
diff --git a/model/jpa/src/main/resources/META-INF/persistence.xml b/model/jpa/src/main/resources/META-INF/persistence.xml
index c93a440..5d3fa81 100755
--- a/model/jpa/src/main/resources/META-INF/persistence.xml
+++ b/model/jpa/src/main/resources/META-INF/persistence.xml
@@ -37,7 +37,6 @@
         <class>org.keycloak.models.jpa.entities.UserRequiredActionEntity</class>
         <class>org.keycloak.models.jpa.entities.UserAttributeEntity</class>
         <class>org.keycloak.models.jpa.entities.UserRoleMappingEntity</class>
-        <class>org.keycloak.models.jpa.entities.ScopeMappingEntity</class>
         <class>org.keycloak.models.jpa.entities.IdentityProviderEntity</class>
         <class>org.keycloak.models.jpa.entities.IdentityProviderMapperEntity</class>
         <class>org.keycloak.models.jpa.entities.ClientIdentityProviderMappingEntity</class>
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/ComponentsTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/ComponentsTest.java
index 4634bfb..62b9cbe 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/ComponentsTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/ComponentsTest.java
@@ -17,13 +17,13 @@
 
 package org.keycloak.testsuite.admin;
 
+import org.keycloak.admin.client.resource.ComponentResource;
 import org.junit.Before;
 import org.junit.Test;
 import org.keycloak.admin.client.resource.ComponentsResource;
+import org.keycloak.admin.client.resource.RealmResource;
 import org.keycloak.common.util.MultivaluedHashMap;
-import org.keycloak.representations.idm.AdminEventRepresentation;
-import org.keycloak.representations.idm.ComponentRepresentation;
-import org.keycloak.representations.idm.ErrorRepresentation;
+import org.keycloak.representations.idm.*;
 import org.keycloak.testsuite.components.TestProvider;
 
 import javax.ws.rs.WebApplicationException;
@@ -33,6 +33,10 @@ import java.util.List;
 import java.util.Map;
 import org.apache.commons.lang3.StringUtils;
 
+import java.util.concurrent.*;
+import java.util.function.BiConsumer;
+import org.apache.commons.lang3.concurrent.BasicThreadFactory;
+import org.hamcrest.Matchers;
 import static org.junit.Assert.*;
 
 /**
@@ -47,6 +51,44 @@ public class ComponentsTest extends AbstractAdminTest {
         components = adminClient.realm(REALM_NAME).components();
     }
 
+    private volatile CountDownLatch remainingDeleteSubmissions;
+
+    private static final int NUMBER_OF_THREADS = 4;
+    private static final int NUMBER_OF_TASKS = NUMBER_OF_THREADS * 5;
+    private static final int NUMBER_OF_CHILDREN = 3;
+
+    private void testConcurrency(BiConsumer<ExecutorService, Integer> taskCreator) throws InterruptedException {
+        ExecutorService s = Executors.newFixedThreadPool(NUMBER_OF_THREADS,
+          new BasicThreadFactory.Builder().daemon(true).uncaughtExceptionHandler((t, e) -> log.error(e.getMessage(), e)).build());
+        this.remainingDeleteSubmissions = new CountDownLatch(NUMBER_OF_TASKS);
+
+        for (int i = 0; i < NUMBER_OF_TASKS; i++) {
+            taskCreator.accept(s, i);
+        }
+
+        try {
+            assertTrue("Did not create all components in time", this.remainingDeleteSubmissions.await(30, TimeUnit.SECONDS));
+            s.shutdown();
+            assertTrue("Did not finish before timeout", s.awaitTermination(30, TimeUnit.SECONDS));
+        } finally {
+            s.shutdownNow();
+        }
+    }
+
+    @Test
+    public void testConcurrencyWithoutChildren() throws InterruptedException {
+        testConcurrency((s, i) -> s.submit(new CreateAndDeleteComponent(s, i)));
+
+        assertThat(realm.components().query(realm.toRepresentation().getId(), TestProvider.class.getName()), Matchers.hasSize(0));
+    }
+
+    @Test
+    public void testConcurrencyWithChildren() throws InterruptedException {
+        testConcurrency((s, i) -> s.submit(new CreateAndDeleteComponentWithFlatChildren(s, i)));
+
+        assertThat(realm.components().query(realm.toRepresentation().getId(), TestProvider.class.getName()), Matchers.hasSize(0));
+    }
+
     @Test
     public void testNotDeadlocked() {
         for (int i = 0; i < 50; i++) {
@@ -67,7 +109,7 @@ public class ComponentsTest extends AbstractAdminTest {
         try {
             createComponent(rep);
         } catch (WebApplicationException e) {
-            assertErrror(e.getResponse(), "'Required' is required");
+            assertError(e.getResponse(), "'Required' is required");
         }
 
         rep.getConfig().putSingle("required", "Required");
@@ -77,7 +119,7 @@ public class ComponentsTest extends AbstractAdminTest {
         try {
             createComponent(rep);
         } catch (WebApplicationException e) {
-            assertErrror(e.getResponse(), "'Number' should be a number");
+            assertError(e.getResponse(), "'Number' should be a number");
         }
     }
 
@@ -259,16 +301,27 @@ public class ComponentsTest extends AbstractAdminTest {
         assertEquals(value, returned.getConfig().getFirst("val1"));
     }
 
-    private String createComponent(ComponentRepresentation rep) {
-        ComponentsResource components = realm.components();
-        Response response = components.add(rep);
-        String id = ApiUtil.getCreatedId(response);
-        getCleanup().addComponentId(id);
-        response.close();
-        return id;
+    private java.lang.String createComponent(ComponentRepresentation rep) {
+        return createComponent(realm, rep);
+    }
+
+    private String createComponent(RealmResource realm, ComponentRepresentation rep) {
+        Response response = null;
+        try {
+            ComponentsResource components = realm.components();
+            response = components.add(rep);
+            String id = ApiUtil.getCreatedId(response);
+            getCleanup(realm.toRepresentation().getRealm()).addComponentId(id);
+            return id;
+        } finally {
+            if (response != null) {
+                response.bufferEntity();
+                response.close();
+            }
+        }
     }
 
-    private void assertErrror(Response response, String error) {
+    private void assertError(Response response, String error) {
         if (!response.hasEntity()) {
             fail("No error message set");
         }
@@ -290,4 +343,119 @@ public class ComponentsTest extends AbstractAdminTest {
         return rep;
     }
 
+    private class CreateComponent implements Runnable {
+
+        protected final ExecutorService s;
+        protected final int i;
+        protected final RealmResource realm;
+
+        public CreateComponent(ExecutorService s, int i, RealmResource realm) {
+            this.s = s;
+            this.i = i;
+            this.realm = realm;
+        }
+
+        public CreateComponent(ExecutorService s, int i) {
+            this(s, i, ComponentsTest.this.realm);
+        }
+
+        @Override
+        public void run() {
+            log.debugf("Started for i=%d ", i);
+            ComponentRepresentation rep = createComponentRepresentation("test-" + i);
+            rep.getConfig().putSingle("required", "required-value");
+            rep.setParentId(this.realm.toRepresentation().getId());
+            
+            String id = createComponent(this.realm, rep);
+            assertThat(id, Matchers.notNullValue());
+
+            createChildren(id);
+
+            log.debugf("Finished: i=%d, id=%s", i, id);
+
+            scheduleDeleteComponent(id);
+            remainingDeleteSubmissions.countDown();
+        }
+
+        protected void scheduleDeleteComponent(String id) {
+        }
+
+        protected void createChildren(String id) {
+        }
+    }
+
+    private class CreateAndDeleteComponent extends CreateComponent {
+
+        public CreateAndDeleteComponent(ExecutorService s, int i) {
+            super(s, i);
+        }
+
+        @Override
+        protected void scheduleDeleteComponent(String id) {
+            s.submit(new DeleteComponent(id));
+        }
+    }
+
+    private class CreateComponentWithFlatChildren extends CreateComponent {
+
+        public CreateComponentWithFlatChildren(ExecutorService s, int i, RealmResource realm) {
+            super(s, i, realm);
+        }
+
+        public CreateComponentWithFlatChildren(ExecutorService s, int i) {
+            super(s, i);
+        }
+
+        @Override
+        protected void createChildren(String id) {
+            for (int j = 0; j < NUMBER_OF_CHILDREN; j ++) {
+                ComponentRepresentation rep = createComponentRepresentation("test-" + i + ":" + j);
+                rep.setParentId(id);
+                rep.getConfig().putSingle("required", "required-value");
+
+                assertThat(createComponent(this.realm, rep), Matchers.notNullValue());
+            }
+        }
+
+    }
+
+    private class CreateAndDeleteComponentWithFlatChildren extends CreateAndDeleteComponent {
+
+        public CreateAndDeleteComponentWithFlatChildren(ExecutorService s, int i) {
+            super(s, i);
+        }
+
+        @Override
+        protected void createChildren(String id) {
+            for (int j = 0; j < NUMBER_OF_CHILDREN; j ++) {
+                ComponentRepresentation rep = createComponentRepresentation("test-" + i + ":" + j);
+                rep.setParentId(id);
+                rep.getConfig().putSingle("required", "required-value");
+
+                assertThat(createComponent(this.realm, rep), Matchers.notNullValue());
+            }
+        }
+
+    }
+
+    private class DeleteComponent implements Runnable {
+
+        private final String id;
+
+        public DeleteComponent(String id) {
+            this.id = id;
+        }
+
+        @Override
+        public void run() {
+            log.debugf("Started, id=%s", id);
+
+            ComponentResource c = realm.components().component(id);
+            assertThat(c.toRepresentation(), Matchers.notNullValue());
+            c.remove();
+
+            log.debugf("Finished, id=%s", id);
+        }
+    }
+
 }