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/24 15:30:12 UTC

[syncope] branch 2_1_X updated: [SYNCOPE-1501] Now isNullValue / isNotNullValue are working as well

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


The following commit(s) were added to refs/heads/2_1_X by this push:
     new 3929ca6  [SYNCOPE-1501] Now isNullValue / isNotNullValue are working as well
3929ca6 is described below

commit 3929ca6c25415b570077575444b81b8293251b9a
Author: Francesco Chicchiriccò <il...@apache.org>
AuthorDate: Thu Oct 24 17:24:53 2019 +0200

    [SYNCOPE-1501] Now isNullValue / isNotNullValue are working as well
---
 .../apache/syncope/core/logic/ResourceLogic.java   |  6 ++-
 .../core/persistence/api/search/FilterVisitor.java | 51 +++++++++++++++-------
 .../api/search/FilterConverterTest.java            | 19 ++++----
 .../core/provisioning/java/utils/MappingUtils.java | 11 ++++-
 .../core/rest/cxf/service/ResourceServiceImpl.java |  5 +++
 .../org/apache/syncope/fit/core/SearchITCase.java  | 39 ++++++++++++-----
 pom.xml                                            |  2 +-
 7 files changed, 94 insertions(+), 39 deletions(-)

diff --git a/core/logic/src/main/java/org/apache/syncope/core/logic/ResourceLogic.java b/core/logic/src/main/java/org/apache/syncope/core/logic/ResourceLogic.java
index 6090b79..55d05be 100644
--- a/core/logic/src/main/java/org/apache/syncope/core/logic/ResourceLogic.java
+++ b/core/logic/src/main/java/org/apache/syncope/core/logic/ResourceLogic.java
@@ -346,6 +346,7 @@ public class ResourceLogic extends AbstractTransactionalLogic<ResourceTO> {
     @Transactional(readOnly = true)
     public Pair<SearchResult, List<ConnObjectTO>> searchConnObjects(
             final Filter filter,
+            final Set<String> moreAttrsToGet,
             final String key,
             final String anyTypeKey,
             final int size,
@@ -365,7 +366,8 @@ public class ResourceLogic extends AbstractTransactionalLogic<ResourceTO> {
             }
 
             objectClass = resource.getOrgUnit().getObjectClass();
-            options = MappingUtils.buildOperationOptions(resource.getOrgUnit().getItems().stream());
+            options = MappingUtils.buildOperationOptions(
+                    resource.getOrgUnit().getItems().stream(), moreAttrsToGet.toArray(new String[0]));
         } else {
             Provision provision = getProvision(key, anyTypeKey);
             resource = provision.getResource();
@@ -374,7 +376,7 @@ public class ResourceLogic extends AbstractTransactionalLogic<ResourceTO> {
             Stream<MappingItem> mapItems = Stream.concat(
                     provision.getMapping().getItems().stream(),
                     virSchemaDAO.findByProvision(provision).stream().map(VirSchema::asLinkingMappingItem));
-            options = MappingUtils.buildOperationOptions(mapItems);
+            options = MappingUtils.buildOperationOptions(mapItems, moreAttrsToGet.toArray(new String[0]));
         }
 
         List<ConnObjectTO> connObjects = new ArrayList<>();
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/search/FilterVisitor.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/search/FilterVisitor.java
index 73d3980..08d3210 100644
--- a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/search/FilterVisitor.java
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/search/FilterVisitor.java
@@ -22,8 +22,11 @@ import java.io.UnsupportedEncodingException;
 import java.net.URLDecoder;
 import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Optional;
+import java.util.Set;
+import org.apache.commons.lang3.StringUtils;
 import org.apache.cxf.jaxrs.ext.search.ConditionType;
 import org.apache.cxf.jaxrs.ext.search.SearchBean;
 import org.apache.cxf.jaxrs.ext.search.SearchCondition;
@@ -41,6 +44,8 @@ public class FilterVisitor extends AbstractSearchConditionVisitor<SearchBean, Fi
 
     private Filter filter;
 
+    private final Set<String> attrs = new HashSet<>();
+
     public FilterVisitor() {
         super(null);
     }
@@ -78,6 +83,7 @@ public class FilterVisitor extends AbstractSearchConditionVisitor<SearchBean, Fi
         }
 
         Attribute attr = AttributeBuilder.build(name, value);
+        attrs.add(name);
 
         Filter leaf;
         switch (ct) {
@@ -85,28 +91,37 @@ public class FilterVisitor extends AbstractSearchConditionVisitor<SearchBean, Fi
             case NOT_EQUALS:
                 if (!specialAttrName.isPresent()) {
                     if (specialAttrValue.isPresent() && specialAttrValue.get() == SpecialAttr.NULL) {
-                        leaf = FilterBuilder.equalTo(AttributeBuilder.build(name));
-                    } else if (value.indexOf('%') == -1) {
-                        leaf = sc.getConditionType() == ConditionType.CUSTOM
-                                ? FilterBuilder.equalsIgnoreCase(attr)
-                                : FilterBuilder.equalTo(attr);
-                    } else if (sc.getConditionType() != ConditionType.CUSTOM && value.startsWith("%")) {
-                        leaf = FilterBuilder.endsWith(
-                                AttributeBuilder.build(name, value.substring(1)));
-                    } else if (sc.getConditionType() != ConditionType.CUSTOM && value.endsWith("%")) {
-                        leaf = FilterBuilder.startsWith(
-                                AttributeBuilder.build(name, value.substring(0, value.length() - 1)));
+                        Filter empty = FilterBuilder.startsWith(AttributeBuilder.build(name, StringUtils.EMPTY));
+                        if (ct == ConditionType.NOT_EQUALS) {
+                            leaf = empty;
+                        } else {
+                            leaf = FilterBuilder.not(empty);
+                            attrs.remove(name);
+                        }
                     } else {
-                        throw new IllegalArgumentException(
-                                String.format("Unsupported search value %s", value));
+                        if (value.indexOf('%') == -1) {
+                            leaf = sc.getConditionType() == ConditionType.CUSTOM
+                                    ? FilterBuilder.equalsIgnoreCase(attr)
+                                    : FilterBuilder.equalTo(attr);
+                        } else if (sc.getConditionType() != ConditionType.CUSTOM && value.startsWith("%")) {
+                            leaf = FilterBuilder.endsWith(
+                                    AttributeBuilder.build(name, value.substring(1)));
+                        } else if (sc.getConditionType() != ConditionType.CUSTOM && value.endsWith("%")) {
+                            leaf = FilterBuilder.startsWith(
+                                    AttributeBuilder.build(name, value.substring(0, value.length() - 1)));
+                        } else {
+                            throw new IllegalArgumentException(
+                                    String.format("Unsupported search value %s", value));
+                        }
+
+                        if (ct == ConditionType.NOT_EQUALS) {
+                            leaf = FilterBuilder.not(leaf);
+                        }
                     }
                 } else {
                     throw new IllegalArgumentException(
                             String.format("Special attr name %s is not supported", specialAttrName));
                 }
-                if (ct == ConditionType.NOT_EQUALS) {
-                    leaf = FilterBuilder.not(leaf);
-                }
                 break;
 
             case GREATER_OR_EQUALS:
@@ -169,4 +184,8 @@ public class FilterVisitor extends AbstractSearchConditionVisitor<SearchBean, Fi
     public Filter getQuery() {
         return filter;
     }
+
+    public Set<String> getAttrs() {
+        return attrs;
+    }
 }
diff --git a/core/persistence-api/src/test/java/org/apache/syncope/core/persistence/api/search/FilterConverterTest.java b/core/persistence-api/src/test/java/org/apache/syncope/core/persistence/api/search/FilterConverterTest.java
index 40c9b69..52834f8 100644
--- a/core/persistence-api/src/test/java/org/apache/syncope/core/persistence/api/search/FilterConverterTest.java
+++ b/core/persistence-api/src/test/java/org/apache/syncope/core/persistence/api/search/FilterConverterTest.java
@@ -25,6 +25,7 @@ import static org.junit.jupiter.api.Assertions.fail;
 
 import java.util.List;
 import java.util.ListIterator;
+import org.apache.commons.lang3.StringUtils;
 import org.apache.commons.lang3.builder.EqualsBuilder;
 import org.apache.syncope.common.lib.SyncopeClientException;
 import org.apache.syncope.common.lib.search.SpecialAttr;
@@ -152,9 +153,14 @@ public class FilterConverterTest {
         String fiql = new ConnObjectTOFiqlSearchConditionBuilder().is("loginDate").nullValue().query();
         assertEquals("loginDate==" + SpecialAttr.NULL, fiql);
 
-        Filter filter = FilterBuilder.equalTo(AttributeBuilder.build("loginDate"));
+        Filter filter = FilterBuilder.not(
+                FilterBuilder.startsWith(AttributeBuilder.build("loginDate", StringUtils.EMPTY)));
 
-        assertTrue(equals(filter, FilterConverter.convert(fiql)));
+        Filter converted = FilterConverter.convert(fiql);
+        assertTrue(converted instanceof NotFilter);
+
+        assertTrue(equals(
+                ((NotFilter) filter).getFilter(), ((NotFilter) converted).getFilter()));
     }
 
     @Test
@@ -162,14 +168,9 @@ public class FilterConverterTest {
         String fiql = new ConnObjectTOFiqlSearchConditionBuilder().is("loginDate").notNullValue().query();
         assertEquals("loginDate!=" + SpecialAttr.NULL, fiql);
 
-        Filter filter = FilterBuilder.not(FilterBuilder.equalTo(AttributeBuilder.build("loginDate")));
-        assertTrue(filter instanceof NotFilter);
-
-        Filter converted = FilterConverter.convert(fiql);
-        assertTrue(converted instanceof NotFilter);
+        Filter filter = FilterBuilder.startsWith(AttributeBuilder.build("loginDate", StringUtils.EMPTY));
 
-        assertTrue(equals(
-                ((NotFilter) filter).getFilter(), ((NotFilter) converted).getFilter()));
+        assertTrue(equals(filter, FilterConverter.convert(fiql)));
     }
 
     @Test
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/utils/MappingUtils.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/utils/MappingUtils.java
index f1fcf4f..45fc590 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/utils/MappingUtils.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/utils/MappingUtils.java
@@ -19,6 +19,7 @@
 package org.apache.syncope.core.provisioning.java.utils;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Optional;
@@ -26,6 +27,7 @@ import java.util.Set;
 import java.util.stream.Stream;
 import org.apache.commons.jexl3.JexlContext;
 import org.apache.commons.jexl3.MapContext;
+import org.apache.commons.lang3.ArrayUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.syncope.common.lib.types.MappingPurpose;
 import org.apache.syncope.core.persistence.api.entity.Any;
@@ -187,16 +189,23 @@ public final class MappingUtils {
      * Build options for requesting all mapped connector attributes.
      *
      * @param items items
+     * @param moreAttrsToGet additional attributes to get
      * @return options for requesting all mapped connector attributes
      * @see OperationOptions
      */
-    public static OperationOptions buildOperationOptions(final Stream<? extends Item> items) {
+    public static OperationOptions buildOperationOptions(
+            final Stream<? extends Item> items,
+            final String... moreAttrsToGet) {
+
         OperationOptionsBuilder builder = new OperationOptionsBuilder();
 
         Set<String> attrsToGet = new HashSet<>();
         attrsToGet.add(Name.NAME);
         attrsToGet.add(Uid.NAME);
         attrsToGet.add(OperationalAttributes.ENABLE_NAME);
+        if (!ArrayUtils.isEmpty(moreAttrsToGet)) {
+            attrsToGet.addAll(Arrays.asList(moreAttrsToGet));
+        }
 
         items.filter(item -> item.getPurpose() != MappingPurpose.NONE).
                 forEach(item -> attrsToGet.add(item.getExtAttrName()));
diff --git a/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/ResourceServiceImpl.java b/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/ResourceServiceImpl.java
index 3eb8954..beb377a 100644
--- a/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/ResourceServiceImpl.java
+++ b/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/ResourceServiceImpl.java
@@ -19,8 +19,10 @@
 package org.apache.syncope.core.rest.cxf.service;
 
 import java.net.URI;
+import java.util.Collections;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 import javax.ws.rs.core.MultivaluedMap;
 import javax.ws.rs.core.Response;
 import javax.ws.rs.core.UriBuilder;
@@ -102,6 +104,7 @@ public class ResourceServiceImpl extends AbstractServiceImpl implements Resource
             final String key, final String anyTypeKey, final ConnObjectTOQuery query) {
 
         Filter filter = null;
+        Set<String> moreAttrsToGet = Collections.emptySet();
         if (StringUtils.isNotBlank(query.getFiql())) {
             try {
                 FilterVisitor visitor = new FilterVisitor();
@@ -109,6 +112,7 @@ public class ResourceServiceImpl extends AbstractServiceImpl implements Resource
                 sc.accept(visitor);
 
                 filter = visitor.getQuery();
+                moreAttrsToGet = visitor.getAttrs();
             } catch (Exception e) {
                 LOG.error("Invalid FIQL expression: {}", query.getFiql(), e);
 
@@ -121,6 +125,7 @@ public class ResourceServiceImpl extends AbstractServiceImpl implements Resource
 
         Pair<SearchResult, List<ConnObjectTO>> list = logic.searchConnObjects(
                 filter,
+                moreAttrsToGet,
                 key,
                 anyTypeKey,
                 query.getSize(),
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 35bdc01..d988174 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
@@ -42,7 +42,6 @@ import org.apache.syncope.common.lib.patch.MembershipPatch;
 import org.apache.syncope.common.lib.patch.UserPatch;
 import org.apache.syncope.common.lib.to.AnyObjectTO;
 import org.apache.syncope.common.lib.to.AnyTypeTO;
-import org.apache.syncope.common.lib.to.ConnObjectTO;
 import org.apache.syncope.common.lib.to.PagedResult;
 import org.apache.syncope.common.lib.to.GroupTO;
 import org.apache.syncope.common.lib.to.MembershipTO;
@@ -511,16 +510,14 @@ public class SearchITCase extends AbstractITCase {
 
     @Test
     public void searchConnObjectsWithFilter() {
-        ConnObjectTO user = resourceService.readConnObject(RESOURCE_NAME_LDAP, AnyTypeKind.USER.name(), "pullFromLDAP");
-        assertNotNull(user);
-
         PagedConnObjectTOResult matches = resourceService.searchConnObjects(
                 RESOURCE_NAME_LDAP,
                 AnyTypeKind.USER.name(),
                 new ConnObjectTOQuery.Builder().size(100).fiql(
                         SyncopeClient.getConnObjectTOFiqlSearchConditionBuilder().
                                 is("givenName").equalTo("pullFromLDAP").query()).build());
-        assertTrue(matches.getResult().contains(user));
+        assertTrue(matches.getResult().stream().
+                anyMatch(connObject -> connObject.getAttr("givenName").get().getValues().contains("pullFromLDAP")));
 
         matches = resourceService.searchConnObjects(
                 RESOURCE_NAME_LDAP,
@@ -528,7 +525,8 @@ public class SearchITCase extends AbstractITCase {
                 new ConnObjectTOQuery.Builder().size(100).fiql(
                         SyncopeClient.getConnObjectTOFiqlSearchConditionBuilder().
                                 is("mail").equalTo("pullFromLDAP*").query()).build());
-        assertTrue(matches.getResult().contains(user));
+        assertTrue(matches.getResult().stream().
+                anyMatch(connObject -> connObject.getAttr("cn").get().getValues().contains("pullFromLDAP")));
 
         matches = resourceService.searchConnObjects(
                 RESOURCE_NAME_LDAP,
@@ -536,7 +534,8 @@ public class SearchITCase extends AbstractITCase {
                 new ConnObjectTOQuery.Builder().size(100).fiql(
                         SyncopeClient.getConnObjectTOFiqlSearchConditionBuilder().
                                 is("mail").equalTo("*@syncope.apache.org").query()).build());
-        assertTrue(matches.getResult().contains(user));
+        assertTrue(matches.getResult().stream().
+                anyMatch(connObject -> connObject.getAttr("cn").get().getValues().contains("pullFromLDAP")));
 
         matches = resourceService.searchConnObjects(
                 RESOURCE_NAME_LDAP,
@@ -544,7 +543,8 @@ public class SearchITCase extends AbstractITCase {
                 new ConnObjectTOQuery.Builder().size(100).fiql(
                         SyncopeClient.getConnObjectTOFiqlSearchConditionBuilder().
                                 is("givenName").equalToIgnoreCase("pullfromldap").query()).build());
-        assertTrue(matches.getResult().contains(user));
+        assertTrue(matches.getResult().stream().
+                anyMatch(connObject -> connObject.getAttr("givenName").get().getValues().contains("pullFromLDAP")));
 
         matches = resourceService.searchConnObjects(
                 RESOURCE_NAME_LDAP,
@@ -552,7 +552,8 @@ public class SearchITCase extends AbstractITCase {
                 new ConnObjectTOQuery.Builder().size(100).fiql(
                         SyncopeClient.getConnObjectTOFiqlSearchConditionBuilder().
                                 is(Name.NAME).equalTo("uid=pullFromLDAP%252Cou=people%252Co=isp").query()).build());
-        assertTrue(matches.getResult().contains(user));
+        assertTrue(matches.getResult().stream().
+                anyMatch(connObject -> connObject.getAttr("cn").get().getValues().contains("pullFromLDAP")));
 
         matches = resourceService.searchConnObjects(
                 RESOURCE_NAME_LDAP,
@@ -560,7 +561,25 @@ public class SearchITCase extends AbstractITCase {
                 new ConnObjectTOQuery.Builder().size(100).fiql(
                         SyncopeClient.getConnObjectTOFiqlSearchConditionBuilder().
                                 is("givenName").notEqualTo("pullFromLDAP").query()).build());
-        assertFalse(matches.getResult().contains(user));
+        assertFalse(matches.getResult().stream().
+                anyMatch(connObject -> connObject.getAttr("givenName").get().getValues().contains("pullFromLDAP")));
+
+        matches = resourceService.searchConnObjects(
+                RESOURCE_NAME_LDAP,
+                AnyTypeKind.USER.name(),
+                new ConnObjectTOQuery.Builder().size(100).fiql(
+                        SyncopeClient.getConnObjectTOFiqlSearchConditionBuilder().
+                                is("homePhone").notNullValue().query()).build());
+        assertTrue(matches.getResult().isEmpty());
+
+        matches = resourceService.searchConnObjects(
+                RESOURCE_NAME_LDAP,
+                AnyTypeKind.USER.name(),
+                new ConnObjectTOQuery.Builder().size(100).fiql(
+                        SyncopeClient.getConnObjectTOFiqlSearchConditionBuilder().
+                                is("homePhone").nullValue().query()).build());
+        assertTrue(matches.getResult().stream().
+                anyMatch(connObject -> !connObject.getAttr("homePhone").isPresent()));
     }
 
     @Test
diff --git a/pom.xml b/pom.xml
index 17c933e..5b763e3 100644
--- a/pom.xml
+++ b/pom.xml
@@ -387,7 +387,7 @@ under the License.
   <properties>
     <syncope.version>${project.version}</syncope.version>
 
-    <connid.version>1.5.0.1</connid.version>
+    <connid.version>1.5.0.2</connid.version>
     <connid.soap.version>1.4.3</connid.soap.version>
     <connid.rest.version>1.0.5</connid.rest.version>
     <connid.database.version>2.2.6</connid.database.version>