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/07/18 10:44:48 UTC

[3/3] syncope git commit: [SYNCOPE-902] Feature provided

[SYNCOPE-902] Feature provided


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

Branch: refs/heads/master
Commit: 31dfc1c51663ee08588dbf671a95148cee257c1a
Parents: 8347a70
Author: Francesco Chicchiricc� <il...@apache.org>
Authored: Mon Jul 18 12:44:38 2016 +0200
Committer: Francesco Chicchiricc� <il...@apache.org>
Committed: Mon Jul 18 12:44:38 2016 +0200

----------------------------------------------------------------------
 .../panels/search/AbstractSearchPanel.java      |   2 +-
 .../console/panels/search/GroupSearchPanel.java |   3 +-
 .../console/panels/search/SearchClause.java     |   1 +
 .../panels/search/SearchClausePanel.java        |  21 ++++
 .../console/panels/search/SearchUtils.java      | 107 +++++++++++--------
 .../client/console/panels/AnyPanel.properties   |   2 +-
 .../console/panels/AnyPanel_it.properties       |   2 +-
 .../console/panels/AnyPanel_pt_BR.properties    |   2 +-
 .../console/panels/AnyPanel_ru.properties       |   4 +-
 .../search/GroupFiqlSearchConditionBuilder.java |  26 ++++-
 .../common/lib/search/GroupProperty.java        |   3 +
 .../syncope/common/lib/search/SpecialAttr.java  |   4 +
 .../persistence/api/dao/search/MemberCond.java  |  40 +++++++
 .../persistence/api/dao/search/SearchCond.java  |  66 ++++--------
 .../api/search/SearchCondVisitor.java           |   7 ++
 .../api/search/SearchCondConverterTest.java     |  13 +++
 .../persistence/jpa/dao/JPAAnySearchDAO.java    |  52 +++++++--
 .../persistence/jpa/inner/AnySearchTest.java    |  14 +++
 .../apache/syncope/fit/core/SearchITCase.java   |  63 ++++++++---
 19 files changed, 316 insertions(+), 116 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/syncope/blob/31dfc1c5/client/console/src/main/java/org/apache/syncope/client/console/panels/search/AbstractSearchPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/panels/search/AbstractSearchPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/panels/search/AbstractSearchPanel.java
