You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@syncope.apache.org by fm...@apache.org on 2016/03/09 15:05:03 UTC

syncope git commit: [SYNCOPE-775] fixes the issue improving search panels

Repository: syncope
Updated Branches:
  refs/heads/master f171f9d31 -> 855c90915


[SYNCOPE-775] fixes the issue improving search panels


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

Branch: refs/heads/master
Commit: 855c909156532b71f5df6fb0cb7266c0cf60c1d4
Parents: f171f9d
Author: fmartelli <fa...@gmail.com>
Authored: Wed Mar 9 15:04:15 2016 +0100
Committer: fmartelli <fa...@gmail.com>
Committed: Wed Mar 9 15:04:15 2016 +0100

----------------------------------------------------------------------
 .../panels/search/AbstractSearchPanel.java      |   8 +-
 .../panels/search/AnyObjectSearchPanel.java     |  26 ++-
 .../console/panels/search/GroupSearchPanel.java |   8 +-
 .../console/panels/search/SearchClause.java     |   5 +-
 .../panels/search/SearchClausePanel.java        | 231 +++++++++++++------
 .../console/panels/search/SearchUtils.java      |  71 +++++-
 .../console/panels/search/UserSearchPanel.java  |  40 ++++
 .../html/list/ConnConfPropertyListView.java     |  23 +-
 .../client/console/wizards/any/Ownership.java   |  59 +++--
 .../console/wizards/any/Relationships.java      |   3 +-
 .../panels/search/SearchClausePanel.html        |   4 +
 .../markup/html/form/AbstractFieldPanel.html    |   1 -
 12 files changed, 336 insertions(+), 143 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/syncope/blob/855c9091/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 c23cd79..b3918e1 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
@@ -21,8 +21,8 @@ package org.apache.syncope.client.console.panels.search;
 import java.io.Serializable;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Map;
 import org.apache.commons.collections4.CollectionUtils;
-import org.apache.commons.lang3.tuple.Pair;
 import org.apache.syncope.client.console.rest.AnyTypeRestClient;
 import org.apache.syncope.client.console.rest.ResourceRestClient;
 import org.apache.syncope.client.console.rest.SchemaRestClient;
