You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@syncope.apache.org by il...@apache.org on 2019/10/10 08:22:25 UTC

[syncope] 01/02: [SYNCOPE-1502]: find anytos in single query

This is an automated email from the ASF dual-hosted git repository.

ilgrosso pushed a commit to branch 2_1_X
in repository https://gitbox.apache.org/repos/asf/syncope.git

commit 10027bbcda7388dcac778eb931b2e26836d6de2c
Author: Dmitriy Brashevets <dm...@united-security-providers.ch>
AuthorDate: Wed Oct 9 12:25:39 2019 +0300

    [SYNCOPE-1502]: find anytos in single query
    
    - AnyTO objects are searched by keys retrieved from the search view using a single SQL query that contains IN condition
    - replacement of multiple OR-realm condition in the resulted SQL query that is executed to search entities in search views with IN clause.
---
 .../syncope/core/persistence/api/dao/AnyDAO.java   |  2 +
 .../core/persistence/jpa/dao/AbstractAnyDAO.java   | 12 ++++++
 .../persistence/jpa/dao/AbstractAnySearchDAO.java  | 45 +++++++++++++---------
 .../core/persistence/jpa/dao/JPAAnySearchDAO.java  | 26 ++++++-------
 4 files changed, 53 insertions(+), 32 deletions(-)

diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/AnyDAO.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/AnyDAO.java
index 787f1cb..fb888eb 100644
--- a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/AnyDAO.java
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/AnyDAO.java
@@ -37,6 +37,8 @@ public interface AnyDAO<A extends Any<?>> extends DAO<A> {
 
     String findKey(String name);
 
+    List<A> findByKeys(List<String> keys);
+
     Date findLastChange(String key);
 
     A authFind(String key);
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/AbstractAnyDAO.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/AbstractAnyDAO.java
index 76761f1..90ed53f 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/AbstractAnyDAO.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/AbstractAnyDAO.java
@@ -32,6 +32,8 @@ import java.util.Set;
 import java.util.regex.Pattern;
 import javax.persistence.Query;
 import javax.persistence.TemporalType;
+import javax.persistence.TypedQuery;
+
 import org.apache.commons.jexl3.parser.Parser;
 import org.apache.commons.jexl3.parser.ParserConstants;
 import org.apache.commons.jexl3.parser.Token;
@@ -153,6 +155,16 @@ public abstract class AbstractAnyDAO<A extends Any<?>> extends AbstractDAO<A> im
 
     @Transactional(readOnly = true)
     @Override
+    public List<A> findByKeys(List<String> keys) {
+        Class<A> entityClass = anyUtils().anyClass();
+        TypedQuery<A> query = entityManager()
+                .createQuery("SELECT e FROM " + entityClass.getSimpleName() + " e WHERE e.id IN (:keys)", entityClass);
+        query.setParameter("keys", keys);
+        return query.getResultList();
+    }
+
+    @Transactional(readOnly = true)
+    @Override
     public A authFind(final String key) {
         if (key == null) {
             throw new NotFoundException("Null key");
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/AbstractAnySearchDAO.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/AbstractAnySearchDAO.java
index cc17e32..4cebca7 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/AbstractAnySearchDAO.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/AbstractAnySearchDAO.java
@@ -21,8 +21,12 @@ package org.apache.syncope.core.persistence.jpa.dao;
 import java.lang.annotation.Annotation;
 import java.lang.reflect.Field;
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Collections;
+import java.util.LinkedHashSet;
 import java.util.List;
+import java.util.Map;
+import java.util.Objects;
 import java.util.Set;
 import java.util.stream.Collectors;
 import javax.validation.ValidationException;
@@ -297,26 +301,31 @@ public abstract class AbstractAnySearchDAO extends AbstractDAO<Any<?>> implement
     }
 
     protected <T extends Any<?>> List<T> buildResult(final List<Object> raw, final AnyTypeKind kind) {
-        List<T> result = new ArrayList<>();
+        List<String> orderedAnyKeys = extractSortedAnyKeys(raw);
+        return constructSortedAnyTOsBySortedKeys(findAnyTOs(kind, orderedAnyKeys), orderedAnyKeys, kind);
+    }
 
-        raw.stream().map(anyKey -> anyKey instanceof Object[]
+    private List<String> extractSortedAnyKeys(List<Object> raw) {
+        return raw.stream().map(anyKey -> anyKey instanceof Object[]
                 ? (String) ((Object[]) anyKey)[0]
-                : ((String) anyKey)).
-                forEachOrdered(actualKey -> {
-                    @SuppressWarnings("unchecked")
-                    T any = kind == AnyTypeKind.USER
-                            ? (T) userDAO.find(actualKey)
-                            : kind == AnyTypeKind.GROUP
-                                    ? (T) groupDAO.find(actualKey)
-                                    : (T) anyObjectDAO.find(actualKey);
-                    if (any == null) {
-                        LOG.error("Could not find {} with id {}, even if returned by native query", kind, actualKey);
-                    } else if (!result.contains(any)) {
-                        result.add(any);
-                    }
-                });
-
-        return result;
+                : ((String) anyKey))
+                .collect(Collectors.toList());
+    }
+
+    @SuppressWarnings("unchecked")
+    private <T extends Any<?>> List<T> findAnyTOs(AnyTypeKind kind, List<String> orderedAnyKeys) {
+        return new ArrayList<>((List<T>)anyUtilsFactory.getInstance(kind).dao().findByKeys(orderedAnyKeys));
+    }
+
+    private <T extends Any<?>> List<T> constructSortedAnyTOsBySortedKeys(List<T> anyTOs,
+            List<String> sortedAnyKeys, AnyTypeKind kind) {
+        Map<String, T> anyMap = anyTOs.stream().collect(Collectors.toMap(T::getKey, anyTO -> anyTO));
+        return sortedAnyKeys.stream().map(key -> {
+            if (anyMap.get(key) == null) {
+                LOG.error("Could not find {} with id {}, even if returned by native query", kind, key);
+            }
+            return anyMap.get(key);
+        }).filter(Objects::nonNull).collect(Collectors.toList());
     }
 
     @Override
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAnySearchDAO.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAnySearchDAO.java
index 3e0ccf2..29fc8e4 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAnySearchDAO.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAnySearchDAO.java
@@ -97,24 +97,22 @@ public class JPAAnySearchDAO extends AbstractAnySearchDAO {
                     map(Entity::getKey).collect(Collectors.toSet()));
         }
 
+        List<String> realmKeyArgs = getRealmKeySqlArgsAndFillParameters(parameters, realmKeys);
+
         StringBuilder adminRealmFilter = new StringBuilder("u.any_id IN (").
-                append("SELECT any_id FROM ").append(svs.field().name).
-                append(" WHERE realm_id IN (SELECT id AS realm_id FROM Realm");
+                append("SELECT any_id FROM ").append(svs.field().name)
+                .append(" WHERE realm_id IN (")
+                .append(StringUtils.join(realmKeyArgs, ", "))
+                .append("))");
+        return Pair.of(adminRealmFilter.toString(), dynRealmKeys);
+    }
 
-        boolean firstRealm = true;
+    private List<String> getRealmKeySqlArgsAndFillParameters(List<Object> parameters, Set<String> realmKeys) {
+        List<String> realmKeyArgs = new ArrayList<>();
         for (String realmKey : realmKeys) {
-            if (firstRealm) {
-                adminRealmFilter.append(" WHERE");
-                firstRealm = false;
-            } else {
-                adminRealmFilter.append(" OR");
-            }
-            adminRealmFilter.append(" id=?").append(setParameter(parameters, realmKey));
+            realmKeyArgs.add("?" + setParameter(parameters, realmKey));
         }
-
-        adminRealmFilter.append("))");
-
-        return Pair.of(adminRealmFilter.toString(), dynRealmKeys);
+        return realmKeyArgs;
     }
 
     SearchSupport buildSearchSupport(final AnyTypeKind kind) {