index 1b6de2c..3c46a9e 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/panels/search/AbstractSearchPanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/search/AbstractSearchPanel.java
@@ -137,7 +137,7 @@ public abstract class AbstractSearchPanel extends Panel {
 
         final MultiFieldPanel.Builder<SearchClause> searchView = new MultiFieldPanel.Builder<SearchClause>(model) {
 
-            private static final long serialVersionUID = 1L;
+            private static final long serialVersionUID = 1343431509987473047L;
 
             @Override
             protected SearchClause newModelObject() {

http://git-wip-us.apache.org/repos/asf/syncope/blob/31dfc1c5/client/console/src/main/java/org/apache/syncope/client/console/panels/search/GroupSearchPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/panels/search/GroupSearchPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/panels/search/GroupSearchPanel.java
index d91aa28..91ed318 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/panels/search/GroupSearchPanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/search/GroupSearchPanel.java
@@ -58,9 +58,10 @@ public final class GroupSearchPanel extends AbstractSearchPanel {
 
             @Override
             protected List<SearchClause.Type> load() {
-                final List<SearchClause.Type> result = new ArrayList<>();
+                List<SearchClause.Type> result = new ArrayList<>();
                 result.add(SearchClause.Type.ATTRIBUTE);
                 result.add(SearchClause.Type.RESOURCE);
+                result.add(SearchClause.Type.GROUP_MEMBER);
                 return result;
             }
         };

http://git-wip-us.apache.org/repos/asf/syncope/blob/31dfc1c5/client/console/src/main/java/org/apache/syncope/client/console/panels/search/SearchClause.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/panels/search/SearchClause.java b/client/console/src/main/java/org/apache/syncope/client/console/panels/search/SearchClause.java
index b5732ed..9007485 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/panels/search/SearchClause.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/search/SearchClause.java
@@ -39,6 +39,7 @@ public final class SearchClause implements Serializable {
 
         ATTRIBUTE,
         GROUP_MEMBERSHIP,
+        GROUP_MEMBER,
         ROLE_MEMBERSHIP,
         RESOURCE,
         RELATIONSHIP;

http://git-wip-us.apache.org/repos/asf/syncope/blob/31dfc1c5/client/console/src/main/java/org/apache/syncope/client/console/panels/search/SearchClausePanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/panels/search/SearchClausePanel.java b/client/console/src/main/java/org/apache/syncope/client/console/panels/search/SearchClausePanel.java
index 7f7eb5e..0db39f4 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/panels/search/SearchClausePanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/search/SearchClausePanel.java
@@ -152,6 +152,7 @@ public class SearchClausePanel extends FieldPanel<SearchClause> {
 
                     case ROLE_MEMBERSHIP:
                     case GROUP_MEMBERSHIP:
+                    case GROUP_MEMBER:
                     case RESOURCE:
                         return Arrays.asList(
                                 SearchClause.Comparator.EQUALS,
@@ -445,6 +446,12 @@ public class SearchClausePanel extends FieldPanel<SearchClause> {
                     value.setModelObject(StringUtils.EMPTY);
                     break;
 
+                case GROUP_MEMBER:
+                    value.setEnabled(true);
+                    property.setEnabled(false);
+                    property.setModelObject(null);
+                    break;
+
                 case RESOURCE:
                     property.setChoiceRenderer(new DefaultChoiceRender());
                     value.setEnabled(false);
@@ -538,6 +545,20 @@ public class SearchClausePanel extends FieldPanel<SearchClause> {
                                 display = StringUtils.EMPTY;
                         }
                         break;
+                    case GROUP_MEMBER:
+                        switch (object) {
+                            case EQUALS:
+                                display = "WITH";
+                                break;
+
+                            case NOT_EQUALS:
+                                display = "NOT WITH";
+                                break;
+
+                            default:
+                                display = StringUtils.EMPTY;
+                        }
+                        break;
                     case ROLE_MEMBERSHIP:
                     case RESOURCE:
                         switch (object) {

http://git-wip-us.apache.org/repos/asf/syncope/blob/31dfc1c5/client/console/src/main/java/org/apache/syncope/client/console/panels/search/SearchUtils.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/panels/search/SearchUtils.java b/client/console/src/main/java/org/apache/syncope/client/console/panels/search/SearchUtils.java
index 6857e20..b1fc298 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/panels/search/SearchUtils.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/search/SearchUtils.java
@@ -33,6 +33,7 @@ import org.apache.cxf.jaxrs.ext.search.client.CompleteCondition;
 import org.apache.cxf.jaxrs.ext.search.fiql.FiqlParser;
 import org.apache.syncope.common.lib.search.AbstractFiqlSearchConditionBuilder;
 import org.apache.syncope.common.lib.search.AnyObjectFiqlSearchConditionBuilder;
+import org.apache.syncope.common.lib.search.GroupFiqlSearchConditionBuilder;
 import org.apache.syncope.common.lib.search.SpecialAttr;
 import org.apache.syncope.common.lib.search.SyncopeProperty;
 import org.apache.syncope.common.lib.search.UserFiqlSearchConditionBuilder;
@@ -74,7 +75,7 @@ public final class SearchUtils implements Serializable {
         return res;
     }
 
-    public static List<SearchClause> getSearchClauses(final SearchCondition<SearchBean> sc) {
+    private static List<SearchClause> getSearchClauses(final SearchCondition<SearchBean> sc) {
         List<SearchClause> res = new ArrayList<>();
 
         if (sc.getStatement() == null) {
@@ -86,7 +87,7 @@ public final class SearchUtils implements Serializable {
         return res;
     }
 
-    public static List<SearchClause> getCompoundSearchClause(final SearchCondition<SearchBean> sc) {
+    private static List<SearchClause> getCompoundSearchClause(final SearchCondition<SearchBean> sc) {
         List<SearchClause> res = new ArrayList<>();
 
         for (SearchCondition<SearchBean> searchCondition : sc.getSearchConditions()) {
@@ -107,7 +108,7 @@ public final class SearchUtils implements Serializable {
         return res;
     }
 
-    public static SearchClause getPrimitiveSearchClause(final SearchCondition<SearchBean> sc) {
+    private static SearchClause getPrimitiveSearchClause(final SearchCondition<SearchBean> sc) {
         SearchClause res = new SearchClause();
 
         String property = sc.getCondition().getKeySet().iterator().next();
@@ -115,7 +116,7 @@ public final class SearchUtils implements Serializable {
         String value = sc.getCondition().get(property);
         res.setValue(value);
 
-        LOG.info("Condition: " + sc.getCondition());
+        LOG.debug("Condition: " + sc.getCondition());
 
         if (SpecialAttr.ROLES.toString().equals(property)) {
             res.setType(SearchClause.Type.ROLE_MEMBERSHIP);
@@ -132,6 +133,9 @@ public final class SearchUtils implements Serializable {
         } else if (SpecialAttr.RESOURCES.toString().equals(property)) {
             res.setType(SearchClause.Type.RESOURCE);
             res.setProperty(value);
+        } else if (SpecialAttr.MEMBER.toString().equals(property)) {
+            res.setType(SearchClause.Type.GROUP_MEMBER);
+            res.setProperty(value);
         } else {
             res.setType(SearchClause.Type.ATTRIBUTE);
         }
@@ -189,12 +193,27 @@ public final class SearchUtils implements Serializable {
         boolean notTheFirst = false;
 
         for (SearchClause clause : clauses) {
-            if (clause.getType() != null && (SearchClause.Type.RELATIONSHIP == clause.getType()
-                    || StringUtils.isNotBlank(clause.getProperty()))) {
-                prevCondition = condition;
+            prevCondition = condition;
+
+            switch (clause.getType()) {
+                case GROUP_MEMBER:
+                    switch (clause.getComparator()) {
+                        case EQUALS:
+                            condition = ((GroupFiqlSearchConditionBuilder) builder).
+                                    withMembers(clause.getValue());
+                            break;
+
+                        case NOT_EQUALS:
+                            condition = ((GroupFiqlSearchConditionBuilder) builder).
+                                    withoutMembers(clause.getValue());
+                            break;
+
+                        default:
+                    }
+                    break;
 
-                switch (clause.getType()) {
-                    case GROUP_MEMBERSHIP:
+                case GROUP_MEMBERSHIP:
+                    if (StringUtils.isNotBlank(clause.getProperty())) {
                         String groupKey = clause.getProperty().split(" ")[0];
 
                         if (builder instanceof UserFiqlSearchConditionBuilder) {
@@ -206,15 +225,19 @@ public final class SearchUtils implements Serializable {
                                     ? ((AnyObjectFiqlSearchConditionBuilder) builder).inGroups(groupKey)
                                     : ((AnyObjectFiqlSearchConditionBuilder) builder).notInGroups(groupKey);
                         }
-                        break;
+                    }
+                    break;
 
-                    case RESOURCE:
+                case RESOURCE:
+                    if (StringUtils.isNotBlank(clause.getProperty())) {
                         condition = clause.getComparator() == SearchClause.Comparator.EQUALS
                                 ? builder.hasResources(clause.getProperty())
                                 : builder.hasNotResources(clause.getProperty());
-                        break;
+                    }
+                    break;
 
-                    case ATTRIBUTE:
+                case ATTRIBUTE:
+                    if (StringUtils.isNotBlank(clause.getProperty())) {
                         SyncopeProperty property = builder.is(clause.getProperty());
                         switch (clause.getComparator()) {
                             case IS_NULL:
@@ -258,9 +281,11 @@ public final class SearchUtils implements Serializable {
                                 condition = property.equalTo(clause.getValue());
                                 break;
                         }
-                        break;
+                    }
+                    break;
 
-                    case ROLE_MEMBERSHIP:
+                case ROLE_MEMBERSHIP:
+                    if (StringUtils.isNotBlank(clause.getProperty())) {
                         switch (clause.getComparator()) {
                             case EQUALS:
                                 condition = ((UserFiqlSearchConditionBuilder) builder).inRoles(clause.getProperty());
@@ -271,30 +296,28 @@ public final class SearchUtils implements Serializable {
                             default:
                                 break;
                         }
-                        break;
-
-                    case RELATIONSHIP:
-                        String relationship = clause.getProperty();
-                        String value = clause.getValue();
+                    }
+                    break;
 
-                        // This condition could be avoided by providing a refactoring of the common lib
+                case RELATIONSHIP:
+                    if (StringUtils.isNotBlank(clause.getProperty())) {
                         if (builder instanceof UserFiqlSearchConditionBuilder) {
                             switch (clause.getComparator()) {
                                 case IS_NOT_NULL:
                                     condition = ((UserFiqlSearchConditionBuilder) builder).
-                                            inRelationshipTypes(relationship);
+                                            inRelationshipTypes(clause.getProperty());
                                     break;
                                 case IS_NULL:
                                     condition = ((UserFiqlSearchConditionBuilder) builder).
-                                            notInRelationshipTypes(relationship);
+                                            notInRelationshipTypes(clause.getProperty());
                                     break;
                                 case EQUALS:
                                     condition = ((UserFiqlSearchConditionBuilder) builder).
-                                            inRelationships(value);
+                                            inRelationships(clause.getValue());
                                     break;
                                 case NOT_EQUALS:
                                     condition = ((UserFiqlSearchConditionBuilder) builder).
-                                            notInRelationships(value);
+                                            notInRelationships(clause.getValue());
                                     break;
                                 default:
                                     break;
@@ -303,41 +326,41 @@ public final class SearchUtils implements Serializable {
                             switch (clause.getComparator()) {
                                 case IS_NOT_NULL:
                                     condition = ((AnyObjectFiqlSearchConditionBuilder) builder).
-                                            inRelationshipTypes(relationship);
+                                            inRelationshipTypes(clause.getProperty());
                                     break;
                                 case IS_NULL:
                                     condition = ((AnyObjectFiqlSearchConditionBuilder) builder).
-                                            notInRelationshipTypes(relationship);
+                                            notInRelationshipTypes(clause.getProperty());
                                     break;
                                 case EQUALS:
                                     condition = ((AnyObjectFiqlSearchConditionBuilder) builder).
-                                            inRelationships(value);
+                                            inRelationships(clause.getValue());
                                     break;
                                 case NOT_EQUALS:
                                     condition = ((AnyObjectFiqlSearchConditionBuilder) builder).
-                                            notInRelationships(value);
+                                            notInRelationships(clause.getValue());
                                     break;
                                 default:
                                     break;
                             }
                         }
-                        break;
+                    }
+                    break;
 
-                    default:
-                        break;
-                }
+                default:
+                    break;
+            }
 
-                if (notTheFirst) {
-                    if (clause.getOperator() == SearchClause.Operator.AND) {
-                        condition = builder.and(prevCondition, condition);
-                    }
-                    if (clause.getOperator() == SearchClause.Operator.OR) {
-                        condition = builder.or(prevCondition, condition);
-                    }
+            if (notTheFirst) {
+                if (clause.getOperator() == SearchClause.Operator.AND) {
+                    condition = builder.and(prevCondition, condition);
+                }
+                if (clause.getOperator() == SearchClause.Operator.OR) {
+                    condition = builder.or(prevCondition, condition);
                 }
-
-                notTheFirst = true;
             }
+
+            notTheFirst = true;
         }
 
         String fiql = condition == null ? null : condition.query();

http://git-wip-us.apache.org/repos/asf/syncope/blob/31dfc1c5/client/console/src/main/resources/org/apache/syncope/client/console/panels/AnyPanel.properties
----------------------------------------------------------------------
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/panels/AnyPanel.properties b/client/console/src/main/resources/org/apache/syncope/client/console/panels/AnyPanel.properties
index aaee233..f9235eb 100644
--- a/client/console/src/main/resources/org/apache/syncope/client/console/panels/AnyPanel.properties
+++ b/client/console/src/main/resources/org/apache/syncope/client/console/panels/AnyPanel.properties
@@ -14,4 +14,4 @@
 # KIND, either express or implied.  See the License for the
 # specific language governing permissions and limitations
 # under the License.
-search.result=Filtered search for ${key}
+search.result=${key} Search

http://git-wip-us.apache.org/repos/asf/syncope/blob/31dfc1c5/client/console/src/main/resources/org/apache/syncope/client/console/panels/AnyPanel_it.properties
----------------------------------------------------------------------
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/panels/AnyPanel_it.properties b/client/console/src/main/resources/org/apache/syncope/client/console/panels/AnyPanel_it.properties
index 19ecff3..eede918 100644
--- a/client/console/src/main/resources/org/apache/syncope/client/console/panels/AnyPanel_it.properties
+++ b/client/console/src/main/resources/org/apache/syncope/client/console/panels/AnyPanel_it.properties
@@ -14,4 +14,4 @@
 # KIND, either express or implied.  See the License for the
 # specific language governing permissions and limitations
 # under the License.
-search.result=Ricerca filtrata per ${key}
+search.result=Ricerca ${key}

http://git-wip-us.apache.org/repos/asf/syncope/blob/31dfc1c5/client/console/src/main/resources/org/apache/syncope/client/console/panels/AnyPanel_pt_BR.properties
----------------------------------------------------------------------
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/panels/AnyPanel_pt_BR.properties b/client/console/src/main/resources/org/apache/syncope/client/console/panels/AnyPanel_pt_BR.properties
index aaee233..f9235eb 100644
--- a/client/console/src/main/resources/org/apache/syncope/client/console/panels/AnyPanel_pt_BR.properties
+++ b/client/console/src/main/resources/org/apache/syncope/client/console/panels/AnyPanel_pt_BR.properties
@@ -14,4 +14,4 @@
 # KIND, either express or implied.  See the License for the
 # specific language governing permissions and limitations
 # under the License.
-search.result=Filtered search for ${key}
+search.result=${key} Search

http://git-wip-us.apache.org/repos/asf/syncope/blob/31dfc1c5/client/console/src/main/resources/org/apache/syncope/client/console/panels/AnyPanel_ru.properties
----------------------------------------------------------------------
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/panels/AnyPanel_ru.properties b/client/console/src/main/resources/org/apache/syncope/client/console/panels/AnyPanel_ru.properties
index 7dbf30b..cfca07a 100644
--- a/client/console/src/main/resources/org/apache/syncope/client/console/panels/AnyPanel_ru.properties
+++ b/client/console/src/main/resources/org/apache/syncope/client/console/panels/AnyPanel_ru.properties
@@ -15,5 +15,5 @@
 # specific language governing permissions and limitations
 # under the License.
 #
-# search.result=\u041f\u043e\u0438\u0441\u043a \u043f\u043e \u0442\u0438\u043f\u0443 \u043e\u0431\u044a\u0435\u043a\u0442\u0430 ${key}
-search.result=\u041f\u043e\u0438\u0441\u043a \u043f\u043e \u0442\u0438\u043f\u0443 \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432: ${key}
+# search.result=\u00d0\u009f\u00d0\u00be\u00d0\u00b8\u00d1\u0081\u00d0\u00ba \u00d0\u00bf\u00d0\u00be \u00d1\u0082\u00d0\u00b8\u00d0\u00bf\u00d1\u0083 \u00d0\u00be\u00d0\u00b1\u00d1\u008a\u00d0\u00b5\u00d0\u00ba\u00d1\u0082\u00d0\u00b0 ${key}
+search.result=${key} Search

http://git-wip-us.apache.org/repos/asf/syncope/blob/31dfc1c5/common/lib/src/main/java/org/apache/syncope/common/lib/search/GroupFiqlSearchConditionBuilder.java
----------------------------------------------------------------------
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/search/GroupFiqlSearchConditionBuilder.java b/common/lib/src/main/java/org/apache/syncope/common/lib/search/GroupFiqlSearchConditionBuilder.java
index af0364b..5e1b1d7 100644
--- a/common/lib/src/main/java/org/apache/syncope/common/lib/search/GroupFiqlSearchConditionBuilder.java
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/search/GroupFiqlSearchConditionBuilder.java
@@ -44,7 +44,19 @@ public class GroupFiqlSearchConditionBuilder extends AbstractFiqlSearchCondition
                 isAssignable();
     }
 
-    protected static class Builder extends AbstractFiqlSearchConditionBuilder.Builder
+    public CompleteCondition withMembers(final String member, final String... moreMembers) {
+        return newBuilderInstance().
+                is(SpecialAttr.MEMBER.toString()).
+                withMembers(member, moreMembers);
+    }
+
+    public CompleteCondition withoutMembers(final String member, final String... moreMembers) {
+        return newBuilderInstance().
+                is(SpecialAttr.MEMBER.toString()).
+                withoutMembers(member, moreMembers);
+    }
+
+    protected class Builder extends AbstractFiqlSearchConditionBuilder.Builder
             implements GroupProperty, CompleteCondition {
 
         public Builder(final Map<String, String> properties) {
@@ -68,5 +80,17 @@ public class GroupFiqlSearchConditionBuilder extends AbstractFiqlSearchCondition
             return condition(FiqlParser.EQ, SpecialAttr.NULL);
         }
 
+        @Override
+        public CompleteCondition withMembers(final String member, final String... moreMembers) {
+            this.result = SpecialAttr.MEMBER.toString();
+            return condition(FiqlParser.EQ, member, (Object[]) moreMembers);
+        }
+
+        @Override
+        public CompleteCondition withoutMembers(final String member, final String... moreMembers) {
+            this.result = SpecialAttr.MEMBER.toString();
+            return condition(FiqlParser.NEQ, member, (Object[]) moreMembers);
+        }
+
     }
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/31dfc1c5/common/lib/src/main/java/org/apache/syncope/common/lib/search/GroupProperty.java
----------------------------------------------------------------------
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/search/GroupProperty.java b/common/lib/src/main/java/org/apache/syncope/common/lib/search/GroupProperty.java
index 672bac0..0325a72 100644
--- a/common/lib/src/main/java/org/apache/syncope/common/lib/search/GroupProperty.java
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/search/GroupProperty.java
@@ -24,4 +24,7 @@ public interface GroupProperty extends SyncopeProperty {
 
     CompleteCondition isAssignable();
 
+    CompleteCondition withMembers(String member, String... moreMembers);
+
+    CompleteCondition withoutMembers(String member, String... moreMembers);
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/31dfc1c5/common/lib/src/main/java/org/apache/syncope/common/lib/search/SpecialAttr.java
----------------------------------------------------------------------
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/search/SpecialAttr.java b/common/lib/src/main/java/org/apache/syncope/common/lib/search/SpecialAttr.java
index c8b917c..d8b6672 100644
--- a/common/lib/src/main/java/org/apache/syncope/common/lib/search/SpecialAttr.java
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/search/SpecialAttr.java
@@ -56,6 +56,10 @@ public enum SpecialAttr {
      */
     ROLES("$roles"),
     /**
+     * Applies to groups.
+     */
+    MEMBER("$member"),
+    /**
      * Applies to groups and any objects.
      */
     ASSIGNABLE("$assignable");

http://git-wip-us.apache.org/repos/asf/syncope/blob/31dfc1c5/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/search/MemberCond.java
----------------------------------------------------------------------
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/search/MemberCond.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/search/MemberCond.java
new file mode 100644
index 0000000..677d65a
--- /dev/null
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/search/MemberCond.java
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.core.persistence.api.dao.search;
+
+public class MemberCond extends AbstractSearchCond {
+
+    private static final long serialVersionUID = 1193754148321878685L;
+
+    private String member;
+
+    public String getMember() {
+        return member;
+    }
+
+    public void setMember(final String member) {
+        this.member = member;
+    }
+
+    @Override
+    public boolean isValid() {
+        return member != null;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/31dfc1c5/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/search/SearchCond.java
----------------------------------------------------------------------
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/search/SearchCond.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/search/SearchCond.java
index 5b4b926..61cc664 100644
--- a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/search/SearchCond.java
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/search/SearchCond.java
@@ -53,6 +53,8 @@ public class SearchCond extends AbstractSearchCond {
 
     private AssignableCond assignableCond;
 
+    private MemberCond memberCond;
+
     private SearchCond leftNodeCond;
 
     private SearchCond rightNodeCond;
@@ -133,6 +135,15 @@ public class SearchCond extends AbstractSearchCond {
         return nodeCond;
     }
 
+    public static SearchCond getLeafCond(final MemberCond memberCond) {
+        SearchCond nodeCond = new SearchCond();
+
+        nodeCond.type = Type.LEAF;
+        nodeCond.memberCond = memberCond;
+
+        return nodeCond;
+    }
+
     public static SearchCond getNotLeafCond(final AttributeCond attributeCond) {
         SearchCond nodeCond = getLeafCond(attributeCond);
         nodeCond.type = Type.NOT_LEAF;
@@ -163,6 +174,12 @@ public class SearchCond extends AbstractSearchCond {
         return nodeCond;
     }
 
+    public static SearchCond getNotLeafCond(final MemberCond memberCond) {
+        SearchCond nodeCond = getLeafCond(memberCond);
+        nodeCond.type = Type.NOT_LEAF;
+        return nodeCond;
+    }
+
     public static SearchCond getNotLeafCond(final SearchCond nodeCond) {
         nodeCond.type = Type.NOT_LEAF;
         return nodeCond;
@@ -218,90 +235,50 @@ public class SearchCond extends AbstractSearchCond {
         return anyCond;
     }
 
-    public void setAnyCond(final AnyCond anyCond) {
-        this.anyCond = anyCond;
-    }
-
     public AttributeCond getAttributeCond() {
         return attributeCond;
     }
 
-    public void setAttributeCond(final AttributeCond attributeCond) {
-        this.attributeCond = attributeCond;
-    }
-
     public RelationshipCond getRelationshipCond() {
         return relationshipCond;
     }
 
-    public void setRelationshipCond(final RelationshipCond relationshipCond) {
-        this.relationshipCond = relationshipCond;
-    }
-
     public RelationshipTypeCond getRelationshipTypeCond() {
         return relationshipTypeCond;
     }
 
-    public void setRelationshipTypeCond(final RelationshipTypeCond relationshipTypeCond) {
-        this.relationshipTypeCond = relationshipTypeCond;
-    }
-
     public MembershipCond getMembershipCond() {
         return membershipCond;
     }
 
-    public void setMembershipCond(final MembershipCond membershipCond) {
-        this.membershipCond = membershipCond;
-    }
-
     public RoleCond getRoleCond() {
         return roleCond;
     }
 
-    public void setRoleCond(final RoleCond roleCond) {
-        this.roleCond = roleCond;
-    }
-
     public ResourceCond getResourceCond() {
         return resourceCond;
     }
 
-    public void setResourceCond(final ResourceCond resourceCond) {
-        this.resourceCond = resourceCond;
-    }
-
     public AssignableCond getAssignableCond() {
         return assignableCond;
     }
 
-    public void setAssignableCond(final AssignableCond assignableCond) {
-        this.assignableCond = assignableCond;
+    public MemberCond getMemberCond() {
+        return memberCond;
     }
 
     public SearchCond getLeftNodeCond() {
         return leftNodeCond;
     }
 
-    public void setLeftNodeCond(final SearchCond leftNodeCond) {
-        this.leftNodeCond = leftNodeCond;
-    }
-
     public SearchCond getRightNodeCond() {
         return rightNodeCond;
     }
 
-    public void setRightNodeCond(final SearchCond rightNodeCond) {
-        this.rightNodeCond = rightNodeCond;
-    }
-
     public Type getType() {
         return type;
     }
 
-    public void setType(final Type type) {
-        this.type = type;
-    }
-
     public String hasAnyTypeCond() {
         String anyTypeName = null;
 
@@ -346,13 +323,14 @@ public class SearchCond extends AbstractSearchCond {
             case NOT_LEAF:
                 isValid = (anyTypeCond != null || anyCond != null || attributeCond != null
                         || relationshipCond != null || relationshipTypeCond != null || membershipCond != null
-                        || roleCond != null || resourceCond != null || assignableCond != null)
+                        || roleCond != null || resourceCond != null || assignableCond != null || memberCond != null)
                         && (anyTypeCond == null || anyTypeCond.isValid())
                         && (anyCond == null || anyCond.isValid())
                         && (attributeCond == null || attributeCond.isValid())
                         && (membershipCond == null || membershipCond.isValid())
                         && (roleCond == null || roleCond.isValid())
-                        && (resourceCond == null || resourceCond.isValid());
+                        && (resourceCond == null || resourceCond.isValid())
+                        && (memberCond == null || memberCond.isValid());
                 break;
 
             case AND:

http://git-wip-us.apache.org/repos/asf/syncope/blob/31dfc1c5/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/search/SearchCondVisitor.java
----------------------------------------------------------------------
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/search/SearchCondVisitor.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/search/SearchCondVisitor.java
index ead74ac..4e8374f 100644
--- a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/search/SearchCondVisitor.java
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/search/SearchCondVisitor.java
@@ -35,6 +35,7 @@ import org.apache.syncope.core.persistence.api.dao.search.SearchCond;
 import org.apache.syncope.core.persistence.api.dao.search.AnyCond;
 import org.apache.syncope.core.persistence.api.dao.search.AnyTypeCond;
 import org.apache.syncope.core.persistence.api.dao.search.AssignableCond;
+import org.apache.syncope.core.persistence.api.dao.search.MemberCond;
 import org.apache.syncope.core.persistence.api.dao.search.RelationshipCond;
 import org.apache.syncope.core.persistence.api.dao.search.RelationshipTypeCond;
 
@@ -132,6 +133,12 @@ public class SearchCondVisitor extends AbstractSearchConditionVisitor<SearchBean
                             assignableCond.setRealmFullPath(realm);
                             leaf = SearchCond.getLeafCond(assignableCond);
                             break;
+                            
+                        case MEMBER:
+                            MemberCond memberCond = new MemberCond();
+                            memberCond.setMember(value);
+                            leaf = SearchCond.getLeafCond(memberCond);
+                            break;
 
                         default:
                             throw new IllegalArgumentException(

http://git-wip-us.apache.org/repos/asf/syncope/blob/31dfc1c5/core/persistence-api/src/test/java/org/apache/syncope/core/persistence/api/search/SearchCondConverterTest.java
----------------------------------------------------------------------
diff --git a/core/persistence-api/src/test/java/org/apache/syncope/core/persistence/api/search/SearchCondConverterTest.java b/core/persistence-api/src/test/java/org/apache/syncope/core/persistence/api/search/SearchCondConverterTest.java
index 07c2d29..6141808 100644
--- a/core/persistence-api/src/test/java/org/apache/syncope/core/persistence/api/search/SearchCondConverterTest.java
+++ b/core/persistence-api/src/test/java/org/apache/syncope/core/persistence/api/search/SearchCondConverterTest.java
@@ -32,6 +32,7 @@ import org.apache.syncope.core.persistence.api.dao.search.SearchCond;
 import org.apache.syncope.core.persistence.api.dao.search.AnyCond;
 import org.apache.syncope.core.persistence.api.dao.search.AnyTypeCond;
 import org.apache.syncope.core.persistence.api.dao.search.AssignableCond;
+import org.apache.syncope.core.persistence.api.dao.search.MemberCond;
 import org.apache.syncope.core.persistence.api.dao.search.RelationshipCond;
 import org.apache.syncope.core.persistence.api.dao.search.RelationshipTypeCond;
 import org.junit.Test;
@@ -180,6 +181,18 @@ public class SearchCondConverterTest {
     }
 
     @Test
+    public void member() {
+        String fiqlExpression = new GroupFiqlSearchConditionBuilder().withMembers("rossini").query();
+        assertEquals(SpecialAttr.MEMBER + "==rossini", fiqlExpression);
+
+        MemberCond mcond = new MemberCond();
+        mcond.setMember("rossini");
+        SearchCond simpleCond = SearchCond.getLeafCond(mcond);
+
+        assertEquals(simpleCond, SearchCondConverter.convert(fiqlExpression));
+    }
+
+    @Test
     public void and() {
         String fiqlExpression = new UserFiqlSearchConditionBuilder().
                 is("fullname").equalTo("*o*").and("fullname").equalTo("*i*").query();

http://git-wip-us.apache.org/repos/asf/syncope/blob/31dfc1c5/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 85aaddc..7c4ed1d 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
@@ -56,6 +56,7 @@ import org.apache.syncope.core.persistence.api.dao.search.SearchCond;
 import org.apache.syncope.core.persistence.api.dao.search.AnyCond;
 import org.apache.syncope.core.persistence.api.dao.search.AnyTypeCond;
 import org.apache.syncope.core.persistence.api.dao.search.AssignableCond;
+import org.apache.syncope.core.persistence.api.dao.search.MemberCond;
 import org.apache.syncope.core.persistence.api.dao.search.RelationshipCond;
 import org.apache.syncope.core.persistence.api.dao.search.RelationshipTypeCond;
 import org.apache.syncope.core.persistence.api.entity.Any;
@@ -266,7 +267,7 @@ public class JPAAnySearchDAO extends AbstractDAO<Any<?>> implements AnySearchDAO
 
     private StringBuilder buildWhere(final OrderBySupport orderBySupport, final AnyTypeKind typeKind) {
         SearchSupport svs = new SearchSupport(typeKind);
-        final StringBuilder where = new StringBuilder(" u");
+        StringBuilder where = new StringBuilder(" u");
         for (SearchSupport.SearchView searchView : orderBySupport.views) {
             where.append(',');
             if (searchView.name.equals(svs.attr().name)) {
@@ -293,7 +294,7 @@ public class JPAAnySearchDAO extends AbstractDAO<Any<?>> implements AnySearchDAO
     }
 
     private StringBuilder buildOrderBy(final OrderBySupport orderBySupport) {
-        final StringBuilder orderBy = new StringBuilder();
+        StringBuilder orderBy = new StringBuilder();
 
         for (OrderBySupport.Item obs : orderBySupport.items) {
             orderBy.append(obs.orderBy).append(',');
@@ -454,6 +455,9 @@ public class JPAAnySearchDAO extends AbstractDAO<Any<?>> implements AnySearchDAO
                 } else if (nodeCond.getRoleCond() != null && AnyTypeKind.USER == svs.anyTypeKind()) {
                     query.append(getQuery(nodeCond.getRoleCond(),
                             nodeCond.getType() == SearchCond.Type.NOT_LEAF, parameters, svs));
+                } else if (nodeCond.getMemberCond() != null && AnyTypeKind.GROUP == svs.anyTypeKind()) {
+                    query.append(getQuery(nodeCond.getMemberCond(),
+                            nodeCond.getType() == SearchCond.Type.NOT_LEAF, parameters, svs));
                 } else if (nodeCond.getResourceCond() != null) {
                     query.append(getQuery(nodeCond.getResourceCond(),
                             nodeCond.getType() == SearchCond.Type.NOT_LEAF, parameters, svs));
@@ -538,7 +542,7 @@ public class JPAAnySearchDAO extends AbstractDAO<Any<?>> implements AnySearchDAO
             query.append("any_id IN (");
         }
 
-        query.append("SELECT DISTINCT any_id ").append("FROM ").
+        query.append("SELECT DISTINCT any_id FROM ").
                 append(svs.relationship().name).append(" WHERE ").
                 append("right_any_id=?").append(setParameter(parameters, cond.getAnyObjectKey())).
                 append(')');
@@ -558,7 +562,7 @@ public class JPAAnySearchDAO extends AbstractDAO<Any<?>> implements AnySearchDAO
             query.append("any_id IN (");
         }
 
-        query.append("SELECT DISTINCT any_id ").append("FROM ").
+        query.append("SELECT DISTINCT any_id FROM ").
                 append(svs.membership().name).append(" WHERE ").
                 append("group_id=?").append(setParameter(parameters, cond.getGroupKey())).
                 append(')');
@@ -569,7 +573,7 @@ public class JPAAnySearchDAO extends AbstractDAO<Any<?>> implements AnySearchDAO
             query.append("OR any_id IN (");
         }
 
-        query.append("SELECT DISTINCT any_id ").append("FROM ").
+        query.append("SELECT DISTINCT any_id FROM ").
                 append(svs.dyngroupmembership().name).append(" WHERE ").
                 append("group_id=?").append(setParameter(parameters, cond.getGroupKey())).
                 append(')');
@@ -589,7 +593,7 @@ public class JPAAnySearchDAO extends AbstractDAO<Any<?>> implements AnySearchDAO
             query.append("any_id IN (");
         }
 
-        query.append("SELECT DISTINCT any_id ").append("FROM ").
+        query.append("SELECT DISTINCT any_id FROM ").
                 append(svs.role().name).append(" WHERE ").
                 append("role_id=?").append(setParameter(parameters, cond.getRoleKey())).
                 append(')');
@@ -600,7 +604,7 @@ public class JPAAnySearchDAO extends AbstractDAO<Any<?>> implements AnySearchDAO
             query.append("OR any_id IN (");
         }
 
-        query.append("SELECT DISTINCT any_id ").append("FROM ").
+        query.append("SELECT DISTINCT any_id FROM ").
                 append(svs.dynrolemembership().name).append(" WHERE ").
                 append("role_id=?").append(setParameter(parameters, cond.getRoleKey())).
                 append(')');
@@ -661,6 +665,37 @@ 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) {
+
+        StringBuilder query = new StringBuilder("SELECT DISTINCT any_id FROM ").
+                append(svs.field().name).append(" WHERE ");
+
+        if (not) {
+            query.append("any_id NOT IN (");
+        } else {
+            query.append("any_id IN (");
+        }
+
+        query.append("SELECT DISTINCT group_id AS any_id FROM ").
+                append(new SearchSupport(AnyTypeKind.USER).membership().name).append(" WHERE ").
+                append("any_id=?").append(setParameter(parameters, cond.getMember())).
+                append(')');
+
+        if (not) {
+            query.append(" AND any_id NOT IN (");
+        } else {
+            query.append(" OR any_id IN (");
+        }
+
+        query.append("SELECT DISTINCT group_id AS any_id FROM ").
+                append(new SearchSupport(AnyTypeKind.ANY_OBJECT).membership().name).append(" WHERE ").
+                append("any_id=?").append(setParameter(parameters, cond.getMember())).
+                append(')');
+
+        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) {
@@ -803,7 +838,6 @@ public class JPAAnySearchDAO extends AbstractDAO<Any<?>> implements AnySearchDAO
         return query.toString();
     }
 
-    @SuppressWarnings("rawtypes")
     private String getQuery(final AnyCond cond, final boolean not, final List<Object> parameters,
             final SearchSupport svs) {
 
@@ -878,7 +912,7 @@ public class JPAAnySearchDAO extends AbstractDAO<Any<?>> implements AnySearchDAO
             }
         }
 
-        final StringBuilder query = new StringBuilder("SELECT DISTINCT any_id FROM ").
+        StringBuilder query = new StringBuilder("SELECT DISTINCT any_id FROM ").
                 append(svs.field().name).append(" WHERE ");
 
         fillAttributeQuery(query, attrValue, schema, cond, not, parameters, svs);

http://git-wip-us.apache.org/repos/asf/syncope/blob/31dfc1c5/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 09e3b5a..5d64425 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
@@ -45,6 +45,7 @@ import org.apache.syncope.core.persistence.api.dao.search.SearchCond;
 import org.apache.syncope.core.persistence.api.dao.search.AnyCond;
 import org.apache.syncope.core.persistence.api.dao.search.AnyTypeCond;
 import org.apache.syncope.core.persistence.api.dao.search.AssignableCond;
+import org.apache.syncope.core.persistence.api.dao.search.MemberCond;
 import org.apache.syncope.core.persistence.api.dao.search.RelationshipCond;
 import org.apache.syncope.core.persistence.api.dao.search.RelationshipTypeCond;
 import org.apache.syncope.core.persistence.api.entity.Any;
@@ -521,6 +522,19 @@ public class AnySearchTest extends AbstractTest {
     }
 
     @Test
+    public void member() {
+        MemberCond memberCond = new MemberCond();
+        memberCond.setMember("1417acbe-cbf6-4277-9372-e75e04f97000");
+        SearchCond searchCondition = SearchCond.getLeafCond(memberCond);
+        assertTrue(searchCondition.isValid());
+
+        List<Group> groups = searchDAO.search(searchCondition, AnyTypeKind.GROUP);
+        assertEquals(2, groups.size());
+        assertTrue(groups.contains(groupDAO.findByName("root")));
+        assertTrue(groups.contains(groupDAO.findByName("otherchild")));
+    }
+
+    @Test
     public void issue202() {
         ResourceCond ws2 = new ResourceCond();
         ws2.setResourceKey("ws-target-resource-2");

http://git-wip-us.apache.org/repos/asf/syncope/blob/31dfc1c5/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 628a1ce..ce3bc3a 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
@@ -48,7 +48,8 @@ public class SearchITCase extends AbstractITCase {
     @Test
     public void searchUser() {
         // LIKE
-        PagedResult<UserTO> matchingUsers = userService.search(new AnyQuery.Builder().realm(SyncopeConstants.ROOT_REALM).
+        PagedResult<UserTO> matchingUsers = userService.search(
+                new AnyQuery.Builder().realm(SyncopeConstants.ROOT_REALM).
                 fiql(SyncopeClient.getUserSearchConditionBuilder().
                         is("fullname").equalTo("*o*").and("fullname").equalTo("*i*").query()).build());
         assertNotNull(matchingUsers);
@@ -77,7 +78,8 @@ public class SearchITCase extends AbstractITCase {
 
     @Test
     public void searchByUsernameAndKey() {
-        PagedResult<UserTO> matchingUsers = userService.search(new AnyQuery.Builder().realm(SyncopeConstants.ROOT_REALM).
+        PagedResult<UserTO> matchingUsers = userService.search(
+                new AnyQuery.Builder().realm(SyncopeConstants.ROOT_REALM).
                 fiql(SyncopeClient.getUserSearchConditionBuilder().
                         is("username").equalTo("rossini").and("key").lessThan(2).query()).build());
         assertNotNull(matchingUsers);
@@ -100,7 +102,8 @@ public class SearchITCase extends AbstractITCase {
 
     @Test
     public void searchByGroup() {
-        PagedResult<UserTO> matchingUsers = userService.search(new AnyQuery.Builder().realm(SyncopeConstants.ROOT_REALM).
+        PagedResult<UserTO> matchingUsers = userService.search(
+                new AnyQuery.Builder().realm(SyncopeConstants.ROOT_REALM).
                 fiql(SyncopeClient.getUserSearchConditionBuilder().
                         inGroups("37d15e4c-cdc1-460b-a591-8505c8133806").query()).
                 build());
@@ -123,7 +126,8 @@ public class SearchITCase extends AbstractITCase {
         group = createGroup(group).getEntity();
         assertNotNull(group);
 
-        PagedResult<UserTO> matchingUsers = userService.search(new AnyQuery.Builder().realm(SyncopeConstants.ROOT_REALM).
+        PagedResult<UserTO> matchingUsers = userService.search(
+                new AnyQuery.Builder().realm(SyncopeConstants.ROOT_REALM).
                 fiql(SyncopeClient.getUserSearchConditionBuilder().inGroups(group.getKey()).query()).
                 build());
         assertNotNull(matchingUsers);
@@ -140,7 +144,8 @@ public class SearchITCase extends AbstractITCase {
 
     @Test
     public void searchByRole() {
-        PagedResult<UserTO> matchingUsers = userService.search(new AnyQuery.Builder().realm(SyncopeConstants.ROOT_REALM).
+        PagedResult<UserTO> matchingUsers = userService.search(
+                new AnyQuery.Builder().realm(SyncopeConstants.ROOT_REALM).
                 fiql(SyncopeClient.getUserSearchConditionBuilder().inRoles("Other").query()).
                 build());
         assertNotNull(matchingUsers);
@@ -163,7 +168,8 @@ public class SearchITCase extends AbstractITCase {
         role = getObject(response.getLocation(), RoleService.class, RoleTO.class);
         assertNotNull(role);
 
-        PagedResult<UserTO> matchingUsers = userService.search(new AnyQuery.Builder().realm(SyncopeConstants.ROOT_REALM).
+        PagedResult<UserTO> matchingUsers = userService.search(
+                new AnyQuery.Builder().realm(SyncopeConstants.ROOT_REALM).
                 fiql(SyncopeClient.getUserSearchConditionBuilder().inRoles(role.getKey()).query()).
                 build());
         assertNotNull(matchingUsers);
@@ -180,7 +186,8 @@ public class SearchITCase extends AbstractITCase {
 
     @Test
     public void searchUserByResourceName() {
-        PagedResult<UserTO> matchingUsers = userService.search(new AnyQuery.Builder().realm(SyncopeConstants.ROOT_REALM).
+        PagedResult<UserTO> matchingUsers = userService.search(
+                new AnyQuery.Builder().realm(SyncopeConstants.ROOT_REALM).
                 fiql(SyncopeClient.getUserSearchConditionBuilder().hasResources(RESOURCE_NAME_MAPPINGS2).query()).
                 build());
         assertNotNull(matchingUsers);
@@ -198,7 +205,8 @@ public class SearchITCase extends AbstractITCase {
     @Test
     public void paginatedSearch() {
         // LIKE
-        PagedResult<UserTO> matchingUsers = userService.search(new AnyQuery.Builder().realm(SyncopeConstants.ROOT_REALM).
+        PagedResult<UserTO> matchingUsers = userService.search(
+                new AnyQuery.Builder().realm(SyncopeConstants.ROOT_REALM).
                 fiql(SyncopeClient.getUserSearchConditionBuilder().
                         is("fullname").equalTo("*o*").and("fullname").equalTo("*i*").query()).page(1).size(2).build());
         assertNotNull(matchingUsers);
@@ -253,7 +261,8 @@ public class SearchITCase extends AbstractITCase {
 
     @Test
     public void nested() {
-        PagedResult<UserTO> matchingUsers = userService.search(new AnyQuery.Builder().realm(SyncopeConstants.ROOT_REALM).
+        PagedResult<UserTO> matchingUsers = userService.search(
+                new AnyQuery.Builder().realm(SyncopeConstants.ROOT_REALM).
                 fiql("((fullname==*o*,fullname==*i*);$resources!=ws-target-resource-1)").page(1).size(2).build());
         assertNotNull(matchingUsers);
 
@@ -265,7 +274,8 @@ public class SearchITCase extends AbstractITCase {
 
     @Test
     public void searchByType() {
-        PagedResult<AnyObjectTO> matching = anyObjectService.search(new AnyQuery.Builder().realm(SyncopeConstants.ROOT_REALM).
+        PagedResult<AnyObjectTO> matching = anyObjectService.search(new AnyQuery.Builder().realm(
+                SyncopeConstants.ROOT_REALM).
                 fiql(SyncopeClient.getAnyObjectSearchConditionBuilder("PRINTER").query()).build());
         assertNotNull(matching);
 
@@ -283,7 +293,8 @@ public class SearchITCase extends AbstractITCase {
 
     @Test
     public void searchByRelationship() {
-        PagedResult<AnyObjectTO> anyObjects = anyObjectService.search(new AnyQuery.Builder().realm(SyncopeConstants.ROOT_REALM).
+        PagedResult<AnyObjectTO> anyObjects = anyObjectService.search(new AnyQuery.Builder().realm(
+                SyncopeConstants.ROOT_REALM).
                 fiql(SyncopeClient.getAnyObjectSearchConditionBuilder("PRINTER").
                         inRelationships("8559d14d-58c2-46eb-a2d4-a7d35161e8f8").query()).
                 build());
@@ -312,7 +323,8 @@ public class SearchITCase extends AbstractITCase {
 
     @Test
     public void searchByRelationshipType() {
-        PagedResult<AnyObjectTO> anyObjects = anyObjectService.search(new AnyQuery.Builder().realm(SyncopeConstants.ROOT_REALM).
+        PagedResult<AnyObjectTO> anyObjects = anyObjectService.search(new AnyQuery.Builder().realm(
+                SyncopeConstants.ROOT_REALM).
                 fiql(SyncopeClient.getAnyObjectSearchConditionBuilder("PRINTER").
                         inRelationshipTypes("neighborhood").query()).
                 build());
@@ -382,8 +394,33 @@ public class SearchITCase extends AbstractITCase {
     }
 
     @Test
+    public void member() {
+        PagedResult<GroupTO> groups = groupService.search(new AnyQuery.Builder().realm("/").page(1).size(1000).
+                fiql(SyncopeClient.getGroupSearchConditionBuilder().
+                        withMembers("1417acbe-cbf6-4277-9372-e75e04f97000").query()).
+                build());
+        assertNotNull(groups);
+
+        assertTrue(IterableUtils.matchesAny(groups.getResult(), new Predicate<GroupTO>() {
+
+            @Override
+            public boolean evaluate(final GroupTO group) {
+                return "root".equals(group.getName());
+            }
+        }));
+        assertTrue(IterableUtils.matchesAny(groups.getResult(), new Predicate<GroupTO>() {
+
+            @Override
+            public boolean evaluate(final GroupTO group) {
+                return "otherchild".equals(group.getName());
+            }
+        }));
+    }
+
+    @Test
     public void orderBy() {
-        PagedResult<UserTO> matchingUsers = userService.search(new AnyQuery.Builder().realm(SyncopeConstants.ROOT_REALM).
+        PagedResult<UserTO> matchingUsers = userService.search(
+                new AnyQuery.Builder().realm(SyncopeConstants.ROOT_REALM).
                 fiql(SyncopeClient.getUserSearchConditionBuilder().is("userId").equalTo("*@apache.org").query()).
                 orderBy(SyncopeClient.getOrderByClauseBuilder().asc("status").desc("firstname").build()).build());
         assertNotNull(matchingUsers);