@@ -61,7 +61,9 @@ public abstract class AbstractSearchPanel extends Panel {
 
     protected IModel<List<SearchClause.Type>> types;
 
-    protected IModel<List<Pair<Long, String>>> groupNames;
+    protected IModel<Map<Long, String>> groupNames;
+
+    protected IModel<List<String>> roleNames;
 
     protected IModel<List<SearchClause>> model;
 
@@ -127,7 +129,7 @@ public abstract class AbstractSearchPanel extends Panel {
         final SearchClausePanel searchClausePanel = new SearchClausePanel("panel", "panel",
                 Model.of(new SearchClause()),
                 required,
-                types, anames, dnames, groupNames, resourceNames);
+                types, anames, dnames, groupNames, roleNames, resourceNames);
 
         if (enableSearch) {
             searchClausePanel.enableSearch();

http://git-wip-us.apache.org/repos/asf/syncope/blob/855c9091/client/console/src/main/java/org/apache/syncope/client/console/panels/search/AnyObjectSearchPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/panels/search/AnyObjectSearchPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/panels/search/AnyObjectSearchPanel.java
index 369c99b..9342fa3 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/panels/search/AnyObjectSearchPanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/search/AnyObjectSearchPanel.java
@@ -19,8 +19,9 @@
 package org.apache.syncope.client.console.panels.search;
 
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
-import org.apache.commons.lang3.tuple.Pair;
+import java.util.Map;
 import org.apache.syncope.client.console.rest.GroupRestClient;
 import org.apache.syncope.common.lib.to.GroupTO;
 import org.apache.syncope.common.lib.types.AnyTypeKind;
@@ -69,32 +70,37 @@ public class AnyObjectSearchPanel extends AbstractSearchPanel {
 
             @Override
             protected List<SearchClause.Type> load() {
-                List<SearchClause.Type> result = new ArrayList<SearchClause.Type>();
-                result.add(SearchClause.Type.ATTRIBUTE);
-                result.add(SearchClause.Type.MEMBERSHIP);
-                result.add(SearchClause.Type.RESOURCE);
-                return result;
+                return getAvailableTypes();
             }
         };
 
-        this.groupNames = new LoadableDetachableModel<List<Pair<Long, String>>>() {
+        this.groupNames = new LoadableDetachableModel<Map<Long, String>>() {
 
             private static final long serialVersionUID = 5275935387613157437L;
 
             @Override
-            protected List<Pair<Long, String>> load() {
+            protected Map<Long, String> load() {
                 List<GroupTO> groupTOs = groupRestClient.list("/",
                         -1, -1,
                         new SortParam<>("name", true),
                         null);
 
-                List<Pair<Long, String>> result = new ArrayList<>(groupTOs.size());
+                final Map<Long, String> result = new HashMap<>(groupTOs.size());
                 for (GroupTO group : groupTOs) {
-                    result.add(Pair.of(group.getKey(), group.getName()));
+                    result.put(group.getKey(), group.getName());
                 }
 
                 return result;
             }
         };
     }
+
+    protected List<SearchClause.Type> getAvailableTypes() {
+        List<SearchClause.Type> result = new ArrayList<SearchClause.Type>();
+        result.add(SearchClause.Type.ATTRIBUTE);
+        result.add(SearchClause.Type.GROUP_MEMBERSHIP);
+        result.add(SearchClause.Type.RESOURCE);
+        result.add(SearchClause.Type.RELATIONSHIP);
+        return result;
+    }
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/855c9091/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 0c68d8b..5780cf1 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
@@ -21,7 +21,7 @@ package org.apache.syncope.client.console.panels.search;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
-import org.apache.commons.lang3.tuple.Pair;
+import java.util.Map;
 import org.apache.syncope.common.lib.types.AnyTypeKind;
 import org.apache.wicket.model.IModel;
 import org.apache.wicket.model.LoadableDetachableModel;
@@ -65,13 +65,13 @@ public final class GroupSearchPanel extends AbstractSearchPanel {
             }
         };
 
-        this.groupNames = new LoadableDetachableModel<List<Pair<Long, String>>>() {
+        this.groupNames = new LoadableDetachableModel<Map<Long, String>>() {
 
             private static final long serialVersionUID = 5275935387613157437L;
 
             @Override
-            protected List<Pair<Long, String>> load() {
-                return Collections.<Pair<Long, String>>emptyList();
+            protected Map<Long, String> load() {
+                return Collections.<Long, String>emptyMap();
             }
         };
     }

http://git-wip-us.apache.org/repos/asf/syncope/blob/855c9091/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 dd46075..b5732ed 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
@@ -38,9 +38,10 @@ public final class SearchClause implements Serializable {
     public enum Type {
 
         ATTRIBUTE,
-        MEMBERSHIP,
+        GROUP_MEMBERSHIP,
+        ROLE_MEMBERSHIP,
         RESOURCE,
-        ENTITLEMENT;
+        RELATIONSHIP;
 
     }
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/855c9091/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 a57127e..c756c42 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
@@ -25,12 +25,12 @@ import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
+import java.util.Map;
 import org.apache.commons.collections4.CollectionUtils;
-import org.apache.commons.collections4.IterableUtils;
-import org.apache.commons.collections4.Predicate;
 import org.apache.commons.collections4.Transformer;
+import org.apache.commons.collections4.functors.StringValueTransformer;
 import org.apache.commons.lang3.StringUtils;
-import org.apache.commons.lang3.tuple.Pair;
+import org.apache.syncope.client.console.SyncopeConsoleSession;
 import org.apache.syncope.client.console.commons.Constants;
 import org.apache.syncope.client.console.panels.search.SearchClause.Comparator;
 import org.apache.syncope.client.console.panels.search.SearchClause.Operator;
@@ -38,6 +38,8 @@ import org.apache.syncope.client.console.panels.search.SearchClause.Type;
 import org.apache.syncope.client.console.wicket.markup.html.form.AjaxDropDownChoicePanel;
 import org.apache.syncope.client.console.wicket.markup.html.form.AjaxTextFieldPanel;
 import org.apache.syncope.client.console.wicket.markup.html.form.FieldPanel;
+import org.apache.syncope.common.lib.to.RelationshipTypeTO;
+import org.apache.syncope.common.rest.api.service.RelationshipTypeService;
 import org.apache.wicket.Component;
 import org.apache.wicket.MarkupContainer;
 import org.apache.wicket.ajax.AjaxRequestTarget;
@@ -68,7 +70,9 @@ public class SearchClausePanel extends FieldPanel<SearchClause> {
 
     private final IModel<List<String>> dnames;
 
-    private final IModel<List<Pair<Long, String>>> groupNames;
+    private final IModel<Map<Long, String>> groupNames;
+
+    private final IModel<List<String>> roleNames;
 
     private final IModel<List<String>> resourceNames;
 
@@ -76,7 +80,7 @@ public class SearchClausePanel extends FieldPanel<SearchClause> {
 
     private final LoadableDetachableModel<List<Comparator>> comparators;
 
-    private final LoadableDetachableModel<List<Pair<Long, String>>> properties;
+    private final LoadableDetachableModel<List<String>> properties;
 
     private final Fragment operatorFragment;
 
@@ -92,7 +96,8 @@ public class SearchClausePanel extends FieldPanel<SearchClause> {
             final IModel<List<SearchClause.Type>> types,
             final IModel<List<String>> anames,
             final IModel<List<String>> dnames,
-            final IModel<List<Pair<Long, String>>> groupNames,
+            final IModel<Map<Long, String>> groupNames,
+            final IModel<List<String>> roleNames,
             final IModel<List<String>> resourceNames
     ) {
 
@@ -105,6 +110,7 @@ public class SearchClausePanel extends FieldPanel<SearchClause> {
         this.anames = anames;
         this.dnames = dnames;
         this.groupNames = groupNames;
+        this.roleNames = roleNames;
         this.resourceNames = resourceNames;
 
         searchButton = new AjaxSubmitLink("search") {
@@ -144,23 +150,33 @@ public class SearchClausePanel extends FieldPanel<SearchClause> {
                     case ATTRIBUTE:
                         return Arrays.asList(SearchClause.Comparator.values());
 
-                    case MEMBERSHIP:
+                    case ROLE_MEMBERSHIP:
+                    case GROUP_MEMBERSHIP:
                     case RESOURCE:
-                        return Arrays.asList(SearchClause.Comparator.EQUALS, SearchClause.Comparator.NOT_EQUALS);
+                        return Arrays.asList(
+                                SearchClause.Comparator.EQUALS,
+                                SearchClause.Comparator.NOT_EQUALS);
+
+                    case RELATIONSHIP:
+                        return Arrays.asList(
+                                SearchClause.Comparator.IS_NOT_NULL,
+                                SearchClause.Comparator.IS_NULL,
+                                SearchClause.Comparator.EQUALS,
+                                SearchClause.Comparator.NOT_EQUALS);
                     default:
                         return Collections.<Comparator>emptyList();
                 }
             }
         };
 
-        properties = new LoadableDetachableModel<List<Pair<Long, String>>>() {
+        properties = new LoadableDetachableModel<List<String>>() {
 
             private static final long serialVersionUID = 1L;
 
             @Override
-            protected List<Pair<Long, String>> load() {
+            protected List<String> load() {
                 if (field.getModel().getObject() == null || field.getModel().getObject().getType() == null) {
-                    return Collections.<Pair<Long, String>>emptyList();
+                    return Collections.<String>emptyList();
                 }
 
                 switch (field.getModel().getObject().getType()) {
@@ -170,28 +186,39 @@ public class SearchClausePanel extends FieldPanel<SearchClause> {
                             names.addAll(anames.getObject());
                         }
                         Collections.sort(names);
-                        return CollectionUtils.collect(names, new Transformer<String, Pair<Long, String>>() {
+                        return names;
 
-                            @Override
-                            public Pair<Long, String> transform(final String input) {
-                                return Pair.of(-1L, input);
-                            }
-                        }, new ArrayList<Pair<Long, String>>());
+                    case GROUP_MEMBERSHIP:
+                        final List<String> groups = CollectionUtils.collect(groupNames.getObject().keySet(),
+                                StringValueTransformer.<Long>stringValueTransformer(), new ArrayList<String>());
 
-                    case MEMBERSHIP:
-                        return groupNames.getObject();
+                        Collections.sort(groups);
+                        return groups;
+
+                    case ROLE_MEMBERSHIP:
+                        final List<String> roles = new ArrayList<>(roleNames.getObject());
+                        Collections.sort(roles);
+                        return roles;
 
                     case RESOURCE:
-                        return CollectionUtils.collect(resourceNames.getObject(),
-                                new Transformer<String, Pair<Long, String>>() {
+                        final List<String> resources = new ArrayList<>(resourceNames.getObject());
+                        Collections.sort(resources);
+                        return resources;
+
+                    case RELATIONSHIP:
+                        final List<String> relations = CollectionUtils.collect(
+                                SyncopeConsoleSession.get().getService(RelationshipTypeService.class).list(),
+                                new Transformer<RelationshipTypeTO, String>() {
 
                             @Override
-                            public Pair<Long, String> transform(final String input) {
-                                return Pair.of(-1L, input);
+                            public String transform(final RelationshipTypeTO input) {
+                                return input.getKey();
                             }
-                        }, new ArrayList<Pair<Long, String>>());
+                        }, new ArrayList<String>());
+                        return relations;
+
                     default:
-                        return Collections.<Pair<Long, String>>emptyList();
+                        return Collections.<String>emptyList();
                 }
             }
         };
@@ -293,29 +320,18 @@ public class SearchClausePanel extends FieldPanel<SearchClause> {
             operatorContainer.add(searchButtonFragment);
         }
 
-        final AjaxDropDownChoicePanel<Pair<Long, String>> property = new AjaxDropDownChoicePanel<>(
-                "property", "property", new PropertyModel<Pair<Long, String>>(searchClause, "property") {
-
-            private static final long serialVersionUID = -8430020195995502040L;
+        final AjaxDropDownChoicePanel<String> property = new AjaxDropDownChoicePanel<>(
+                "property", "property", new PropertyModel<String>(searchClause, "property"));
+        property.hideLabel().setRequired(required).setOutputMarkupId(true);
+        property.setChoices(properties);
+        property.getField().add(new AjaxFormComponentUpdatingBehavior(Constants.ON_CHANGE) {
 
-            @Override
-            public Pair<Long, String> getObject() {
-                return Pair.of(
-                        searchClause.getType() == Type.MEMBERSHIP && searchClause.getProperty() != null
-                                ? Long.parseLong(searchClause.getProperty()) : -1L,
-                        searchClause.getProperty());
-            }
+            private static final long serialVersionUID = -1107858522700306810L;
 
             @Override
-            public void setObject(final Pair<Long, String> object) {
-                if (object != null) {
-                    searchClause.setProperty(
-                            object.getLeft() >= 0 ? String.valueOf(object.getLeft()) : object.getRight());
-                }
+            protected void onUpdate(final AjaxRequestTarget target) {
             }
         });
-        property.hideLabel().setRequired(required).setOutputMarkupId(true);
-        property.setChoices(properties);
         field.add(property);
 
         final AjaxDropDownChoicePanel<SearchClause.Comparator> comparator = new AjaxDropDownChoicePanel<>(
@@ -340,6 +356,10 @@ public class SearchClausePanel extends FieldPanel<SearchClause> {
 
             @Override
             protected void onUpdate(final AjaxRequestTarget target) {
+                final SearchClause searchClause = new SearchClause();
+                searchClause.setType(Type.valueOf(type.getDefaultModelObjectAsString()));
+                SearchClausePanel.this.clause.setObject(searchClause);
+
                 setFieldAccess(searchClause.getType(), property, comparator, value);
                 target.add(property);
                 target.add(comparator);
@@ -354,7 +374,8 @@ public class SearchClausePanel extends FieldPanel<SearchClause> {
 
             @Override
             protected void onUpdate(final AjaxRequestTarget target) {
-                if (type.getModelObject() == SearchClause.Type.ATTRIBUTE) {
+                if (type.getModelObject() == SearchClause.Type.ATTRIBUTE
+                        || type.getModelObject() == SearchClause.Type.RELATIONSHIP) {
                     if (comparator.getModelObject() == SearchClause.Comparator.IS_NULL
                             || comparator.getModelObject() == SearchClause.Comparator.IS_NOT_NULL) {
 
@@ -365,6 +386,22 @@ public class SearchClausePanel extends FieldPanel<SearchClause> {
                     }
                     target.add(value);
                 }
+
+                if (type.getModelObject() == SearchClause.Type.RELATIONSHIP) {
+                    if (comparator.getModelObject() == SearchClause.Comparator.EQUALS
+                            || comparator.getModelObject() == SearchClause.Comparator.NOT_EQUALS) {
+                        property.setEnabled(false);
+                    } else {
+                        property.setEnabled(true);
+                    }
+
+                    final SearchClause searchClause = new SearchClause();
+                    searchClause.setType(Type.valueOf(type.getDefaultModelObjectAsString()));
+                    searchClause.setComparator(comparator.getModelObject());
+                    SearchClausePanel.this.clause.setObject(searchClause);
+
+                    target.add(property);
+                }
             }
         });
 
@@ -375,11 +412,15 @@ public class SearchClausePanel extends FieldPanel<SearchClause> {
 
     private void setFieldAccess(
             final Type type,
-            final AjaxDropDownChoicePanel<Pair<Long, String>> property,
+            final AjaxDropDownChoicePanel<String> property,
             final FieldPanel<Comparator> comparator,
             final FieldPanel<String> value) {
 
         if (type != null) {
+            property.setEnabled(true);
+            comparator.setEnabled(true);
+            value.setEnabled(true);
+
             switch (type) {
                 case ATTRIBUTE:
                     if (!comparator.isEnabled()) {
@@ -391,17 +432,41 @@ public class SearchClausePanel extends FieldPanel<SearchClause> {
                             && comparator.getModelObject() != SearchClause.Comparator.IS_NOT_NULL);
                     property.setChoiceRenderer(new DefaultChoiceRender());
                     break;
-                case MEMBERSHIP:
+
+                case ROLE_MEMBERSHIP:
+                    property.setChoiceRenderer(new DefaultChoiceRender());
+                    value.setEnabled(false);
+                    value.setModelObject("");
+                    break;
+
+                case GROUP_MEMBERSHIP:
                     property.setChoiceRenderer(new GroupChoiceRender());
                     value.setEnabled(false);
                     value.setModelObject("");
                     break;
+
                 case RESOURCE:
                     property.setChoiceRenderer(new DefaultChoiceRender());
                     value.setEnabled(false);
                     value.setModelObject("");
                     break;
+
+                case RELATIONSHIP:
+                    property.setChoiceRenderer(new DefaultChoiceRender());
+                    if (comparator.getModelObject() == SearchClause.Comparator.IS_NULL
+                            || comparator.getModelObject() == SearchClause.Comparator.IS_NOT_NULL) {
+                        value.setEnabled(false);
+                        value.setModelObject("");
+                        property.setEnabled(true);
+                    } else {
+                        value.setEnabled(true);
+                        property.setEnabled(false);
+                        property.setModelObject(null);
+                    }
+                    break;
+
                 default:
+                    break;
             }
         }
     }
@@ -459,7 +524,7 @@ public class SearchClausePanel extends FieldPanel<SearchClause> {
                                 display = StringUtils.EMPTY;
                         }
                         break;
-                    case MEMBERSHIP:
+                    case GROUP_MEMBERSHIP:
                         switch (object) {
                             case EQUALS:
                                 display = "IN";
@@ -473,6 +538,7 @@ public class SearchClausePanel extends FieldPanel<SearchClause> {
                                 display = StringUtils.EMPTY;
                         }
                         break;
+                    case ROLE_MEMBERSHIP:
                     case RESOURCE:
                         switch (object) {
                             case EQUALS:
@@ -487,6 +553,28 @@ public class SearchClausePanel extends FieldPanel<SearchClause> {
                                 display = StringUtils.EMPTY;
                         }
                         break;
+                    case RELATIONSHIP:
+                        switch (object) {
+                            case IS_NOT_NULL:
+                                display = "EXIST";
+                                break;
+
+                            case IS_NULL:
+                                display = "NOT EXIST";
+                                break;
+
+                            case EQUALS:
+                                display = "WITH";
+                                break;
+
+                            case NOT_EQUALS:
+                                display = "NOT WITH";
+                                break;
+
+                            default:
+                                display = StringUtils.EMPTY;
+                        }
+                        break;
                     default:
                         display = object.toString();
                 }
@@ -502,20 +590,28 @@ public class SearchClausePanel extends FieldPanel<SearchClause> {
             public SearchClause.Comparator getObject(
                     final String id, final IModel<? extends List<? extends SearchClause.Comparator>> choices) {
 
+                if (id == null) {
+                    return SearchClause.Comparator.EQUALS;
+                }
+
                 final SearchClause.Comparator res;
                 switch (id) {
                     case "HAS":
                     case "IN":
+                    case "WITH":
                         res = SearchClause.Comparator.EQUALS;
                         break;
                     case "HAS NOT":
                     case "NOT IN":
+                    case "NOT WITH":
                         res = SearchClause.Comparator.NOT_EQUALS;
                         break;
                     case "NULL":
+                    case "NOT EXIST":
                         res = SearchClause.Comparator.IS_NULL;
                         break;
                     case "NOT NULL":
+                    case "EXIST":
                         res = SearchClause.Comparator.IS_NOT_NULL;
                         break;
                     case "==":
@@ -549,7 +645,7 @@ public class SearchClausePanel extends FieldPanel<SearchClause> {
     @Override
     public FieldPanel<SearchClause> clone() {
         final SearchClausePanel panel = new SearchClausePanel(
-                getId(), name, null, required, types, anames, dnames, groupNames, resourceNames);
+                getId(), name, null, required, types, anames, dnames, groupNames, roleNames, resourceNames);
         panel.setReadOnly(this.isReadOnly());
         panel.setRequired(this.isRequired());
         if (searchButton.isEnabled()) {
@@ -558,30 +654,23 @@ public class SearchClausePanel extends FieldPanel<SearchClause> {
         return panel;
     }
 
-    private class DefaultChoiceRender implements IChoiceRenderer<Pair<Long, String>> {
+    private class DefaultChoiceRender implements IChoiceRenderer<String> {
 
         private static final long serialVersionUID = -8034248752951761058L;
 
         @Override
-        public Object getDisplayValue(final Pair<Long, String> object) {
-            return object.getRight();
+        public Object getDisplayValue(final String object) {
+            return object;
         }
 
         @Override
-        public String getIdValue(final Pair<Long, String> object, final int index) {
-            return object.getRight();
+        public String getIdValue(final String object, final int index) {
+            return object;
         }
 
         @Override
-        public Pair<Long, String> getObject(
-                final String id, final IModel<? extends List<? extends Pair<Long, String>>> choices) {
-            return IterableUtils.find(choices.getObject(), new Predicate<Pair<Long, String>>() {
-
-                @Override
-                public boolean evaluate(final Pair<Long, String> object) {
-                    return id.equals(object.getRight());
-                }
-            });
+        public String getObject(final String id, final IModel<? extends List<? extends String>> choices) {
+            return id;
         }
     }
 
@@ -590,20 +679,18 @@ public class SearchClausePanel extends FieldPanel<SearchClause> {
         private static final long serialVersionUID = -8034248752951761058L;
 
         @Override
-        public String getIdValue(final Pair<Long, String> object, final int index) {
-            return String.valueOf(object.getLeft());
+        public String getIdValue(final String object, final int index) {
+            return object;
         }
 
         @Override
-        public Pair<Long, String> getObject(
-                final String id, final IModel<? extends List<? extends Pair<Long, String>>> choices) {
-            return IterableUtils.find(choices.getObject(), new Predicate<Pair<Long, String>>() {
+        public String getObject(final String id, final IModel<? extends List<? extends String>> choices) {
+            return id;
+        }
 
-                @Override
-                public boolean evaluate(final Pair<Long, String> object) {
-                    return id.equals(String.valueOf(object.getLeft()));
-                }
-            });
+        @Override
+        public Object getDisplayValue(final String object) {
+            return groupNames.getObject().get(Long.parseLong(object));
         }
     }
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/855c9091/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 4717779..0d53955 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
@@ -118,7 +118,7 @@ public final class SearchUtils implements Serializable {
         LOG.info("Condition: " + sc.getCondition());
 
         if (SpecialAttr.GROUPS.toString().equals(property)) {
-            res.setType(SearchClause.Type.MEMBERSHIP);
+            res.setType(SearchClause.Type.GROUP_MEMBERSHIP);
             res.setProperty(value);
         } else if (SpecialAttr.RESOURCES.toString().equals(property)) {
             res.setType(SearchClause.Type.RESOURCE);
@@ -170,11 +170,12 @@ public final class SearchUtils implements Serializable {
         boolean notTheFirst = false;
 
         for (SearchClause clause : clauses) {
-            if (clause.getType() != null && StringUtils.isNotBlank(clause.getProperty())) {
+            if (clause.getType() != null && (SearchClause.Type.RELATIONSHIP == clause.getType()
+                    || StringUtils.isNotBlank(clause.getProperty()))) {
                 prevCondition = condition;
 
                 switch (clause.getType()) {
-                    case MEMBERSHIP:
+                    case GROUP_MEMBERSHIP:
                         Long groupId = NumberUtils.toLong(clause.getProperty().split(" ")[0]);
 
                         if (builder instanceof UserFiqlSearchConditionBuilder) {
@@ -239,6 +240,70 @@ public final class SearchUtils implements Serializable {
                                 break;
                         }
                         break;
+
+                    case ROLE_MEMBERSHIP:
+                        switch (clause.getComparator()) {
+                            case EQUALS:
+                                condition = ((UserFiqlSearchConditionBuilder) builder).inRoles(clause.getProperty());
+                                break;
+                            case NOT_EQUALS:
+                                condition = ((UserFiqlSearchConditionBuilder) builder).notInRoles(clause.getProperty());
+                                break;
+                            default:
+                                break;
+                        }
+                        break;
+
+                    case RELATIONSHIP:
+                        String relationship = clause.getProperty();
+                        String value = clause.getValue();
+
+                        // This condition could be avoided by providing a refactoring of the common lib
+                        if (builder instanceof UserFiqlSearchConditionBuilder) {
+                            switch (clause.getComparator()) {
+                                case IS_NOT_NULL:
+                                    condition = ((UserFiqlSearchConditionBuilder) builder).
+                                            inRelationshipTypes(relationship);
+                                    break;
+                                case IS_NULL:
+                                    condition = ((UserFiqlSearchConditionBuilder) builder).
+                                            notInRelationshipTypes(relationship);
+                                    break;
+                                case EQUALS:
+                                    condition = ((UserFiqlSearchConditionBuilder) builder).
+                                            inRelationships(Long.parseLong(value));
+                                    break;
+                                case NOT_EQUALS:
+                                    condition = ((UserFiqlSearchConditionBuilder) builder).
+                                            notInRelationships(Long.parseLong(value));
+                                    break;
+                                default:
+                                    break;
+                            }
+                        } else {
+                            switch (clause.getComparator()) {
+                                case IS_NOT_NULL:
+                                    condition = ((AnyObjectFiqlSearchConditionBuilder) builder).
+                                            inRelationshipTypes(relationship);
+                                    break;
+                                case IS_NULL:
+                                    condition = ((AnyObjectFiqlSearchConditionBuilder) builder).
+                                            notInRelationshipTypes(relationship);
+                                    break;
+                                case EQUALS:
+                                    condition = ((AnyObjectFiqlSearchConditionBuilder) builder).
+                                            inRelationships(Long.parseLong(value));
+                                    break;
+                                case NOT_EQUALS:
+                                    condition = ((AnyObjectFiqlSearchConditionBuilder) builder).
+                                            notInRelationships(Long.parseLong(value));
+                                    break;
+                                default:
+                                    break;
+                            }
+                        }
+                        break;
+
                     default:
                         break;
                 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/855c9091/client/console/src/main/java/org/apache/syncope/client/console/panels/search/UserSearchPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/panels/search/UserSearchPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/panels/search/UserSearchPanel.java
index 2d01fc2..2949130 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/panels/search/UserSearchPanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/search/UserSearchPanel.java
@@ -18,14 +18,22 @@
  */
 package org.apache.syncope.client.console.panels.search;
 
+import java.util.ArrayList;
 import java.util.List;
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.collections4.Transformer;
+import org.apache.syncope.client.console.rest.RoleRestClient;
+import org.apache.syncope.common.lib.to.RoleTO;
 import org.apache.syncope.common.lib.types.AnyTypeKind;
 import org.apache.wicket.model.IModel;
+import org.apache.wicket.model.LoadableDetachableModel;
 
 public final class UserSearchPanel extends AnyObjectSearchPanel {
 
     private static final long serialVersionUID = -1769527800450203738L;
 
+    private final RoleRestClient roleRestClient = new RoleRestClient();
+
     public static class Builder extends AnyObjectSearchPanel.Builder {
 
         private static final long serialVersionUID = 6308997285778809578L;
@@ -44,4 +52,36 @@ public final class UserSearchPanel extends AnyObjectSearchPanel {
         super(id, AnyTypeKind.USER, builder);
     }
 
+    @Override
+    protected void populate() {
+        super.populate();
+
+        this.roleNames = new LoadableDetachableModel<List<String>>() {
+
+            private static final long serialVersionUID = 5275935387613157437L;
+
+            @Override
+            protected List<String> load() {
+                return CollectionUtils.collect(roleRestClient.list(), new Transformer<RoleTO, String>() {
+
+                    @Override
+                    public String transform(final RoleTO input) {
+                        return input.getKey();
+                    }
+                }, new ArrayList<String>());
+            }
+        };
+    }
+
+    @Override
+    protected List<SearchClause.Type> getAvailableTypes() {
+        List<SearchClause.Type> result = new ArrayList<SearchClause.Type>();
+        result.add(SearchClause.Type.ATTRIBUTE);
+        result.add(SearchClause.Type.ROLE_MEMBERSHIP);
+        result.add(SearchClause.Type.GROUP_MEMBERSHIP);
+        result.add(SearchClause.Type.RESOURCE);
+        result.add(SearchClause.Type.RELATIONSHIP);
+        return result;
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/855c9091/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/list/ConnConfPropertyListView.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/list/ConnConfPropertyListView.java b/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/list/ConnConfPropertyListView.java
index 1d173aa..f362a38 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/list/ConnConfPropertyListView.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/list/ConnConfPropertyListView.java
@@ -36,7 +36,6 @@ import org.apache.syncope.common.lib.types.ConnConfProperty;
 import org.apache.wicket.ajax.AjaxRequestTarget;
 import org.apache.wicket.ajax.form.AjaxFormComponentUpdatingBehavior;
 import org.apache.wicket.markup.ComponentTag;
-import org.apache.wicket.markup.html.basic.Label;
 import org.apache.wicket.markup.html.form.CheckBox;
 import org.apache.wicket.markup.html.form.FormComponent;
 import org.apache.wicket.markup.html.form.PasswordTextField;
@@ -70,9 +69,8 @@ public class ConnConfPropertyListView extends ListView<ConnConfProperty> {
     protected void populateItem(final ListItem<ConnConfProperty> item) {
         final ConnConfProperty property = item.getModelObject();
 
-        final Label label = new Label("connPropAttrSchema", StringUtils.isBlank(property.getSchema().getDisplayName())
-                ? property.getSchema().getName() : property.getSchema().getDisplayName());
-        item.add(label);
+        final String label = StringUtils.isBlank(property.getSchema().getDisplayName())
+                ? property.getSchema().getName() : property.getSchema().getDisplayName();
 
         final FieldPanel<? extends Serializable> field;
         boolean required = false;
@@ -82,8 +80,7 @@ public class ConnConfPropertyListView extends ListView<ConnConfProperty> {
                 || Constants.GUARDED_STRING.equalsIgnoreCase(property.getSchema().getType())
                 || Constants.GUARDED_BYTE_ARRAY.equalsIgnoreCase(property.getSchema().getType())) {
 
-            field = new AjaxPasswordFieldPanel(
-                    "panel", label.getDefaultModelObjectAsString(), new Model<String>(), false);
+            field = new AjaxPasswordFieldPanel("panel", label, new Model<String>(), false);
             ((PasswordTextField) field.getField()).setResetPassword(false);
 
             required = property.getSchema().isRequired();
@@ -102,16 +99,12 @@ public class ConnConfPropertyListView extends ListView<ConnConfProperty> {
             if (ClassUtils.isAssignable(Number.class, propertySchemaClass)) {
                 @SuppressWarnings("unchecked")
                 Class<Number> numberClass = (Class<Number>) propertySchemaClass;
-                field = new AjaxSpinnerFieldPanel.Builder<>().build(
-                        "panel", label.getDefaultModelObjectAsString(), numberClass, new Model<Number>());
-
+                field = new AjaxSpinnerFieldPanel.Builder<>().build("panel", label, numberClass, new Model<Number>());
                 required = property.getSchema().isRequired();
             } else if (ClassUtils.isAssignable(Boolean.class, propertySchemaClass)) {
-                field = new AjaxCheckBoxPanel(
-                        "panel", label.getDefaultModelObjectAsString(), new Model<Boolean>(), false);
+                field = new AjaxCheckBoxPanel("panel", label, new Model<Boolean>(), false);
             } else {
-                field = new AjaxTextFieldPanel(
-                        "panel", label.getDefaultModelObjectAsString(), new Model<String>(), false);
+                field = new AjaxTextFieldPanel("panel", label, new Model<String>(), false);
                 required = property.getSchema().isRequired();
             }
 
@@ -126,9 +119,7 @@ public class ConnConfPropertyListView extends ListView<ConnConfProperty> {
         if (isArray) {
             final MultiFieldPanel multiFieldPanel = new MultiFieldPanel.Builder(
                     new PropertyModel<List<String>>(property, "values")).setEventTemplate(true).build(
-                            "panel",
-                            label.getDefaultModelObjectAsString(),
-                            field);
+                    "panel", label, field);
             item.add(multiFieldPanel);
             fieldPanel = multiFieldPanel;
         } else {

http://git-wip-us.apache.org/repos/asf/syncope/blob/855c9091/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/Ownership.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/Ownership.java b/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/Ownership.java
index 98574b4..445564a 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/Ownership.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/Ownership.java
@@ -188,38 +188,37 @@ public class Ownership extends WizardStep {
             ownerContainer.add(userSearchFragment);
         }
 
-        final AjaxTextFieldPanel userOwner
-                = new AjaxTextFieldPanel("userOwner", "userOwner",
-                        new PropertyModel<String>(groupHandler.getInnerObject(), "userOwner") {
+        final AjaxTextFieldPanel userOwner = new AjaxTextFieldPanel(
+                "userOwner", "userOwner", new PropertyModel<String>(groupHandler.getInnerObject(), "userOwner") {
 
-                    private static final long serialVersionUID = -3743432456095828573L;
+            private static final long serialVersionUID = -3743432456095828573L;
 
-                    @Override
-                    public String getObject() {
-                        if (groupHandler.getInnerObject().getUserOwner() == null) {
-                            return StringUtils.EMPTY;
-                        } else {
-                            UserTO userTO = userRestClient.read(groupHandler.getInnerObject().getUserOwner());
-                            if (userTO == null) {
-                                return StringUtils.EMPTY;
-                            } else {
-                                return String.format("[%d] %s", userTO.getKey(), userTO.getUsername());
-                            }
-                        }
+            @Override
+            public String getObject() {
+                if (groupHandler.getInnerObject().getUserOwner() == null) {
+                    return StringUtils.EMPTY;
+                } else {
+                    UserTO userTO = userRestClient.read(groupHandler.getInnerObject().getUserOwner());
+                    if (userTO == null) {
+                        return StringUtils.EMPTY;
+                    } else {
+                        return String.format("[%d] %s", userTO.getKey(), userTO.getUsername());
                     }
+                }
+            }
 
-                    @Override
-                    public void setObject(final String object) {
-                        if (StringUtils.isBlank(object)) {
-                            groupHandler.getInnerObject().setUserOwner(null);
-                        } else {
-                            final Matcher matcher = owner.matcher(object);
-                            if (matcher.matches()) {
-                                groupHandler.getInnerObject().setUserOwner(Long.parseLong(matcher.group(1)));
-                            }
-                        }
+            @Override
+            public void setObject(final String object) {
+                if (StringUtils.isBlank(object)) {
+                    groupHandler.getInnerObject().setUserOwner(null);
+                } else {
+                    final Matcher matcher = owner.matcher(object);
+                    if (matcher.matches()) {
+                        groupHandler.getInnerObject().setUserOwner(Long.parseLong(matcher.group(1)));
                     }
-                }, false);
+                }
+            }
+        }, false);
         userOwner.setPlaceholder("userOwner");
         userOwner.hideLabel();
         userOwner.setReadOnly(true).setOutputMarkupId(true);
@@ -237,8 +236,8 @@ public class Ownership extends WizardStep {
         };
         userSearchFragment.add(userOwnerReset);
 
-        final AjaxTextFieldPanel groupOwner = new AjaxTextFieldPanel("groupOwner", "groupOwner",
-                new PropertyModel<String>(groupHandler.getInnerObject(), "groupOwner") {
+        final AjaxTextFieldPanel groupOwner = new AjaxTextFieldPanel(
+                "groupOwner", "groupOwner", new PropertyModel<String>(groupHandler.getInnerObject(), "groupOwner") {
 
             private static final long serialVersionUID = -3743432456095828573L;
 
@@ -292,7 +291,7 @@ public class Ownership extends WizardStep {
             final AjaxRequestTarget target = SearchClausePanel.SearchEvent.class.cast(event.getPayload()).getTarget();
             if (Ownership.this.isGroupOwnership.getObject()) {
                 final String fiql = SearchUtils.buildFIQL(
-                        groupSearchPanel.getModel().getObject(), SyncopeClient.getUserSearchConditionBuilder());
+                        groupSearchPanel.getModel().getObject(), SyncopeClient.getGroupSearchConditionBuilder());
                 groupSearchResultPanel.search(fiql, target);
             } else {
                 final String fiql = SearchUtils.buildFIQL(

http://git-wip-us.apache.org/repos/asf/syncope/blob/855c9091/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/Relationships.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/Relationships.java b/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/Relationships.java
index fc2a941..6764cca 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/Relationships.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/Relationships.java
@@ -177,8 +177,7 @@ public class Relationships extends WizardStep {
                 : Collections.<RelationshipTO>emptyList();
     }
 
-    private void addRelationship(
-            final Map<String, List<RelationshipTO>> relationships, final RelationshipTO... rels) {
+    private void addRelationship(final Map<String, List<RelationshipTO>> relationships, final RelationshipTO... rels) {
 
         for (RelationshipTO relationship : rels) {
             final List<RelationshipTO> listrels;

http://git-wip-us.apache.org/repos/asf/syncope/blob/855c9091/client/console/src/main/resources/org/apache/syncope/client/console/panels/search/SearchClausePanel.html
----------------------------------------------------------------------
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/panels/search/SearchClausePanel.html b/client/console/src/main/resources/org/apache/syncope/client/console/panels/search/SearchClausePanel.html
index bf8165e..683fef7 100644
--- a/client/console/src/main/resources/org/apache/syncope/client/console/panels/search/SearchClausePanel.html
+++ b/client/console/src/main/resources/org/apache/syncope/client/console/panels/search/SearchClausePanel.html
@@ -20,6 +20,10 @@ under the License.
   <head><title></title></head>
   <body>
     <wicket:extend>
+      <wicket:enclosure child="field-label">
+        <label wicket:id="field-label">[LABEL]</label><span wicket:id="required"/>
+        <span wicket:id="externalAction"/>
+      </wicket:enclosure>
       <span wicket:id="container"  class="clause">
         <div wicket:id="operatorContainer" class="field operator"><span wicket:id="operator"/></div>
         <span wicket:id="type" class="field type"/>

http://git-wip-us.apache.org/repos/asf/syncope/blob/855c9091/client/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/AbstractFieldPanel.html
----------------------------------------------------------------------
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/AbstractFieldPanel.html b/client/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/AbstractFieldPanel.html
index b3ee7bc..c1ac297 100644
--- a/client/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/AbstractFieldPanel.html
+++ b/client/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/AbstractFieldPanel.html
@@ -18,7 +18,6 @@ under the License.
 -->
 <html xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org">
   <wicket:panel>
-
     <wicket:fragment wicket:id="requiredFragment">
       <span wicket:id="requiredLabel"/>
     </wicket:fragment>