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 2016/12/22 08:28:07 UTC

[1/2] syncope git commit: [SYNCOPE-983] Improving search performance by skipping unnecessary checks for mandatory schemas

Repository: syncope
Updated Branches:
  refs/heads/2_0_X 5a6173bb7 -> 8b5285e18
  refs/heads/master 18ac4512c -> 941dc06a3


[SYNCOPE-983] Improving search performance by skipping unnecessary checks for mandatory schemas


Project: http://git-wip-us.apache.org/repos/asf/syncope/repo
Commit: http://git-wip-us.apache.org/repos/asf/syncope/commit/8b5285e1
Tree: http://git-wip-us.apache.org/repos/asf/syncope/tree/8b5285e1
Diff: http://git-wip-us.apache.org/repos/asf/syncope/diff/8b5285e1

Branch: refs/heads/2_0_X
Commit: 8b5285e1863a21b64172d24ce4ffa804545f3541
Parents: 5a6173b
Author: Francesco Chicchiricc� <il...@apache.org>
Authored: Thu Dec 22 09:27:41 2016 +0100
Committer: Francesco Chicchiricc� <il...@apache.org>
Committed: Thu Dec 22 09:27:41 2016 +0100

----------------------------------------------------------------------
 .../core/persistence/api/dao/AnySearchDAO.java  |   3 +-
 .../persistence/jpa/dao/JPAAnySearchDAO.java    | 170 ++++++++++---------
 .../core/persistence/jpa/dao/JPAGroupDAO.java   |   6 +-
 .../core/persistence/jpa/dao/JPARoleDAO.java    |   4 +-
 .../persistence/jpa/dao/OrderBySupport.java     |   2 +
 .../core/persistence/jpa/dao/SearchSupport.java |   8 +-
 .../persistence/jpa/inner/AnySearchTest.java    |  42 ++++-
 .../notification/NotificationManagerImpl.java   |   7 +-
 .../apache/syncope/fit/core/RealmITCase.java    |   2 +-
 .../apache/syncope/fit/core/SearchITCase.java   |  11 ++
 10 files changed, 150 insertions(+), 105 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/syncope/blob/8b5285e1/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/AnySearchDAO.java
----------------------------------------------------------------------
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/AnySearchDAO.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/AnySearchDAO.java
index b93ca49..fe5b572 100644
--- a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/AnySearchDAO.java
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/AnySearchDAO.java
@@ -79,9 +79,8 @@ public interface AnySearchDAO extends DAO<Any<?>> {
      *
      * @param any to be checked
      * @param searchCondition to be verified
-     * @param kind any object
      * @param <T> any
      * @return true if any matches searchCondition
      */
-    <T extends Any<?>> boolean matches(T any, SearchCond searchCondition, AnyTypeKind kind);
+    <T extends Any<?>> boolean matches(T any, SearchCond searchCondition);
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/8b5285e1/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAnySearchDAO.java
----------------------------------------------------------------------
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 9554f9a..49bf4ff 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
@@ -114,7 +114,7 @@ public class JPAAnySearchDAO extends AbstractDAO<Any<?>> implements AnySearchDAO
             }
         }
 
-        StringBuilder adminRealmFilter = new StringBuilder().
+        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");
 
@@ -129,7 +129,7 @@ public class JPAAnySearchDAO extends AbstractDAO<Any<?>> implements AnySearchDAO
             adminRealmFilter.append(" id=?").append(setParameter(parameters, realmKey));
         }
 
-        adminRealmFilter.append(')');
+        adminRealmFilter.append("))");
 
         return adminRealmFilter.toString();
     }
@@ -144,8 +144,7 @@ public class JPAAnySearchDAO extends AbstractDAO<Any<?>> implements AnySearchDAO
 
         // 2. take into account administrative realms
         queryString.insert(0, "SELECT u.any_id FROM (");
-        queryString.append(") u WHERE any_id IN (");
-        queryString.append(getAdminRealmsFilter(adminRealms, svs, parameters)).append(')');
+        queryString.append(") u WHERE ").append(getAdminRealmsFilter(adminRealms, svs, parameters));
 
         // 3. prepare the COUNT query
         queryString.insert(0, "SELECT COUNT(any_id) FROM (");
@@ -202,13 +201,11 @@ public class JPAAnySearchDAO extends AbstractDAO<Any<?>> implements AnySearchDAO
     }
 
     @Override
-    public <T extends Any<?>> boolean matches(
-            final T any, final SearchCond cond, final AnyTypeKind typeKind) {
-
+    public <T extends Any<?>> boolean matches(final T any, final SearchCond cond) {
         List<Object> parameters = Collections.synchronizedList(new ArrayList<>());
 
         // 1. get the query string from the search condition
-        SearchSupport svs = new SearchSupport(typeKind);
+        SearchSupport svs = new SearchSupport(any.getType().getKind());
         StringBuilder queryString = getQuery(cond, parameters, svs);
 
         boolean matches;
@@ -257,52 +254,55 @@ public class JPAAnySearchDAO extends AbstractDAO<Any<?>> implements AnySearchDAO
         }
     }
 
-    private StringBuilder buildSelect(final OrderBySupport orderBySupport) {
+    private StringBuilder buildSelect(final OrderBySupport obs) {
         final StringBuilder select = new StringBuilder("SELECT u.any_id");
 
-        for (OrderBySupport.Item obs : orderBySupport.items) {
-            select.append(',').append(obs.select);
+        for (OrderBySupport.Item item : obs.items) {
+            select.append(',').append(item.select);
         }
         select.append(" FROM ");
 
         return select;
     }
 
-    private StringBuilder buildWhere(final OrderBySupport orderBySupport, final AnyTypeKind typeKind) {
-        SearchSupport svs = new SearchSupport(typeKind);
+    private StringBuilder buildWhere(final SearchSupport svs, final OrderBySupport obs) {
         StringBuilder where = new StringBuilder(" u");
-        for (SearchSupport.SearchView searchView : orderBySupport.views) {
+        for (SearchSupport.SearchView searchView : obs.views) {
             where.append(',');
             if (searchView.name.equals(svs.attr().name)) {
-                where.append(" (SELECT * FROM ").append(searchView.name).append(" UNION ").
-                        append("SELECT * FROM ").append(svs.nullAttr().name).append(')');
+                where.append(" (SELECT * FROM ").append(searchView.name);
+
+                if (svs.nonMandatorySchemas || obs.nonMandatorySchemas) {
+                    where.append(" UNION SELECT * FROM ").append(svs.nullAttr().name);
+                }
+
+                where.append(')');
             } else {
                 where.append(searchView.name);
             }
             where.append(' ').append(searchView.alias);
         }
         where.append(" WHERE ");
-        for (SearchSupport.SearchView searchView : orderBySupport.views) {
+        for (SearchSupport.SearchView searchView : obs.views) {
             where.append("u.any_id=").append(searchView.alias).append(".any_id AND ");
         }
 
-        for (OrderBySupport.Item obs : orderBySupport.items) {
-            if (StringUtils.isNotBlank(obs.where)) {
-                where.append(obs.where).append(" AND ");
+        for (OrderBySupport.Item item : obs.items) {
+            if (StringUtils.isNotBlank(item.where)) {
+                where.append(item.where).append(" AND ");
             }
         }
-        where.append("u.any_id IN (");
 
         return where;
     }
 
-    private StringBuilder buildOrderBy(final OrderBySupport orderBySupport) {
+    private StringBuilder buildOrderBy(final OrderBySupport obs) {
         StringBuilder orderBy = new StringBuilder();
 
-        for (OrderBySupport.Item obs : orderBySupport.items) {
-            orderBy.append(obs.orderBy).append(',');
+        for (OrderBySupport.Item item : obs.items) {
+            orderBy.append(item.orderBy).append(',');
         }
-        if (!orderBySupport.items.isEmpty()) {
+        if (!obs.items.isEmpty()) {
             orderBy.insert(0, " ORDER BY ");
             orderBy.deleteCharAt(orderBy.length() - 1);
         }
@@ -315,10 +315,10 @@ public class JPAAnySearchDAO extends AbstractDAO<Any<?>> implements AnySearchDAO
 
         final AnyUtils attrUtils = anyUtilsFactory.getInstance(type);
 
-        OrderBySupport orderBySupport = new OrderBySupport();
+        OrderBySupport obs = new OrderBySupport();
 
         for (OrderByClause clause : orderByClauses) {
-            OrderBySupport.Item obs = new OrderBySupport.Item();
+            OrderBySupport.Item item = new OrderBySupport.Item();
 
             // Manage difference among external key attribute and internal JPA @Id
             String fieldName = "key".equals(clause.getField()) ? "id" : clause.getField();
@@ -327,44 +327,47 @@ public class JPAAnySearchDAO extends AbstractDAO<Any<?>> implements AnySearchDAO
             if (anyField == null) {
                 PlainSchema schema = schemaDAO.find(fieldName);
                 if (schema != null) {
+                    // keep track of involvement of non-mandatory schemas in the order by clauses
+                    obs.nonMandatorySchemas = !"true".equals(schema.getMandatoryCondition());
+
                     if (schema.isUniqueConstraint()) {
-                        orderBySupport.views.add(svs.uniqueAttr());
+                        obs.views.add(svs.uniqueAttr());
 
-                        obs.select = new StringBuilder().
+                        item.select = new StringBuilder().
                                 append(svs.uniqueAttr().alias).append('.').append(svs.fieldName(schema.getType())).
                                 append(" AS ").append(fieldName).toString();
-                        obs.where = new StringBuilder().
+                        item.where = new StringBuilder().
                                 append(svs.uniqueAttr().alias).
                                 append(".schema_id='").append(fieldName).append("'").toString();
-                        obs.orderBy = fieldName + " " + clause.getDirection().name();
+                        item.orderBy = fieldName + " " + clause.getDirection().name();
                     } else {
-                        orderBySupport.views.add(svs.attr());
+                        obs.views.add(svs.attr());
 
-                        obs.select = new StringBuilder().
+                        item.select = new StringBuilder().
                                 append(svs.attr().alias).append('.').append(svs.fieldName(schema.getType())).
                                 append(" AS ").append(fieldName).toString();
-                        obs.where = new StringBuilder().
+                        item.where = new StringBuilder().
                                 append(svs.attr().alias).
                                 append(".schema_id='").append(fieldName).append("'").toString();
-                        obs.orderBy = fieldName + " " + clause.getDirection().name();
+                        item.orderBy = fieldName + " " + clause.getDirection().name();
                     }
                 }
             } else {
-                orderBySupport.views.add(svs.field());
+                obs.views.add(svs.field());
 
-                obs.select = svs.field().alias + "." + fieldName;
-                obs.where = StringUtils.EMPTY;
-                obs.orderBy = svs.field().alias + "." + fieldName + " " + clause.getDirection().name();
+                item.select = svs.field().alias + "." + fieldName;
+                item.where = StringUtils.EMPTY;
+                item.orderBy = svs.field().alias + "." + fieldName + " " + clause.getDirection().name();
             }
 
-            if (obs.isEmpty()) {
+            if (item.isEmpty()) {
                 LOG.warn("Cannot build any valid clause from {}", clause);
             } else {
-                orderBySupport.items.add(obs);
+                obs.items.add(item);
             }
         }
 
-        return orderBySupport;
+        return obs;
     }
 
     @SuppressWarnings("unchecked")
@@ -379,17 +382,17 @@ public class JPAAnySearchDAO extends AbstractDAO<Any<?>> implements AnySearchDAO
         StringBuilder queryString = getQuery(cond, parameters, svs);
 
         // 2. take into account administrative groups and ordering
-        OrderBySupport orderBySupport = parseOrderBy(typeKind, svs, orderBy);
+        OrderBySupport obs = parseOrderBy(typeKind, svs, orderBy);
         if (queryString.charAt(0) == '(') {
-            queryString.insert(0, buildSelect(orderBySupport));
-            queryString.append(buildWhere(orderBySupport, typeKind));
+            queryString.insert(0, buildSelect(obs));
+            queryString.append(buildWhere(svs, obs));
         } else {
-            queryString.insert(0, buildSelect(orderBySupport).append('('));
-            queryString.append(')').append(buildWhere(orderBySupport, typeKind));
+            queryString.insert(0, buildSelect(obs).append('('));
+            queryString.append(')').append(buildWhere(svs, obs));
         }
         queryString.
-                append(getAdminRealmsFilter(adminRealms, svs, parameters)).append(')').
-                append(buildOrderBy(orderBySupport));
+                append(getAdminRealmsFilter(adminRealms, svs, parameters)).
+                append(buildOrderBy(obs));
 
         // 3. prepare the search query
         Query query = entityManager().createNativeQuery(queryString.toString());
@@ -434,30 +437,30 @@ public class JPAAnySearchDAO extends AbstractDAO<Any<?>> implements AnySearchDAO
         switch (cond.getType()) {
             case LEAF:
             case NOT_LEAF:
-                if (cond.getAnyTypeCond() != null && AnyTypeKind.ANY_OBJECT == svs.anyTypeKind()) {
+                if (cond.getAnyTypeCond() != null && AnyTypeKind.ANY_OBJECT == svs.anyTypeKind) {
                     query.append(getQuery(cond.getAnyTypeCond(),
                             cond.getType() == SearchCond.Type.NOT_LEAF, parameters, svs));
                 } else if (cond.getRelationshipTypeCond() != null
-                        && (AnyTypeKind.USER == svs.anyTypeKind() || AnyTypeKind.ANY_OBJECT == svs.anyTypeKind())) {
+                        && (AnyTypeKind.USER == svs.anyTypeKind || AnyTypeKind.ANY_OBJECT == svs.anyTypeKind)) {
 
                     query.append(getQuery(cond.getRelationshipTypeCond(),
                             cond.getType() == SearchCond.Type.NOT_LEAF, parameters, svs));
                 } else if (cond.getRelationshipCond() != null
-                        && (AnyTypeKind.USER == svs.anyTypeKind() || AnyTypeKind.ANY_OBJECT == svs.anyTypeKind())) {
+                        && (AnyTypeKind.USER == svs.anyTypeKind || AnyTypeKind.ANY_OBJECT == svs.anyTypeKind)) {
 
                     query.append(getQuery(cond.getRelationshipCond(),
                             cond.getType() == SearchCond.Type.NOT_LEAF, parameters, svs));
                 } else if (cond.getMembershipCond() != null
-                        && (AnyTypeKind.USER == svs.anyTypeKind() || AnyTypeKind.ANY_OBJECT == svs.anyTypeKind())) {
+                        && (AnyTypeKind.USER == svs.anyTypeKind || AnyTypeKind.ANY_OBJECT == svs.anyTypeKind)) {
 
                     query.append(getQuery(cond.getMembershipCond(),
                             cond.getType() == SearchCond.Type.NOT_LEAF, parameters, svs));
                 } else if (cond.getAssignableCond() != null) {
                     query.append(getQuery(cond.getAssignableCond(), parameters, svs));
-                } else if (cond.getRoleCond() != null && AnyTypeKind.USER == svs.anyTypeKind()) {
+                } else if (cond.getRoleCond() != null && AnyTypeKind.USER == svs.anyTypeKind) {
                     query.append(getQuery(cond.getRoleCond(),
                             cond.getType() == SearchCond.Type.NOT_LEAF, parameters, svs));
-                } else if (cond.getMemberCond() != null && AnyTypeKind.GROUP == svs.anyTypeKind()) {
+                } else if (cond.getMemberCond() != null && AnyTypeKind.GROUP == svs.anyTypeKind) {
                     query.append(getQuery(cond.getMemberCond(),
                             cond.getType() == SearchCond.Type.NOT_LEAF, parameters, svs));
                 } else if (cond.getResourceCond() != null) {
@@ -498,8 +501,8 @@ public class JPAAnySearchDAO extends AbstractDAO<Any<?>> implements AnySearchDAO
         return query;
     }
 
-    private String getQuery(final AnyTypeCond cond, final boolean not, final List<Object> parameters,
-            final SearchSupport svs) {
+    private String getQuery(
+            final AnyTypeCond cond, final boolean not, final List<Object> parameters, final SearchSupport svs) {
 
         StringBuilder query = new StringBuilder("SELECT DISTINCT any_id FROM ").
                 append(svs.field().name).append(" WHERE type_id");
@@ -515,7 +518,10 @@ public class JPAAnySearchDAO extends AbstractDAO<Any<?>> implements AnySearchDAO
         return query.toString();
     }
 
-    private String getQuery(final RelationshipTypeCond cond, final boolean not, final List<Object> parameters,
+    private String getQuery(
+            final RelationshipTypeCond cond,
+            final boolean not,
+            final List<Object> parameters,
             final SearchSupport svs) {
 
         StringBuilder query = new StringBuilder("SELECT DISTINCT any_id FROM ").
@@ -538,8 +544,8 @@ public class JPAAnySearchDAO extends AbstractDAO<Any<?>> implements AnySearchDAO
         return query.toString();
     }
 
-    private String getQuery(final RelationshipCond cond, final boolean not, final List<Object> parameters,
-            final SearchSupport svs) {
+    private String getQuery(
+            final RelationshipCond cond, final boolean not, final List<Object> parameters, final SearchSupport svs) {
 
         String rightAnyObjectKey;
         if (SyncopeConstants.UUID_PATTERN.matcher(cond.getAnyObject()).matches()) {
@@ -569,8 +575,8 @@ public class JPAAnySearchDAO extends AbstractDAO<Any<?>> implements AnySearchDAO
         return query.toString();
     }
 
-    private String getQuery(final MembershipCond cond, final boolean not, final List<Object> parameters,
-            final SearchSupport svs) {
+    private String getQuery(
+            final MembershipCond cond, final boolean not, final List<Object> parameters, final SearchSupport svs) {
 
         String groupKey;
         if (SyncopeConstants.UUID_PATTERN.matcher(cond.getGroup()).matches()) {
@@ -611,8 +617,8 @@ public class JPAAnySearchDAO extends AbstractDAO<Any<?>> implements AnySearchDAO
         return query.toString();
     }
 
-    private String getQuery(final RoleCond cond, final boolean not, final List<Object> parameters,
-            final SearchSupport svs) {
+    private String getQuery(
+            final RoleCond cond, final boolean not, final List<Object> parameters, final SearchSupport svs) {
 
         StringBuilder query = new StringBuilder("SELECT DISTINCT any_id FROM ").
                 append(svs.field().name).append(" WHERE (");
@@ -642,8 +648,8 @@ public class JPAAnySearchDAO extends AbstractDAO<Any<?>> implements AnySearchDAO
         return query.toString();
     }
 
-    private String getQuery(final ResourceCond cond, final boolean not, final List<Object> parameters,
-            final SearchSupport svs) {
+    private String getQuery(
+            final ResourceCond cond, final boolean not, final List<Object> parameters, final SearchSupport svs) {
 
         StringBuilder query = new StringBuilder("SELECT DISTINCT any_id FROM ").
                 append(svs.field().name).append(" WHERE ");
@@ -659,7 +665,7 @@ public class JPAAnySearchDAO extends AbstractDAO<Any<?>> implements AnySearchDAO
                 append(" WHERE resource_id=?").
                 append(setParameter(parameters, cond.getResourceKey()));
 
-        if (svs.anyTypeKind() == AnyTypeKind.USER) {
+        if (svs.anyTypeKind == AnyTypeKind.USER) {
             query.append(" UNION SELECT DISTINCT any_id FROM ").
                     append(svs.groupResource().name).
                     append(" WHERE resource_id=?").
@@ -695,8 +701,8 @@ public class JPAAnySearchDAO extends AbstractDAO<Any<?>> implements AnySearchDAO
         return query.toString();
     }
 
-    private String getQuery(final MemberCond cond, final boolean not, final List<Object> parameters,
-            final SearchSupport svs) {
+    private String getQuery(
+            final MemberCond cond, final boolean not, final List<Object> parameters, final SearchSupport svs) {
 
         String memberKey;
         if (SyncopeConstants.UUID_PATTERN.matcher(cond.getMember()).matches()) {
@@ -740,9 +746,14 @@ public class JPAAnySearchDAO extends AbstractDAO<Any<?>> implements AnySearchDAO
         return query.toString();
     }
 
-    private void fillAttributeQuery(final StringBuilder query, final PlainAttrValue attrValue,
-            final PlainSchema schema, final AttributeCond cond, final boolean not,
-            final List<Object> parameters, final SearchSupport svs) {
+    private void fillAttributeQuery(
+            final StringBuilder query,
+            final PlainAttrValue attrValue,
+            final PlainSchema schema,
+            final AttributeCond cond,
+            final boolean not,
+            final List<Object> parameters,
+            final SearchSupport svs) {
 
         // activate ignoreCase only for EQ and LIKE operators
         boolean ignoreCase = AttributeCond.Type.ILIKE == cond.getType() || AttributeCond.Type.IEQ == cond.getType();
@@ -850,10 +861,10 @@ public class JPAAnySearchDAO extends AbstractDAO<Any<?>> implements AnySearchDAO
         }
     }
 
-    private String getQuery(final AttributeCond cond, final boolean not, final List<Object> parameters,
-            final SearchSupport svs) {
+    private String getQuery(
+            final AttributeCond cond, final boolean not, final List<Object> parameters, final SearchSupport svs) {
 
-        AnyUtils attrUtils = anyUtilsFactory.getInstance(svs.anyTypeKind());
+        AnyUtils attrUtils = anyUtilsFactory.getInstance(svs.anyTypeKind);
 
         PlainSchema schema = schemaDAO.find(cond.getSchema());
         if (schema == null) {
@@ -861,6 +872,9 @@ public class JPAAnySearchDAO extends AbstractDAO<Any<?>> implements AnySearchDAO
             return EMPTY_QUERY;
         }
 
+        // keep track of involvement of non-mandatory schemas in the search condition
+        svs.nonMandatorySchemas = !"true".equals(schema.getMandatoryCondition());
+
         PlainAttrValue attrValue = attrUtils.newPlainAttrValue();
         try {
             if (cond.getType() != AttributeCond.Type.LIKE
@@ -902,12 +916,12 @@ public class JPAAnySearchDAO extends AbstractDAO<Any<?>> implements AnySearchDAO
         return query.toString();
     }
 
-    private String getQuery(final AnyCond cond, final boolean not, final List<Object> parameters,
-            final SearchSupport svs) {
+    private String getQuery(
+            final AnyCond cond, final boolean not, final List<Object> parameters, final SearchSupport svs) {
 
         AnyCond condClone = SerializationUtils.clone(cond);
 
-        AnyUtils attrUtils = anyUtilsFactory.getInstance(svs.anyTypeKind());
+        AnyUtils attrUtils = anyUtilsFactory.getInstance(svs.anyTypeKind);
 
         // Keeps track of difference between entity's getKey() and JPA @Id fields
         if ("key".equals(condClone.getSchema())) {

http://git-wip-us.apache.org/repos/asf/syncope/blob/8b5285e1/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAGroupDAO.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAGroupDAO.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAGroupDAO.java
index 1785672..0bcdee2 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAGroupDAO.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAGroupDAO.java
@@ -290,8 +290,7 @@ public class JPAGroupDAO extends AbstractAnyDAO<Group> implements GroupDAO {
             for (ADynGroupMembership memb : group.getADynMemberships()) {
                 if (searchDAO.matches(
                         anyObject,
-                        buildDynMembershipCond(memb.getFIQLCond(), group.getRealm()),
-                        AnyTypeKind.ANY_OBJECT)) {
+                        buildDynMembershipCond(memb.getFIQLCond(), group.getRealm()))) {
 
                     memb.add(anyObject);
                 } else {
@@ -308,8 +307,7 @@ public class JPAGroupDAO extends AbstractAnyDAO<Group> implements GroupDAO {
             if (group.getUDynMembership() != null) {
                 if (searchDAO.matches(
                         user,
-                        buildDynMembershipCond(group.getUDynMembership().getFIQLCond(), group.getRealm()),
-                        AnyTypeKind.USER)) {
+                        buildDynMembershipCond(group.getUDynMembership().getFIQLCond(), group.getRealm()))) {
 
                     group.getUDynMembership().add(user);
                 } else {

http://git-wip-us.apache.org/repos/asf/syncope/blob/8b5285e1/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPARoleDAO.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPARoleDAO.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPARoleDAO.java
index fc91712..b636fc6 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPARoleDAO.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPARoleDAO.java
@@ -111,9 +111,7 @@ public class JPARoleDAO extends AbstractDAO<Role> implements RoleDAO {
     public void refreshDynMemberships(final User user) {
         for (Role role : findAll()) {
             if (role.getDynMembership() != null) {
-                if (searchDAO.matches(user,
-                        SearchCondConverter.convert(role.getDynMembership().getFIQLCond()), AnyTypeKind.USER)) {
-
+                if (searchDAO.matches(user, SearchCondConverter.convert(role.getDynMembership().getFIQLCond()))) {
                     role.getDynMembership().add(user);
                 } else {
                     role.getDynMembership().getMembers().remove(user);

http://git-wip-us.apache.org/repos/asf/syncope/blob/8b5285e1/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/OrderBySupport.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/OrderBySupport.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/OrderBySupport.java
index 63f442e..ec87f5b 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/OrderBySupport.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/OrderBySupport.java
@@ -44,4 +44,6 @@ class OrderBySupport {
 
     protected List<Item> items = new ArrayList<>();
 
+    protected boolean nonMandatorySchemas = false;
+
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/8b5285e1/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/SearchSupport.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/SearchSupport.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/SearchSupport.java
index 06854df..9964d89 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/SearchSupport.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/SearchSupport.java
@@ -47,16 +47,14 @@ class SearchSupport {
         }
     }
 
-    private final AnyTypeKind anyTypeKind;
+    protected final AnyTypeKind anyTypeKind;
+
+    protected boolean nonMandatorySchemas = false;
 
     SearchSupport(final AnyTypeKind anyTypeKind) {
         this.anyTypeKind = anyTypeKind;
     }
 
-    public AnyTypeKind anyTypeKind() {
-        return anyTypeKind;
-    }
-
     public String fieldName(final AttrSchemaType attrSchemaType) {
         String result;
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/8b5285e1/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/AnySearchTest.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/AnySearchTest.java b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/AnySearchTest.java
index 429dfb5..c7e5c62 100644
--- a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/AnySearchTest.java
+++ b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/AnySearchTest.java
@@ -89,11 +89,11 @@ public class AnySearchTest extends AbstractTest {
 
         RelationshipCond relationshipCond = new RelationshipCond();
         relationshipCond.setAnyObject("Canon MF 8030cn");
-        assertTrue(searchDAO.matches(anyObject, SearchCond.getLeafCond(relationshipCond), AnyTypeKind.ANY_OBJECT));
+        assertTrue(searchDAO.matches(anyObject, SearchCond.getLeafCond(relationshipCond)));
 
         RelationshipTypeCond relationshipTypeCond = new RelationshipTypeCond();
         relationshipTypeCond.setRelationshipTypeKey("neighborhood");
-        assertTrue(searchDAO.matches(anyObject, SearchCond.getLeafCond(relationshipTypeCond), AnyTypeKind.ANY_OBJECT));
+        assertTrue(searchDAO.matches(anyObject, SearchCond.getLeafCond(relationshipTypeCond)));
     }
 
     @Test
@@ -103,25 +103,25 @@ public class AnySearchTest extends AbstractTest {
 
         MembershipCond groupCond = new MembershipCond();
         groupCond.setGroup("secretary");
-        assertFalse(searchDAO.matches(user, SearchCond.getLeafCond(groupCond), AnyTypeKind.USER));
+        assertFalse(searchDAO.matches(user, SearchCond.getLeafCond(groupCond)));
 
         groupCond.setGroup("root");
-        assertTrue(searchDAO.matches(user, SearchCond.getLeafCond(groupCond), AnyTypeKind.USER));
+        assertTrue(searchDAO.matches(user, SearchCond.getLeafCond(groupCond)));
 
         RoleCond roleCond = new RoleCond();
         roleCond.setRoleKey("Other");
-        assertTrue(searchDAO.matches(user, SearchCond.getLeafCond(roleCond), AnyTypeKind.USER));
+        assertTrue(searchDAO.matches(user, SearchCond.getLeafCond(roleCond)));
 
         user = userDAO.find("c9b2dec2-00a7-4855-97c0-d854842b4b24");
         assertNotNull(user);
 
         RelationshipCond relationshipCond = new RelationshipCond();
         relationshipCond.setAnyObject("fc6dbc3a-6c07-4965-8781-921e7401a4a5");
-        assertTrue(searchDAO.matches(user, SearchCond.getLeafCond(relationshipCond), AnyTypeKind.USER));
+        assertTrue(searchDAO.matches(user, SearchCond.getLeafCond(relationshipCond)));
 
         RelationshipTypeCond relationshipTypeCond = new RelationshipTypeCond();
         relationshipTypeCond.setRelationshipTypeKey("neighborhood");
-        assertTrue(searchDAO.matches(user, SearchCond.getLeafCond(relationshipTypeCond), AnyTypeKind.USER));
+        assertTrue(searchDAO.matches(user, SearchCond.getLeafCond(relationshipTypeCond)));
     }
 
     @Test
@@ -133,7 +133,7 @@ public class AnySearchTest extends AbstractTest {
         attrCond.setSchema("show");
         attrCond.setType(AttributeCond.Type.ISNOTNULL);
 
-        assertTrue(searchDAO.matches(group, SearchCond.getLeafCond(attrCond), AnyTypeKind.GROUP));
+        assertTrue(searchDAO.matches(group, SearchCond.getLeafCond(attrCond)));
     }
 
     @Test
@@ -755,4 +755,30 @@ public class AnySearchTest extends AbstractTest {
         matching = searchDAO.search(searchCondition, AnyTypeKind.ANY_OBJECT);
         assertEquals(1, matching.size());
     }
+
+    @Test
+    public void issueSYNCOPE983() {
+        AttributeCond fullnameLeafCond = new AttributeCond(AttributeCond.Type.LIKE);
+        fullnameLeafCond.setSchema("surname");
+        fullnameLeafCond.setExpression("%o%");
+
+        List<OrderByClause> orderByClauses = new ArrayList<>();
+        OrderByClause orderByClause = new OrderByClause();
+        orderByClause.setField("surname");
+        orderByClause.setDirection(OrderByClause.Direction.ASC);
+        orderByClauses.add(orderByClause);
+        orderByClause = new OrderByClause();
+        orderByClause.setField("username");
+        orderByClause.setDirection(OrderByClause.Direction.DESC);
+        orderByClauses.add(orderByClause);
+
+        List<User> users = searchDAO.search(
+                SyncopeConstants.FULL_ADMIN_REALMS,
+                SearchCond.getLeafCond(fullnameLeafCond),
+                -1,
+                -1,
+                orderByClauses,
+                AnyTypeKind.USER);
+        assertFalse(users.isEmpty());
+    }
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/8b5285e1/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/notification/NotificationManagerImpl.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/notification/NotificationManagerImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/notification/NotificationManagerImpl.java
index e5982c4..6248185 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/notification/NotificationManagerImpl.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/notification/NotificationManagerImpl.java
@@ -212,8 +212,8 @@ public class NotificationManagerImpl implements NotificationManager {
             try {
                 NotificationRecipientsProvider recipientsProvider =
                         (NotificationRecipientsProvider) ApplicationContextProvider.getBeanFactory().
-                        createBean(Class.forName(notification.getRecipientsProviderClassName()),
-                                AbstractBeanDefinition.AUTOWIRE_BY_NAME, false);
+                                createBean(Class.forName(notification.getRecipientsProviderClassName()),
+                                        AbstractBeanDefinition.AUTOWIRE_BY_NAME, false);
                 recipientEmails.addAll(recipientsProvider.provideRecipients(notification));
             } catch (Exception e) {
                 LOG.error("Could not fetch recipients from {}", notification.getRecipientsProviderClassName(), e);
@@ -309,8 +309,7 @@ public class NotificationManagerImpl implements NotificationManager {
                     LOG.debug("No events found about {}", any);
                 } else if (anyType == null || any == null
                         || notification.getAbout(anyType) == null
-                        || searchDAO.matches(any,
-                                SearchCondConverter.convert(notification.getAbout(anyType).get()), anyType.getKind())) {
+                        || searchDAO.matches(any, SearchCondConverter.convert(notification.getAbout(anyType).get()))) {
 
                     LOG.debug("Creating notification task for event {} about {}", currentEvent, any);
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/8b5285e1/fit/core-reference/src/test/java/org/apache/syncope/fit/core/RealmITCase.java
----------------------------------------------------------------------
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/RealmITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/RealmITCase.java
index 3d1622e..ae2bf7b 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/RealmITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/RealmITCase.java
@@ -168,7 +168,7 @@ public class RealmITCase extends AbstractITCase {
     @Test
     public void delete() {
         RealmTO realm = new RealmTO();
-        realm.setName("deletable");
+        realm.setName("deletable3");
 
         Response response = realmService.create("/even/two", realm);
         RealmTO[] actuals = getObject(response.getLocation(), RealmService.class, RealmTO[].class);

http://git-wip-us.apache.org/repos/asf/syncope/blob/8b5285e1/fit/core-reference/src/test/java/org/apache/syncope/fit/core/SearchITCase.java
----------------------------------------------------------------------
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/SearchITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/SearchITCase.java
index c652cde..976c11c 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/SearchITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/SearchITCase.java
@@ -20,6 +20,7 @@ package org.apache.syncope.fit.core;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 
@@ -521,4 +522,14 @@ public class SearchITCase extends AbstractITCase {
             anyTypeService.delete(service.getKey());
         }
     }
+
+    @Test
+    public void issueSYNCOPE983() {
+        PagedResult<UserTO> users = userService.search(
+                new AnyQuery.Builder().
+                        fiql(SyncopeClient.getUserSearchConditionBuilder().is("surname").equalTo("*o*").query()).
+                        orderBy(SyncopeClient.getOrderByClauseBuilder().asc("surname").desc("username").build()).
+                        build());
+        assertNotEquals(0, users.getTotalCount());
+    }
 }


[2/2] syncope git commit: [SYNCOPE-983] Improving search performance by skipping unnecessary checks for mandatory schemas

Posted by il...@apache.org.
[SYNCOPE-983] Improving search performance by skipping unnecessary checks for mandatory schemas


Project: http://git-wip-us.apache.org/repos/asf/syncope/repo
Commit: http://git-wip-us.apache.org/repos/asf/syncope/commit/941dc06a
Tree: http://git-wip-us.apache.org/repos/asf/syncope/tree/941dc06a
Diff: http://git-wip-us.apache.org/repos/asf/syncope/diff/941dc06a

Branch: refs/heads/master
Commit: 941dc06a30e14122bd4552de0c600d273a6592b5
Parents: 18ac451
Author: Francesco Chicchiricc� <il...@apache.org>
Authored: Thu Dec 22 09:27:41 2016 +0100
Committer: Francesco Chicchiricc� <il...@apache.org>
Committed: Thu Dec 22 09:27:51 2016 +0100

----------------------------------------------------------------------
 .../core/persistence/api/dao/AnySearchDAO.java  |   3 +-
 .../persistence/jpa/dao/JPAAnySearchDAO.java    | 170 ++++++++++---------
 .../core/persistence/jpa/dao/JPAGroupDAO.java   |   6 +-
 .../core/persistence/jpa/dao/JPARoleDAO.java    |   4 +-
 .../persistence/jpa/dao/OrderBySupport.java     |   2 +
 .../core/persistence/jpa/dao/SearchSupport.java |   8 +-
 .../persistence/jpa/inner/AnySearchTest.java    |  42 ++++-
 .../notification/NotificationManagerImpl.java   |   7 +-
 .../apache/syncope/fit/core/RealmITCase.java    |   2 +-
 .../apache/syncope/fit/core/SearchITCase.java   |  11 ++
 10 files changed, 150 insertions(+), 105 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/syncope/blob/941dc06a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/AnySearchDAO.java
----------------------------------------------------------------------
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/AnySearchDAO.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/AnySearchDAO.java
index b93ca49..fe5b572 100644
--- a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/AnySearchDAO.java
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/AnySearchDAO.java
@@ -79,9 +79,8 @@ public interface AnySearchDAO extends DAO<Any<?>> {
      *
      * @param any to be checked
      * @param searchCondition to be verified
-     * @param kind any object
      * @param <T> any
      * @return true if any matches searchCondition
      */
-    <T extends Any<?>> boolean matches(T any, SearchCond searchCondition, AnyTypeKind kind);
+    <T extends Any<?>> boolean matches(T any, SearchCond searchCondition);
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/941dc06a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAnySearchDAO.java
----------------------------------------------------------------------
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 9554f9a..49bf4ff 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
@@ -114,7 +114,7 @@ public class JPAAnySearchDAO extends AbstractDAO<Any<?>> implements AnySearchDAO
             }
         }
 
-        StringBuilder adminRealmFilter = new StringBuilder().
+        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");
 
@@ -129,7 +129,7 @@ public class JPAAnySearchDAO extends AbstractDAO<Any<?>> implements AnySearchDAO
             adminRealmFilter.append(" id=?").append(setParameter(parameters, realmKey));
         }
 
-        adminRealmFilter.append(')');
+        adminRealmFilter.append("))");
 
         return adminRealmFilter.toString();
     }
@@ -144,8 +144,7 @@ public class JPAAnySearchDAO extends AbstractDAO<Any<?>> implements AnySearchDAO
 
         // 2. take into account administrative realms
         queryString.insert(0, "SELECT u.any_id FROM (");
-        queryString.append(") u WHERE any_id IN (");
-        queryString.append(getAdminRealmsFilter(adminRealms, svs, parameters)).append(')');
+        queryString.append(") u WHERE ").append(getAdminRealmsFilter(adminRealms, svs, parameters));
 
         // 3. prepare the COUNT query
         queryString.insert(0, "SELECT COUNT(any_id) FROM (");
@@ -202,13 +201,11 @@ public class JPAAnySearchDAO extends AbstractDAO<Any<?>> implements AnySearchDAO
     }
 
     @Override
-    public <T extends Any<?>> boolean matches(
-            final T any, final SearchCond cond, final AnyTypeKind typeKind) {
-
+    public <T extends Any<?>> boolean matches(final T any, final SearchCond cond) {
         List<Object> parameters = Collections.synchronizedList(new ArrayList<>());
 
         // 1. get the query string from the search condition
-        SearchSupport svs = new SearchSupport(typeKind);
+        SearchSupport svs = new SearchSupport(any.getType().getKind());
         StringBuilder queryString = getQuery(cond, parameters, svs);
 
         boolean matches;
@@ -257,52 +254,55 @@ public class JPAAnySearchDAO extends AbstractDAO<Any<?>> implements AnySearchDAO
         }
     }
 
-    private StringBuilder buildSelect(final OrderBySupport orderBySupport) {
+    private StringBuilder buildSelect(final OrderBySupport obs) {
         final StringBuilder select = new StringBuilder("SELECT u.any_id");
 
-        for (OrderBySupport.Item obs : orderBySupport.items) {
-            select.append(',').append(obs.select);
+        for (OrderBySupport.Item item : obs.items) {
+            select.append(',').append(item.select);
         }
         select.append(" FROM ");
 
         return select;
     }
 
-    private StringBuilder buildWhere(final OrderBySupport orderBySupport, final AnyTypeKind typeKind) {
-        SearchSupport svs = new SearchSupport(typeKind);
+    private StringBuilder buildWhere(final SearchSupport svs, final OrderBySupport obs) {
         StringBuilder where = new StringBuilder(" u");
-        for (SearchSupport.SearchView searchView : orderBySupport.views) {
+        for (SearchSupport.SearchView searchView : obs.views) {
             where.append(',');
             if (searchView.name.equals(svs.attr().name)) {
-                where.append(" (SELECT * FROM ").append(searchView.name).append(" UNION ").
-                        append("SELECT * FROM ").append(svs.nullAttr().name).append(')');
+                where.append(" (SELECT * FROM ").append(searchView.name);
+
+                if (svs.nonMandatorySchemas || obs.nonMandatorySchemas) {
+                    where.append(" UNION SELECT * FROM ").append(svs.nullAttr().name);
+                }
+
+                where.append(')');
             } else {
                 where.append(searchView.name);
             }
             where.append(' ').append(searchView.alias);
         }
         where.append(" WHERE ");
-        for (SearchSupport.SearchView searchView : orderBySupport.views) {
+        for (SearchSupport.SearchView searchView : obs.views) {
             where.append("u.any_id=").append(searchView.alias).append(".any_id AND ");
         }
 
-        for (OrderBySupport.Item obs : orderBySupport.items) {
-            if (StringUtils.isNotBlank(obs.where)) {
-                where.append(obs.where).append(" AND ");
+        for (OrderBySupport.Item item : obs.items) {
+            if (StringUtils.isNotBlank(item.where)) {
+                where.append(item.where).append(" AND ");
             }
         }
-        where.append("u.any_id IN (");
 
         return where;
     }
 
-    private StringBuilder buildOrderBy(final OrderBySupport orderBySupport) {
+    private StringBuilder buildOrderBy(final OrderBySupport obs) {
         StringBuilder orderBy = new StringBuilder();
 
-        for (OrderBySupport.Item obs : orderBySupport.items) {
-            orderBy.append(obs.orderBy).append(',');
+        for (OrderBySupport.Item item : obs.items) {
+            orderBy.append(item.orderBy).append(',');
         }
-        if (!orderBySupport.items.isEmpty()) {
+        if (!obs.items.isEmpty()) {
             orderBy.insert(0, " ORDER BY ");
             orderBy.deleteCharAt(orderBy.length() - 1);
         }
@@ -315,10 +315,10 @@ public class JPAAnySearchDAO extends AbstractDAO<Any<?>> implements AnySearchDAO
 
         final AnyUtils attrUtils = anyUtilsFactory.getInstance(type);
 
-        OrderBySupport orderBySupport = new OrderBySupport();
+        OrderBySupport obs = new OrderBySupport();
 
         for (OrderByClause clause : orderByClauses) {
-            OrderBySupport.Item obs = new OrderBySupport.Item();
+            OrderBySupport.Item item = new OrderBySupport.Item();
 
             // Manage difference among external key attribute and internal JPA @Id
             String fieldName = "key".equals(clause.getField()) ? "id" : clause.getField();
@@ -327,44 +327,47 @@ public class JPAAnySearchDAO extends AbstractDAO<Any<?>> implements AnySearchDAO
             if (anyField == null) {
                 PlainSchema schema = schemaDAO.find(fieldName);
                 if (schema != null) {
+                    // keep track of involvement of non-mandatory schemas in the order by clauses
+                    obs.nonMandatorySchemas = !"true".equals(schema.getMandatoryCondition());
+
                     if (schema.isUniqueConstraint()) {
-                        orderBySupport.views.add(svs.uniqueAttr());
+                        obs.views.add(svs.uniqueAttr());
 
-                        obs.select = new StringBuilder().
+                        item.select = new StringBuilder().
                                 append(svs.uniqueAttr().alias).append('.').append(svs.fieldName(schema.getType())).
                                 append(" AS ").append(fieldName).toString();
-                        obs.where = new StringBuilder().
+                        item.where = new StringBuilder().
                                 append(svs.uniqueAttr().alias).
                                 append(".schema_id='").append(fieldName).append("'").toString();
-                        obs.orderBy = fieldName + " " + clause.getDirection().name();
+                        item.orderBy = fieldName + " " + clause.getDirection().name();
                     } else {
-                        orderBySupport.views.add(svs.attr());
+                        obs.views.add(svs.attr());
 
-                        obs.select = new StringBuilder().
+                        item.select = new StringBuilder().
                                 append(svs.attr().alias).append('.').append(svs.fieldName(schema.getType())).
                                 append(" AS ").append(fieldName).toString();
-                        obs.where = new StringBuilder().
+                        item.where = new StringBuilder().
                                 append(svs.attr().alias).
                                 append(".schema_id='").append(fieldName).append("'").toString();
-                        obs.orderBy = fieldName + " " + clause.getDirection().name();
+                        item.orderBy = fieldName + " " + clause.getDirection().name();
                     }
                 }
             } else {
-                orderBySupport.views.add(svs.field());
+                obs.views.add(svs.field());
 
-                obs.select = svs.field().alias + "." + fieldName;
-                obs.where = StringUtils.EMPTY;
-                obs.orderBy = svs.field().alias + "." + fieldName + " " + clause.getDirection().name();
+                item.select = svs.field().alias + "." + fieldName;
+                item.where = StringUtils.EMPTY;
+                item.orderBy = svs.field().alias + "." + fieldName + " " + clause.getDirection().name();
             }
 
-            if (obs.isEmpty()) {
+            if (item.isEmpty()) {
                 LOG.warn("Cannot build any valid clause from {}", clause);
             } else {
-                orderBySupport.items.add(obs);
+                obs.items.add(item);
             }
         }
 
-        return orderBySupport;
+        return obs;
     }
 
     @SuppressWarnings("unchecked")
@@ -379,17 +382,17 @@ public class JPAAnySearchDAO extends AbstractDAO<Any<?>> implements AnySearchDAO
         StringBuilder queryString = getQuery(cond, parameters, svs);
 
         // 2. take into account administrative groups and ordering
-        OrderBySupport orderBySupport = parseOrderBy(typeKind, svs, orderBy);
+        OrderBySupport obs = parseOrderBy(typeKind, svs, orderBy);
         if (queryString.charAt(0) == '(') {
-            queryString.insert(0, buildSelect(orderBySupport));
-            queryString.append(buildWhere(orderBySupport, typeKind));
+            queryString.insert(0, buildSelect(obs));
+            queryString.append(buildWhere(svs, obs));
         } else {
-            queryString.insert(0, buildSelect(orderBySupport).append('('));
-            queryString.append(')').append(buildWhere(orderBySupport, typeKind));
+            queryString.insert(0, buildSelect(obs).append('('));
+            queryString.append(')').append(buildWhere(svs, obs));
         }
         queryString.
-                append(getAdminRealmsFilter(adminRealms, svs, parameters)).append(')').
-                append(buildOrderBy(orderBySupport));
+                append(getAdminRealmsFilter(adminRealms, svs, parameters)).
+                append(buildOrderBy(obs));
 
         // 3. prepare the search query
         Query query = entityManager().createNativeQuery(queryString.toString());
@@ -434,30 +437,30 @@ public class JPAAnySearchDAO extends AbstractDAO<Any<?>> implements AnySearchDAO
         switch (cond.getType()) {
             case LEAF:
             case NOT_LEAF:
-                if (cond.getAnyTypeCond() != null && AnyTypeKind.ANY_OBJECT == svs.anyTypeKind()) {
+                if (cond.getAnyTypeCond() != null && AnyTypeKind.ANY_OBJECT == svs.anyTypeKind) {
                     query.append(getQuery(cond.getAnyTypeCond(),
                             cond.getType() == SearchCond.Type.NOT_LEAF, parameters, svs));
                 } else if (cond.getRelationshipTypeCond() != null
-                        && (AnyTypeKind.USER == svs.anyTypeKind() || AnyTypeKind.ANY_OBJECT == svs.anyTypeKind())) {
+                        && (AnyTypeKind.USER == svs.anyTypeKind || AnyTypeKind.ANY_OBJECT == svs.anyTypeKind)) {
 
                     query.append(getQuery(cond.getRelationshipTypeCond(),
                             cond.getType() == SearchCond.Type.NOT_LEAF, parameters, svs));
                 } else if (cond.getRelationshipCond() != null
-                        && (AnyTypeKind.USER == svs.anyTypeKind() || AnyTypeKind.ANY_OBJECT == svs.anyTypeKind())) {
+                        && (AnyTypeKind.USER == svs.anyTypeKind || AnyTypeKind.ANY_OBJECT == svs.anyTypeKind)) {
 
                     query.append(getQuery(cond.getRelationshipCond(),
                             cond.getType() == SearchCond.Type.NOT_LEAF, parameters, svs));
                 } else if (cond.getMembershipCond() != null
-                        && (AnyTypeKind.USER == svs.anyTypeKind() || AnyTypeKind.ANY_OBJECT == svs.anyTypeKind())) {
+                        && (AnyTypeKind.USER == svs.anyTypeKind || AnyTypeKind.ANY_OBJECT == svs.anyTypeKind)) {
 
                     query.append(getQuery(cond.getMembershipCond(),
                             cond.getType() == SearchCond.Type.NOT_LEAF, parameters, svs));
                 } else if (cond.getAssignableCond() != null) {
                     query.append(getQuery(cond.getAssignableCond(), parameters, svs));
-                } else if (cond.getRoleCond() != null && AnyTypeKind.USER == svs.anyTypeKind()) {
+                } else if (cond.getRoleCond() != null && AnyTypeKind.USER == svs.anyTypeKind) {
                     query.append(getQuery(cond.getRoleCond(),
                             cond.getType() == SearchCond.Type.NOT_LEAF, parameters, svs));
-                } else if (cond.getMemberCond() != null && AnyTypeKind.GROUP == svs.anyTypeKind()) {
+                } else if (cond.getMemberCond() != null && AnyTypeKind.GROUP == svs.anyTypeKind) {
                     query.append(getQuery(cond.getMemberCond(),
                             cond.getType() == SearchCond.Type.NOT_LEAF, parameters, svs));
                 } else if (cond.getResourceCond() != null) {
@@ -498,8 +501,8 @@ public class JPAAnySearchDAO extends AbstractDAO<Any<?>> implements AnySearchDAO
         return query;
     }
 
-    private String getQuery(final AnyTypeCond cond, final boolean not, final List<Object> parameters,
-            final SearchSupport svs) {
+    private String getQuery(
+            final AnyTypeCond cond, final boolean not, final List<Object> parameters, final SearchSupport svs) {
 
         StringBuilder query = new StringBuilder("SELECT DISTINCT any_id FROM ").
                 append(svs.field().name).append(" WHERE type_id");
@@ -515,7 +518,10 @@ public class JPAAnySearchDAO extends AbstractDAO<Any<?>> implements AnySearchDAO
         return query.toString();
     }
 
-    private String getQuery(final RelationshipTypeCond cond, final boolean not, final List<Object> parameters,
+    private String getQuery(
+            final RelationshipTypeCond cond,
+            final boolean not,
+            final List<Object> parameters,
             final SearchSupport svs) {
 
         StringBuilder query = new StringBuilder("SELECT DISTINCT any_id FROM ").
@@ -538,8 +544,8 @@ public class JPAAnySearchDAO extends AbstractDAO<Any<?>> implements AnySearchDAO
         return query.toString();
     }
 
-    private String getQuery(final RelationshipCond cond, final boolean not, final List<Object> parameters,
-            final SearchSupport svs) {
+    private String getQuery(
+            final RelationshipCond cond, final boolean not, final List<Object> parameters, final SearchSupport svs) {
 
         String rightAnyObjectKey;
         if (SyncopeConstants.UUID_PATTERN.matcher(cond.getAnyObject()).matches()) {
@@ -569,8 +575,8 @@ public class JPAAnySearchDAO extends AbstractDAO<Any<?>> implements AnySearchDAO
         return query.toString();
     }
 
-    private String getQuery(final MembershipCond cond, final boolean not, final List<Object> parameters,
-            final SearchSupport svs) {
+    private String getQuery(
+            final MembershipCond cond, final boolean not, final List<Object> parameters, final SearchSupport svs) {
 
         String groupKey;
         if (SyncopeConstants.UUID_PATTERN.matcher(cond.getGroup()).matches()) {
@@ -611,8 +617,8 @@ public class JPAAnySearchDAO extends AbstractDAO<Any<?>> implements AnySearchDAO
         return query.toString();
     }
 
-    private String getQuery(final RoleCond cond, final boolean not, final List<Object> parameters,
-            final SearchSupport svs) {
+    private String getQuery(
+            final RoleCond cond, final boolean not, final List<Object> parameters, final SearchSupport svs) {
 
         StringBuilder query = new StringBuilder("SELECT DISTINCT any_id FROM ").
                 append(svs.field().name).append(" WHERE (");
@@ -642,8 +648,8 @@ public class JPAAnySearchDAO extends AbstractDAO<Any<?>> implements AnySearchDAO
         return query.toString();
     }
 
-    private String getQuery(final ResourceCond cond, final boolean not, final List<Object> parameters,
-            final SearchSupport svs) {
+    private String getQuery(
+            final ResourceCond cond, final boolean not, final List<Object> parameters, final SearchSupport svs) {
 
         StringBuilder query = new StringBuilder("SELECT DISTINCT any_id FROM ").
                 append(svs.field().name).append(" WHERE ");
@@ -659,7 +665,7 @@ public class JPAAnySearchDAO extends AbstractDAO<Any<?>> implements AnySearchDAO
                 append(" WHERE resource_id=?").
                 append(setParameter(parameters, cond.getResourceKey()));
 
-        if (svs.anyTypeKind() == AnyTypeKind.USER) {
+        if (svs.anyTypeKind == AnyTypeKind.USER) {
             query.append(" UNION SELECT DISTINCT any_id FROM ").
                     append(svs.groupResource().name).
                     append(" WHERE resource_id=?").
@@ -695,8 +701,8 @@ public class JPAAnySearchDAO extends AbstractDAO<Any<?>> implements AnySearchDAO
         return query.toString();
     }
 
-    private String getQuery(final MemberCond cond, final boolean not, final List<Object> parameters,
-            final SearchSupport svs) {
+    private String getQuery(
+            final MemberCond cond, final boolean not, final List<Object> parameters, final SearchSupport svs) {
 
         String memberKey;
         if (SyncopeConstants.UUID_PATTERN.matcher(cond.getMember()).matches()) {
@@ -740,9 +746,14 @@ public class JPAAnySearchDAO extends AbstractDAO<Any<?>> implements AnySearchDAO
         return query.toString();
     }
 
-    private void fillAttributeQuery(final StringBuilder query, final PlainAttrValue attrValue,
-            final PlainSchema schema, final AttributeCond cond, final boolean not,
-            final List<Object> parameters, final SearchSupport svs) {
+    private void fillAttributeQuery(
+            final StringBuilder query,
+            final PlainAttrValue attrValue,
+            final PlainSchema schema,
+            final AttributeCond cond,
+            final boolean not,
+            final List<Object> parameters,
+            final SearchSupport svs) {
 
         // activate ignoreCase only for EQ and LIKE operators
         boolean ignoreCase = AttributeCond.Type.ILIKE == cond.getType() || AttributeCond.Type.IEQ == cond.getType();
@@ -850,10 +861,10 @@ public class JPAAnySearchDAO extends AbstractDAO<Any<?>> implements AnySearchDAO
         }
     }
 
-    private String getQuery(final AttributeCond cond, final boolean not, final List<Object> parameters,
-            final SearchSupport svs) {
+    private String getQuery(
+            final AttributeCond cond, final boolean not, final List<Object> parameters, final SearchSupport svs) {
 
-        AnyUtils attrUtils = anyUtilsFactory.getInstance(svs.anyTypeKind());
+        AnyUtils attrUtils = anyUtilsFactory.getInstance(svs.anyTypeKind);
 
         PlainSchema schema = schemaDAO.find(cond.getSchema());
         if (schema == null) {
@@ -861,6 +872,9 @@ public class JPAAnySearchDAO extends AbstractDAO<Any<?>> implements AnySearchDAO
             return EMPTY_QUERY;
         }
 
+        // keep track of involvement of non-mandatory schemas in the search condition
+        svs.nonMandatorySchemas = !"true".equals(schema.getMandatoryCondition());
+
         PlainAttrValue attrValue = attrUtils.newPlainAttrValue();
         try {
             if (cond.getType() != AttributeCond.Type.LIKE
@@ -902,12 +916,12 @@ public class JPAAnySearchDAO extends AbstractDAO<Any<?>> implements AnySearchDAO
         return query.toString();
     }
 
-    private String getQuery(final AnyCond cond, final boolean not, final List<Object> parameters,
-            final SearchSupport svs) {
+    private String getQuery(
+            final AnyCond cond, final boolean not, final List<Object> parameters, final SearchSupport svs) {
 
         AnyCond condClone = SerializationUtils.clone(cond);
 
-        AnyUtils attrUtils = anyUtilsFactory.getInstance(svs.anyTypeKind());
+        AnyUtils attrUtils = anyUtilsFactory.getInstance(svs.anyTypeKind);
 
         // Keeps track of difference between entity's getKey() and JPA @Id fields
         if ("key".equals(condClone.getSchema())) {

http://git-wip-us.apache.org/repos/asf/syncope/blob/941dc06a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAGroupDAO.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAGroupDAO.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAGroupDAO.java
index 1785672..0bcdee2 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAGroupDAO.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAGroupDAO.java
@@ -290,8 +290,7 @@ public class JPAGroupDAO extends AbstractAnyDAO<Group> implements GroupDAO {
             for (ADynGroupMembership memb : group.getADynMemberships()) {
                 if (searchDAO.matches(
                         anyObject,
-                        buildDynMembershipCond(memb.getFIQLCond(), group.getRealm()),
-                        AnyTypeKind.ANY_OBJECT)) {
+                        buildDynMembershipCond(memb.getFIQLCond(), group.getRealm()))) {
 
                     memb.add(anyObject);
                 } else {
@@ -308,8 +307,7 @@ public class JPAGroupDAO extends AbstractAnyDAO<Group> implements GroupDAO {
             if (group.getUDynMembership() != null) {
                 if (searchDAO.matches(
                         user,
-                        buildDynMembershipCond(group.getUDynMembership().getFIQLCond(), group.getRealm()),
-                        AnyTypeKind.USER)) {
+                        buildDynMembershipCond(group.getUDynMembership().getFIQLCond(), group.getRealm()))) {
 
                     group.getUDynMembership().add(user);
                 } else {

http://git-wip-us.apache.org/repos/asf/syncope/blob/941dc06a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPARoleDAO.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPARoleDAO.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPARoleDAO.java
index fc91712..b636fc6 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPARoleDAO.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPARoleDAO.java
@@ -111,9 +111,7 @@ public class JPARoleDAO extends AbstractDAO<Role> implements RoleDAO {
     public void refreshDynMemberships(final User user) {
         for (Role role : findAll()) {
             if (role.getDynMembership() != null) {
-                if (searchDAO.matches(user,
-                        SearchCondConverter.convert(role.getDynMembership().getFIQLCond()), AnyTypeKind.USER)) {
-
+                if (searchDAO.matches(user, SearchCondConverter.convert(role.getDynMembership().getFIQLCond()))) {
                     role.getDynMembership().add(user);
                 } else {
                     role.getDynMembership().getMembers().remove(user);

http://git-wip-us.apache.org/repos/asf/syncope/blob/941dc06a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/OrderBySupport.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/OrderBySupport.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/OrderBySupport.java
index 63f442e..ec87f5b 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/OrderBySupport.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/OrderBySupport.java
@@ -44,4 +44,6 @@ class OrderBySupport {
 
     protected List<Item> items = new ArrayList<>();
 
+    protected boolean nonMandatorySchemas = false;
+
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/941dc06a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/SearchSupport.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/SearchSupport.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/SearchSupport.java
index 06854df..9964d89 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/SearchSupport.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/SearchSupport.java
@@ -47,16 +47,14 @@ class SearchSupport {
         }
     }
 
-    private final AnyTypeKind anyTypeKind;
+    protected final AnyTypeKind anyTypeKind;
+
+    protected boolean nonMandatorySchemas = false;
 
     SearchSupport(final AnyTypeKind anyTypeKind) {
         this.anyTypeKind = anyTypeKind;
     }
 
-    public AnyTypeKind anyTypeKind() {
-        return anyTypeKind;
-    }
-
     public String fieldName(final AttrSchemaType attrSchemaType) {
         String result;
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/941dc06a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/AnySearchTest.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/AnySearchTest.java b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/AnySearchTest.java
index 429dfb5..c7e5c62 100644
--- a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/AnySearchTest.java
+++ b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/AnySearchTest.java
@@ -89,11 +89,11 @@ public class AnySearchTest extends AbstractTest {
 
         RelationshipCond relationshipCond = new RelationshipCond();
         relationshipCond.setAnyObject("Canon MF 8030cn");
-        assertTrue(searchDAO.matches(anyObject, SearchCond.getLeafCond(relationshipCond), AnyTypeKind.ANY_OBJECT));
+        assertTrue(searchDAO.matches(anyObject, SearchCond.getLeafCond(relationshipCond)));
 
         RelationshipTypeCond relationshipTypeCond = new RelationshipTypeCond();
         relationshipTypeCond.setRelationshipTypeKey("neighborhood");
-        assertTrue(searchDAO.matches(anyObject, SearchCond.getLeafCond(relationshipTypeCond), AnyTypeKind.ANY_OBJECT));
+        assertTrue(searchDAO.matches(anyObject, SearchCond.getLeafCond(relationshipTypeCond)));
     }
 
     @Test
@@ -103,25 +103,25 @@ public class AnySearchTest extends AbstractTest {
 
         MembershipCond groupCond = new MembershipCond();
         groupCond.setGroup("secretary");
-        assertFalse(searchDAO.matches(user, SearchCond.getLeafCond(groupCond), AnyTypeKind.USER));
+        assertFalse(searchDAO.matches(user, SearchCond.getLeafCond(groupCond)));
 
         groupCond.setGroup("root");
-        assertTrue(searchDAO.matches(user, SearchCond.getLeafCond(groupCond), AnyTypeKind.USER));
+        assertTrue(searchDAO.matches(user, SearchCond.getLeafCond(groupCond)));
 
         RoleCond roleCond = new RoleCond();
         roleCond.setRoleKey("Other");
-        assertTrue(searchDAO.matches(user, SearchCond.getLeafCond(roleCond), AnyTypeKind.USER));
+        assertTrue(searchDAO.matches(user, SearchCond.getLeafCond(roleCond)));
 
         user = userDAO.find("c9b2dec2-00a7-4855-97c0-d854842b4b24");
         assertNotNull(user);
 
         RelationshipCond relationshipCond = new RelationshipCond();
         relationshipCond.setAnyObject("fc6dbc3a-6c07-4965-8781-921e7401a4a5");
-        assertTrue(searchDAO.matches(user, SearchCond.getLeafCond(relationshipCond), AnyTypeKind.USER));
+        assertTrue(searchDAO.matches(user, SearchCond.getLeafCond(relationshipCond)));
 
         RelationshipTypeCond relationshipTypeCond = new RelationshipTypeCond();
         relationshipTypeCond.setRelationshipTypeKey("neighborhood");
-        assertTrue(searchDAO.matches(user, SearchCond.getLeafCond(relationshipTypeCond), AnyTypeKind.USER));
+        assertTrue(searchDAO.matches(user, SearchCond.getLeafCond(relationshipTypeCond)));
     }
 
     @Test
@@ -133,7 +133,7 @@ public class AnySearchTest extends AbstractTest {
         attrCond.setSchema("show");
         attrCond.setType(AttributeCond.Type.ISNOTNULL);
 
-        assertTrue(searchDAO.matches(group, SearchCond.getLeafCond(attrCond), AnyTypeKind.GROUP));
+        assertTrue(searchDAO.matches(group, SearchCond.getLeafCond(attrCond)));
     }
 
     @Test
@@ -755,4 +755,30 @@ public class AnySearchTest extends AbstractTest {
         matching = searchDAO.search(searchCondition, AnyTypeKind.ANY_OBJECT);
         assertEquals(1, matching.size());
     }
+
+    @Test
+    public void issueSYNCOPE983() {
+        AttributeCond fullnameLeafCond = new AttributeCond(AttributeCond.Type.LIKE);
+        fullnameLeafCond.setSchema("surname");
+        fullnameLeafCond.setExpression("%o%");
+
+        List<OrderByClause> orderByClauses = new ArrayList<>();
+        OrderByClause orderByClause = new OrderByClause();
+        orderByClause.setField("surname");
+        orderByClause.setDirection(OrderByClause.Direction.ASC);
+        orderByClauses.add(orderByClause);
+        orderByClause = new OrderByClause();
+        orderByClause.setField("username");
+        orderByClause.setDirection(OrderByClause.Direction.DESC);
+        orderByClauses.add(orderByClause);
+
+        List<User> users = searchDAO.search(
+                SyncopeConstants.FULL_ADMIN_REALMS,
+                SearchCond.getLeafCond(fullnameLeafCond),
+                -1,
+                -1,
+                orderByClauses,
+                AnyTypeKind.USER);
+        assertFalse(users.isEmpty());
+    }
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/941dc06a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/notification/NotificationManagerImpl.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/notification/NotificationManagerImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/notification/NotificationManagerImpl.java
index e5982c4..6248185 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/notification/NotificationManagerImpl.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/notification/NotificationManagerImpl.java
@@ -212,8 +212,8 @@ public class NotificationManagerImpl implements NotificationManager {
             try {
                 NotificationRecipientsProvider recipientsProvider =
                         (NotificationRecipientsProvider) ApplicationContextProvider.getBeanFactory().
-                        createBean(Class.forName(notification.getRecipientsProviderClassName()),
-                                AbstractBeanDefinition.AUTOWIRE_BY_NAME, false);
+                                createBean(Class.forName(notification.getRecipientsProviderClassName()),
+                                        AbstractBeanDefinition.AUTOWIRE_BY_NAME, false);
                 recipientEmails.addAll(recipientsProvider.provideRecipients(notification));
             } catch (Exception e) {
                 LOG.error("Could not fetch recipients from {}", notification.getRecipientsProviderClassName(), e);
@@ -309,8 +309,7 @@ public class NotificationManagerImpl implements NotificationManager {
                     LOG.debug("No events found about {}", any);
                 } else if (anyType == null || any == null
                         || notification.getAbout(anyType) == null
-                        || searchDAO.matches(any,
-                                SearchCondConverter.convert(notification.getAbout(anyType).get()), anyType.getKind())) {
+                        || searchDAO.matches(any, SearchCondConverter.convert(notification.getAbout(anyType).get()))) {
 
                     LOG.debug("Creating notification task for event {} about {}", currentEvent, any);
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/941dc06a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/RealmITCase.java
----------------------------------------------------------------------
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/RealmITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/RealmITCase.java
index 3d1622e..ae2bf7b 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/RealmITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/RealmITCase.java
@@ -168,7 +168,7 @@ public class RealmITCase extends AbstractITCase {
     @Test
     public void delete() {
         RealmTO realm = new RealmTO();
-        realm.setName("deletable");
+        realm.setName("deletable3");
 
         Response response = realmService.create("/even/two", realm);
         RealmTO[] actuals = getObject(response.getLocation(), RealmService.class, RealmTO[].class);

http://git-wip-us.apache.org/repos/asf/syncope/blob/941dc06a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/SearchITCase.java
----------------------------------------------------------------------
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/SearchITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/SearchITCase.java
index c652cde..976c11c 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/SearchITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/SearchITCase.java
@@ -20,6 +20,7 @@ package org.apache.syncope.fit.core;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 
@@ -521,4 +522,14 @@ public class SearchITCase extends AbstractITCase {
             anyTypeService.delete(service.getKey());
         }
     }
+
+    @Test
+    public void issueSYNCOPE983() {
+        PagedResult<UserTO> users = userService.search(
+                new AnyQuery.Builder().
+                        fiql(SyncopeClient.getUserSearchConditionBuilder().is("surname").equalTo("*o*").query()).
+                        orderBy(SyncopeClient.getOrderByClauseBuilder().asc("surname").desc("username").build()).
+                        build());
+        assertNotEquals(0, users.getTotalCount());
+    }
 }