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 2015/12/09 18:10:59 UTC
[2/2] syncope git commit: [SYNCOPE-156] providing dynamic membership
[SYNCOPE-156] providing dynamic membership
Project: http://git-wip-us.apache.org/repos/asf/syncope/repo
Commit: http://git-wip-us.apache.org/repos/asf/syncope/commit/c50dae60
Tree: http://git-wip-us.apache.org/repos/asf/syncope/tree/c50dae60
Diff: http://git-wip-us.apache.org/repos/asf/syncope/diff/c50dae60
Branch: refs/heads/master
Commit: c50dae60a8404df618190c00ea57eed414ac3c66
Parents: 1e51b34
Author: fmartelli <fa...@gmail.com>
Authored: Wed Dec 9 18:10:19 2015 +0100
Committer: fmartelli <fa...@gmail.com>
Committed: Wed Dec 9 18:10:19 2015 +0100
----------------------------------------------------------------------
.../syncope/client/console/panels/Realm.java | 6 +-
.../panels/search/AbstractSearchPanel.java | 205 ++++++++
.../panels/search/AnyObjectSearchPanel.java | 92 ++++
.../console/panels/search/GroupSearchPanel.java | 77 +++
.../console/panels/search/MapOfListModel.java | 68 +++
.../console/panels/search/SearchClause.java | 129 +++++
.../panels/search/SearchClausePanel.java | 488 +++++++++++++++++++
.../console/panels/search/SearchUtils.java | 266 ++++++++++
.../console/panels/search/UserSearchPanel.java | 46 ++
.../wicket/markup/html/form/FieldPanel.java | 21 +
.../markup/html/form/MultiFieldPanel.java | 52 +-
.../console/wizards/AjaxWizardBuilder.java | 8 +-
.../console/wizards/AjaxWizardButton.java | 2 +-
.../console/wizards/AjaxWizardButtonBar.java | 10 +-
.../client/console/wizards/any/Details.java | 2 +-
.../console/wizards/any/GroupDetails.java | 119 ++++-
.../console/wizards/any/GroupWizardBuilder.java | 102 +++-
.../META-INF/resources/css/fieldstyle.css | 62 ---
.../resources/META-INF/resources/css/search.css | 75 +++
.../META-INF/resources/css/syncopeConsole.css | 1 +
.../syncope/client/console/pages/BasePage.html | 2 +-
.../panels/search/AbstractSearchPanel.html | 36 ++
.../panels/search/SearchClausePanel.html | 32 ++
.../markup/html/form/AjaxTextFieldPanel.html | 2 +-
.../console/wizards/any/GroupDetails.html | 17 +-
.../console/wizards/any/GroupDetails.properties | 4 +
.../wizards/any/GroupDetails_it.properties | 4 +
.../wizards/any/GroupDetails_pt_BR.properties | 4 +
28 files changed, 1824 insertions(+), 108 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/syncope/blob/c50dae60/client/console/src/main/java/org/apache/syncope/client/console/panels/Realm.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/panels/Realm.java b/client/console/src/main/java/org/apache/syncope/client/console/panels/Realm.java
index 626bcaa..3eb8c5b 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/panels/Realm.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/Realm.java
@@ -122,7 +122,7 @@ public class Realm extends Panel {
realmTO.getFullPath(),
anyTypeTO.getKey()).
addNewItemPanelBuilder(new UserWizardBuilder(
- BaseModal.CONTENT_ID, userTO, anyTypeTO.getClasses(), pageRef)).
+ BaseModal.CONTENT_ID, userTO, anyTypeTO.getClasses(), pageRef)).
addNotificationPanel(BasePage.class.cast(this.pageRef.getPage()).getFeedbackPanel()).
build(id);
break;
@@ -135,7 +135,7 @@ public class Realm extends Panel {
realmTO.getFullPath(),
anyTypeTO.getKey()).
addNewItemPanelBuilder(new GroupWizardBuilder(
- BaseModal.CONTENT_ID, groupTO, anyTypeTO.getClasses(), pageRef)).
+ BaseModal.CONTENT_ID, groupTO, anyTypeTO.getClasses(), pageRef)).
addNotificationPanel(BasePage.class.cast(this.pageRef.getPage()).getFeedbackPanel()).
build(id);
break;
@@ -149,7 +149,7 @@ public class Realm extends Panel {
realmTO.getFullPath(),
anyTypeTO.getKey()).
addNewItemPanelBuilder(new AnyWizardBuilder<AnyObjectTO>(
- BaseModal.CONTENT_ID, anyObjectTO, anyTypeTO.getClasses(), pageRef)).
+ BaseModal.CONTENT_ID, anyObjectTO, anyTypeTO.getClasses(), pageRef)).
addNotificationPanel(BasePage.class.cast(this.pageRef.getPage()).getFeedbackPanel()).
build(id);
break;
http://git-wip-us.apache.org/repos/asf/syncope/blob/c50dae60/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
new file mode 100644
index 0000000..90ff64c
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/search/AbstractSearchPanel.java
@@ -0,0 +1,205 @@
+/*
+ * 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.client.console.panels.search;
+
+import java.io.Serializable;
+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.panels.NotificationPanel;
+import org.apache.syncope.client.console.rest.ResourceRestClient;
+import org.apache.syncope.client.console.rest.SchemaRestClient;
+import org.apache.syncope.client.console.wicket.markup.html.form.MultiFieldPanel;
+import org.apache.syncope.common.lib.search.SearchableFields;
+import org.apache.syncope.common.lib.to.ResourceTO;
+import org.apache.syncope.common.lib.types.AnyTypeKind;
+import org.apache.wicket.feedback.FeedbackMessage;
+import org.apache.wicket.feedback.IFeedbackMessageFilter;
+import org.apache.wicket.markup.html.WebMarkupContainer;
+import org.apache.wicket.markup.html.panel.Panel;
+import org.apache.wicket.model.IModel;
+import org.apache.wicket.model.LoadableDetachableModel;
+import org.apache.wicket.model.Model;
+import org.apache.wicket.model.PropertyModel;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public abstract class AbstractSearchPanel extends Panel {
+
+ private static final long serialVersionUID = 5922413053568696414L;
+
+ /**
+ * Logger.
+ */
+ protected static final Logger LOG = LoggerFactory.getLogger(AbstractSearchPanel.class);
+
+ protected SchemaRestClient schemaRestClient = new SchemaRestClient();
+
+ protected ResourceRestClient resourceRestClient = new ResourceRestClient();
+
+// protected AuthRestClient authRestClient;
+ protected IModel<List<String>> dnames;
+
+ protected IModel<List<String>> anames;
+
+ protected IModel<List<String>> resourceNames;
+
+// protected IModel<List<String>> entitlements;
+ protected IModel<List<SearchClause.Type>> types;
+
+ protected IModel<List<String>> groupNames;
+
+ protected NotificationPanel searchFeedback;
+
+ protected PropertyModel<List<SearchClause>> model;
+
+ protected WebMarkupContainer searchFormContainer;
+
+ protected AnyTypeKind typeKind;
+
+ protected boolean required;
+
+ public abstract static class Builder<T extends AbstractSearchPanel> implements Serializable {
+
+ private static final long serialVersionUID = 6308997285778809578L;
+
+ protected final PropertyModel<List<SearchClause>> model;
+
+ protected boolean required = true;
+
+ public Builder(final PropertyModel<List<SearchClause>> model) {
+ this.model = model;
+ }
+
+ public Builder<T> required(final boolean required) {
+ this.required = required;
+ return this;
+ }
+
+ public abstract T build(final String id);
+ }
+
+ protected AbstractSearchPanel(
+ final String id,
+ final PropertyModel<List<SearchClause>> model,
+ final AnyTypeKind typeKind) {
+ this(id, model, typeKind, true);
+ }
+
+ protected AbstractSearchPanel(
+ final String id,
+ final PropertyModel<List<SearchClause>> model,
+ final AnyTypeKind typeKind,
+ final boolean required) {
+
+ super(id);
+ populate();
+
+ this.typeKind = typeKind;
+ this.required = required;
+
+ setOutputMarkupId(true);
+
+ searchFormContainer = new WebMarkupContainer("searchFormContainer");
+ searchFormContainer.setOutputMarkupId(true);
+ add(searchFormContainer);
+
+ searchFeedback = new NotificationPanel("searchFeedback", new IFeedbackMessageFilter() {
+
+ private static final long serialVersionUID = 6895024863321391672L;
+
+ @Override
+ public boolean accept(final FeedbackMessage message) {
+ boolean result;
+
+ // messages reported on the session have a null reporter
+ if (message.getReporter() == null) {
+ result = false;
+ } else {
+ // only accept messages coming from the children of the search form container
+ result = searchFormContainer.contains(message.getReporter(), true);
+ }
+
+ return result;
+ }
+ });
+ searchFeedback.setOutputMarkupId(true);
+ add(searchFeedback);
+
+ final SearchClausePanel searchClausePanel = new SearchClausePanel("panel", "panel",
+ Model.of(new SearchClause()),
+ required,
+ types, anames, dnames, groupNames, resourceNames);
+
+ final MultiFieldPanel.Builder<SearchClause> searchView = new MultiFieldPanel.Builder<SearchClause>(model) {
+
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ protected SearchClause newModelObject() {
+ return new SearchClause();
+ }
+ };
+
+ searchFormContainer.add(searchView.build("search", "search", searchClausePanel).hideLabel());
+ }
+
+ protected void populate() {
+ dnames = new LoadableDetachableModel<List<String>>() {
+
+ private static final long serialVersionUID = 5275935387613157437L;
+
+ @Override
+ protected List<String> load() {
+ return SearchableFields.get(typeKind);
+ }
+ };
+
+ anames = new LoadableDetachableModel<List<String>>() {
+
+ private static final long serialVersionUID = 5275935387613157437L;
+
+ @Override
+ protected List<String> load() {
+ return schemaRestClient.getPlainSchemaNames();
+ }
+ };
+
+ resourceNames = new LoadableDetachableModel<List<String>>() {
+
+ private static final long serialVersionUID = 5275935387613157437L;
+
+ @Override
+ protected List<String> load() {
+ return CollectionUtils.collect(resourceRestClient.getAll(), new Transformer<ResourceTO, String>() {
+
+ @Override
+ public String transform(final ResourceTO input) {
+ return input.getKey();
+ }
+ }, new ArrayList<String>());
+ }
+ };
+ }
+
+ public NotificationPanel getSearchFeedback() {
+ return searchFeedback;
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/c50dae60/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
new file mode 100644
index 0000000..16115b0
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/search/AnyObjectSearchPanel.java
@@ -0,0 +1,92 @@
+/*
+ * 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.client.console.panels.search;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.apache.syncope.client.console.rest.GroupRestClient;
+import org.apache.syncope.common.lib.to.GroupTO;
+import org.apache.syncope.common.lib.types.AnyTypeKind;
+import org.apache.wicket.extensions.markup.html.repeater.util.SortParam;
+import org.apache.wicket.model.LoadableDetachableModel;
+import org.apache.wicket.model.PropertyModel;
+
+public class AnyObjectSearchPanel extends AbstractSearchPanel {
+
+ private static final long serialVersionUID = -1769527800450203738L;
+
+ private final GroupRestClient groupRestClient = new GroupRestClient();
+
+ public static class Builder extends AbstractSearchPanel.Builder<AnyObjectSearchPanel> {
+
+ private static final long serialVersionUID = 6308997285778809578L;
+
+ public Builder(final PropertyModel<List<SearchClause>> model) {
+ super(model);
+ }
+
+ @Override
+ public AnyObjectSearchPanel build(final String id) {
+ return new AnyObjectSearchPanel(id, AnyTypeKind.ANY_OBJECT, this);
+ }
+ }
+
+ protected AnyObjectSearchPanel(final String id, final AnyTypeKind kind, final Builder builder) {
+ super(id, builder.model, kind, builder.required);
+ }
+
+ @Override
+ protected void populate() {
+ super.populate();
+
+ this.types = new LoadableDetachableModel<List<SearchClause.Type>>() {
+
+ private static final long serialVersionUID = 5275935387613157437L;
+
+ @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;
+ }
+ };
+
+ this.groupNames = new LoadableDetachableModel<List<String>>() {
+
+ private static final long serialVersionUID = 5275935387613157437L;
+
+ @Override
+ protected List<String> load() {
+ List<GroupTO> groupTOs = groupRestClient.list("/",
+ -1, -1,
+ new SortParam<>("name", true),
+ null);
+
+ List<String> result = new ArrayList<>(groupTOs.size());
+ for (GroupTO group : groupTOs) {
+ result.add(group.getName());
+ }
+
+ return result;
+ }
+ };
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/c50dae60/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
new file mode 100644
index 0000000..046e00f
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/search/GroupSearchPanel.java
@@ -0,0 +1,77 @@
+/*
+ * 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.client.console.panels.search;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import org.apache.syncope.common.lib.types.AnyTypeKind;
+import org.apache.wicket.model.LoadableDetachableModel;
+import org.apache.wicket.model.PropertyModel;
+
+public final class GroupSearchPanel extends AbstractSearchPanel {
+
+ private static final long serialVersionUID = 5757183539269316263L;
+
+ public static class Builder extends AbstractSearchPanel.Builder<GroupSearchPanel> {
+
+ private static final long serialVersionUID = 6308997285778809578L;
+
+ public Builder(final PropertyModel<List<SearchClause>> model) {
+ super(model);
+ }
+
+ @Override
+ public GroupSearchPanel build(final String id) {
+ return new GroupSearchPanel(id, this);
+ }
+ }
+
+ private GroupSearchPanel(final String id, final GroupSearchPanel.Builder builder) {
+ super(id, builder.model, AnyTypeKind.USER, builder.required);
+ }
+
+ @Override
+ protected void populate() {
+ super.populate();
+
+ this.types = new LoadableDetachableModel<List<SearchClause.Type>>() {
+
+ private static final long serialVersionUID = 5275935387613157437L;
+
+ @Override
+ protected List<SearchClause.Type> load() {
+ final List<SearchClause.Type> result = new ArrayList<SearchClause.Type>();
+ result.add(SearchClause.Type.ATTRIBUTE);
+ result.add(SearchClause.Type.RESOURCE);
+ return result;
+ }
+ };
+
+ this.groupNames = new LoadableDetachableModel<List<String>>() {
+
+ private static final long serialVersionUID = 5275935387613157437L;
+
+ @Override
+ protected List<String> load() {
+ return Collections.<String>emptyList();
+ }
+ };
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/c50dae60/client/console/src/main/java/org/apache/syncope/client/console/panels/search/MapOfListModel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/panels/search/MapOfListModel.java b/client/console/src/main/java/org/apache/syncope/client/console/panels/search/MapOfListModel.java
new file mode 100644
index 0000000..403c498
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/search/MapOfListModel.java
@@ -0,0 +1,68 @@
+/*
+ * 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.client.console.panels.search;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.wicket.core.util.lang.PropertyResolver;
+import org.apache.wicket.model.PropertyModel;
+
+public class MapOfListModel<T> extends PropertyModel<List<T>> {
+
+ private static final long serialVersionUID = -7647997536634092231L;
+
+ private final String key;
+
+ public MapOfListModel(final Object modelObject, final String expression, final String key) {
+ super(modelObject, expression);
+ this.key = key;
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public List<T> getObject() {
+ final String expression = propertyExpression();
+ final Object target = getInnermostModelOrObject();
+
+ if (target == null || StringUtils.isBlank(expression) || expression.startsWith(".")) {
+ throw new IllegalArgumentException("Property expressions cannot start with a '.' character");
+ }
+
+ final Map<String, List<T>> map = (Map<String, List<T>>) PropertyResolver.getValue(expression, target);
+
+ final List<T> res;
+ if (map.containsKey(key)) {
+ res = map.get(key);
+ } else {
+ res = new ArrayList<T>();
+ map.put(key, res);
+ }
+ return res;
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public void setObject(final List<T> object) {
+ final String expression = propertyExpression();
+ final Object target = getInnermostModelOrObject();
+ ((Map<String, List<T>>) PropertyResolver.getValue(expression, target)).put(key, object);
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/c50dae60/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
new file mode 100644
index 0000000..dd46075
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/search/SearchClause.java
@@ -0,0 +1,129 @@
+/*
+ * 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.client.console.panels.search;
+
+import java.io.Serializable;
+import org.apache.commons.lang3.builder.EqualsBuilder;
+import org.apache.commons.lang3.builder.HashCodeBuilder;
+import org.apache.commons.lang3.builder.ReflectionToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+public final class SearchClause implements Serializable {
+
+ private static final long serialVersionUID = 2010794463096110104L;
+
+ public enum Operator {
+
+ AND,
+ OR;
+
+ }
+
+ public enum Type {
+
+ ATTRIBUTE,
+ MEMBERSHIP,
+ RESOURCE,
+ ENTITLEMENT;
+
+ }
+
+ public enum Comparator {
+
+ IS_NULL,
+ IS_NOT_NULL,
+ EQUALS,
+ NOT_EQUALS,
+ GREATER_OR_EQUALS,
+ GREATER_THAN,
+ LESS_OR_EQUALS,
+ LESS_THAN;
+
+ }
+
+ private Operator operator;
+
+ private Type type;
+
+ private String property;
+
+ private Comparator comparator;
+
+ private String value;
+
+ public SearchClause() {
+ setOperator(SearchClause.Operator.AND);
+ setComparator(SearchClause.Comparator.EQUALS);
+ }
+
+ public Operator getOperator() {
+ return operator;
+ }
+
+ public void setOperator(final Operator operator) {
+ this.operator = operator;
+ }
+
+ public Type getType() {
+ return type;
+ }
+
+ public void setType(final Type type) {
+ this.type = type;
+ }
+
+ public String getProperty() {
+ return property;
+ }
+
+ public void setProperty(final String property) {
+ this.property = property;
+ }
+
+ public Comparator getComparator() {
+ return comparator;
+ }
+
+ public void setComparator(final Comparator comparator) {
+ this.comparator = comparator;
+ }
+
+ public String getValue() {
+ return value;
+ }
+
+ public void setValue(final String value) {
+ this.value = value;
+ }
+
+ @Override
+ public boolean equals(final Object obj) {
+ return EqualsBuilder.reflectionEquals(this, obj);
+ }
+
+ @Override
+ public int hashCode() {
+ return HashCodeBuilder.reflectionHashCode(this);
+ }
+
+ @Override
+ public String toString() {
+ return ReflectionToStringBuilder.toString(this, ToStringStyle.MULTI_LINE_STYLE);
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/c50dae60/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
new file mode 100644
index 0000000..561c744
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/search/SearchClausePanel.java
@@ -0,0 +1,488 @@
+/*
+ * 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.client.console.panels.search;
+
+import static org.apache.syncope.client.console.panels.search.SearchClause.Type.ATTRIBUTE;
+
+import de.agilecoders.wicket.extensions.markup.html.bootstrap.form.checkbox.bootstraptoggle.BootstrapToggle;
+import de.agilecoders.wicket.extensions.markup.html.bootstrap.form.checkbox.bootstraptoggle.BootstrapToggleConfig;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import org.apache.commons.lang3.StringUtils;
+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;
+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.wicket.Component;
+import org.apache.wicket.MarkupContainer;
+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.WebMarkupContainer;
+import org.apache.wicket.markup.html.form.CheckBox;
+import org.apache.wicket.markup.html.form.FormComponent;
+import org.apache.wicket.markup.html.form.IChoiceRenderer;
+import org.apache.wicket.markup.html.list.ListItem;
+import org.apache.wicket.model.IModel;
+import org.apache.wicket.model.LoadableDetachableModel;
+import org.apache.wicket.model.Model;
+import org.apache.wicket.model.PropertyModel;
+
+public class SearchClausePanel extends FieldPanel<SearchClause> {
+
+ private static final long serialVersionUID = -527351923968737757L;
+
+ private final boolean required;
+
+ private final IModel<List<SearchClause.Type>> types;
+
+ private final IModel<List<String>> anames;
+
+ private final IModel<List<String>> dnames;
+
+ private final IModel<List<String>> groupNames;
+
+ private final IModel<List<String>> resourceNames;
+
+ private IModel<SearchClause> clause;
+
+ private final LoadableDetachableModel<List<Comparator>> comparators;
+
+ private final LoadableDetachableModel<List<String>> properties;
+
+ public SearchClausePanel(
+ final String id,
+ final String name,
+ final Model<SearchClause> clause,
+ final boolean required,
+ final IModel<List<SearchClause.Type>> types,
+ final IModel<List<String>> anames,
+ final IModel<List<String>> dnames,
+ final IModel<List<String>> groupNames,
+ final IModel<List<String>> resourceNames
+ ) {
+
+ super(id, name, clause);
+
+ this.clause = clause == null ? new Model<SearchClause>(null) : clause;
+
+ this.required = required;
+ this.types = types;
+ this.anames = anames;
+ this.dnames = dnames;
+ this.groupNames = groupNames;
+ this.resourceNames = resourceNames;
+
+ field = new FormComponent<SearchClause>("container", this.clause) {
+
+ private static final long serialVersionUID = 1L;
+
+ };
+
+ add(field);
+
+ comparators = new LoadableDetachableModel<List<Comparator>>() {
+
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ protected List<Comparator> load() {
+ if (field.getModel().getObject() == null || field.getModel().getObject().getType() == null) {
+ return Collections.<Comparator>emptyList();
+ }
+
+ switch (field.getModel().getObject().getType()) {
+ case ATTRIBUTE:
+ return Arrays.asList(SearchClause.Comparator.values());
+
+ case MEMBERSHIP:
+ case RESOURCE:
+ return Arrays.asList(SearchClause.Comparator.EQUALS, SearchClause.Comparator.NOT_EQUALS);
+ default:
+ return Collections.<Comparator>emptyList();
+ }
+ }
+ };
+
+ properties = new LoadableDetachableModel<List<String>>() {
+
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ protected List<String> load() {
+ if (field.getModel().getObject() == null || field.getModel().getObject().getType() == null) {
+ return Collections.<String>emptyList();
+ }
+
+ switch (field.getModel().getObject().getType()) {
+ case ATTRIBUTE:
+ final List<String> names = new ArrayList<String>(dnames.getObject());
+ if (anames.getObject() != null && !anames.getObject().isEmpty()) {
+ names.addAll(anames.getObject());
+ }
+ Collections.sort(names);
+ return names;
+
+ case MEMBERSHIP:
+ return groupNames.getObject();
+
+ case RESOURCE:
+ return resourceNames.getObject();
+ default:
+ return Collections.<String>emptyList();
+ }
+ }
+ };
+ }
+
+ @Override
+ public SearchClause getModelObject() {
+ return this.clause.getObject();
+ }
+
+ @Override
+ public FieldPanel<SearchClause> setModelObject(final SearchClause object) {
+ this.clause.setObject(object);
+ return super.setModelObject(object);
+ }
+
+ @Override
+ @SuppressWarnings("rawtypes")
+ public FieldPanel<SearchClause> setNewModel(final ListItem item) {
+ clause.setObject(SearchClause.class.cast(item.getModelObject()));
+ return this;
+ }
+
+ @Override
+ public FieldPanel<SearchClause> setNewModel(final IModel<SearchClause> model) {
+ clause = model;
+ return super.setNewModel(model);
+ }
+
+ @Override
+ public final MarkupContainer add(final Component... childs) {
+ return super.add(childs);
+ }
+
+ @Override
+ public FieldPanel<SearchClause> settingsDependingComponents() {
+ final SearchClause searchClause = this.clause.getObject();
+
+ final WebMarkupContainer operatorContainer = new WebMarkupContainer("operatorContainer") {
+
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ protected void onComponentTag(final ComponentTag tag) {
+ super.onComponentTag(tag);
+ if (getIndex() == 0) {
+ tag.append("class", "glyphicon glyphicon-search", " ");
+ }
+ }
+
+ };
+
+ operatorContainer.setOutputMarkupId(true);
+
+ field.add(operatorContainer);
+
+ final BootstrapToggleConfig config = new BootstrapToggleConfig();
+ config
+ .withOnStyle(BootstrapToggleConfig.Style.info).withOffStyle(BootstrapToggleConfig.Style.warning)
+ .withSize(BootstrapToggleConfig.Size.mini)
+ .withOnLabel("AND")
+ .withOffLabel("OR");
+
+ operatorContainer.add(new BootstrapToggle("operator", new Model<Boolean>() {
+
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public Boolean getObject() {
+ return searchClause.getOperator() == Operator.AND;
+ }
+
+ @Override
+ public void setObject(final Boolean object) {
+ searchClause.setOperator(object ? Operator.AND : Operator.OR);
+ }
+ }, config) {
+
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ protected IModel<String> getOffLabel() {
+ return Model.of(getString("Off", null, "Off"));
+ }
+
+ @Override
+ protected IModel<String> getOnLabel() {
+ return Model.of(getString("On", null, "On"));
+ }
+
+ @Override
+ protected CheckBox newCheckBox(final String id, final IModel<Boolean> model) {
+ final CheckBox checkBox = super.newCheckBox(id, model);
+ checkBox.add(new AjaxFormComponentUpdatingBehavior(Constants.ON_CHANGE) {
+
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ protected void onUpdate(final AjaxRequestTarget target) {
+ }
+ });
+ return checkBox;
+ }
+ }.setVisible(getIndex() > 0).setOutputMarkupPlaceholderTag(true));
+
+ final AjaxDropDownChoicePanel<String> property = new AjaxDropDownChoicePanel<>(
+ "property", "property", new PropertyModel<String>(searchClause, "property"));
+ property.hideLabel().setRequired(required).setOutputMarkupId(true);
+ property.setChoices(properties);
+ field.add(property);
+
+ final AjaxDropDownChoicePanel<SearchClause.Comparator> comparator = new AjaxDropDownChoicePanel<>(
+ "comparator", "comparator", new PropertyModel<SearchClause.Comparator>(searchClause, "comparator"));
+ comparator.setChoices(comparators);
+ comparator.setNullValid(false).hideLabel().setOutputMarkupId(true);
+ comparator.setRequired(required);
+ comparator.setChoiceRenderer(getComparatorRender(field.getModel()));
+ field.add(comparator);
+
+ final AjaxTextFieldPanel value = new AjaxTextFieldPanel(
+ "value", "value", new PropertyModel<String>(searchClause, "value"));
+ value.hideLabel().setOutputMarkupId(true);
+ field.add(value);
+
+ final AjaxDropDownChoicePanel<SearchClause.Type> type = new AjaxDropDownChoicePanel<>(
+ "type", "type", new PropertyModel<SearchClause.Type>(searchClause, "type"));
+ type.setChoices(types).hideLabel().setRequired(required).setOutputMarkupId(true);
+ type.getField().add(new AjaxFormComponentUpdatingBehavior(Constants.ON_CHANGE) {
+
+ private static final long serialVersionUID = -1107858522700306810L;
+
+ @Override
+ protected void onUpdate(final AjaxRequestTarget target) {
+ setFieldAccess(searchClause.getType(), comparator, value);
+ target.add(property);
+ target.add(comparator);
+ target.add(value);
+ }
+ });
+ field.add(type);
+
+ comparator.getField().add(new AjaxFormComponentUpdatingBehavior(Constants.ON_CHANGE) {
+
+ private static final long serialVersionUID = -1107858522700306810L;
+
+ @Override
+ protected void onUpdate(final AjaxRequestTarget target) {
+ if (type.getModelObject() == SearchClause.Type.ATTRIBUTE) {
+ if (comparator.getModelObject() == SearchClause.Comparator.IS_NULL
+ || comparator.getModelObject() == SearchClause.Comparator.IS_NOT_NULL) {
+
+ value.setModelObject(null);
+ value.setEnabled(false);
+ } else {
+ value.setEnabled(true);
+ }
+ target.add(value);
+ }
+ }
+ });
+
+ setFieldAccess(searchClause.getType(), comparator, value);
+
+ return this;
+ }
+
+ private void setFieldAccess(
+ final Type type, final FieldPanel<Comparator> comparator, final FieldPanel<String> value) {
+ if (type != null) {
+ switch (type) {
+ case ATTRIBUTE:
+ if (!comparator.isEnabled()) {
+ comparator.setEnabled(true);
+ comparator.setRequired(true);
+ }
+
+ value.setEnabled(comparator.getModelObject() != SearchClause.Comparator.IS_NULL
+ && comparator.getModelObject() != SearchClause.Comparator.IS_NOT_NULL);
+ break;
+ default:
+ value.setEnabled(false);
+ value.setModelObject("");
+ }
+ }
+ }
+
+ private IChoiceRenderer<SearchClause.Comparator> getComparatorRender(final IModel<SearchClause> clause) {
+ return new IChoiceRenderer<SearchClause.Comparator>() {
+
+ private static final long serialVersionUID = -9086043750227867686L;
+
+ @Override
+ public Object getDisplayValue(final SearchClause.Comparator object) {
+
+ if (clause == null || clause.getObject() == null || clause.getObject().getType() == null) {
+ return object.toString();
+ }
+
+ String display;
+
+ switch (clause.getObject().getType()) {
+ case ATTRIBUTE:
+ switch (object) {
+ case IS_NULL:
+ display = "NULL";
+ break;
+
+ case IS_NOT_NULL:
+ display = "NOT NULL";
+ break;
+
+ case EQUALS:
+ display = "==";
+ break;
+
+ case NOT_EQUALS:
+ display = "!=";
+ break;
+
+ case LESS_THAN:
+ display = "<";
+ break;
+
+ case LESS_OR_EQUALS:
+ display = "<=";
+ break;
+
+ case GREATER_THAN:
+ display = ">";
+ break;
+
+ case GREATER_OR_EQUALS:
+ display = ">=";
+ break;
+
+ default:
+ display = StringUtils.EMPTY;
+ }
+ break;
+ case MEMBERSHIP:
+ switch (object) {
+ case EQUALS:
+ display = "IN";
+ break;
+
+ case NOT_EQUALS:
+ display = "NOT IN";
+ break;
+
+ default:
+ display = StringUtils.EMPTY;
+ }
+ break;
+ case RESOURCE:
+ switch (object) {
+ case EQUALS:
+ display = "HAS";
+ break;
+
+ case NOT_EQUALS:
+ display = "HAS NOT";
+ break;
+
+ default:
+ display = StringUtils.EMPTY;
+ }
+ break;
+ default:
+ display = object.toString();
+ }
+ return display;
+ }
+
+ @Override
+ public String getIdValue(final SearchClause.Comparator object, final int index) {
+ return getDisplayValue(object).toString();
+ }
+
+ @Override
+ public SearchClause.Comparator getObject(
+ final String id, final IModel<? extends List<? extends SearchClause.Comparator>> choices) {
+
+ final SearchClause.Comparator res;
+ switch (id) {
+ case "HAS":
+ case "IN":
+ res = SearchClause.Comparator.EQUALS;
+ break;
+ case "HAS NOT":
+ case "NOT IN":
+ res = SearchClause.Comparator.NOT_EQUALS;
+ break;
+ case "NULL":
+ res = SearchClause.Comparator.IS_NULL;
+ break;
+ case "NOT NULL":
+ res = SearchClause.Comparator.IS_NOT_NULL;
+ break;
+ case "==":
+ res = SearchClause.Comparator.EQUALS;
+ break;
+ case "!=":
+ res = SearchClause.Comparator.NOT_EQUALS;
+ break;
+ case "<":
+ res = SearchClause.Comparator.LESS_THAN;
+ break;
+ case "<=":
+ res = SearchClause.Comparator.LESS_OR_EQUALS;
+ break;
+ case ">":
+ res = SearchClause.Comparator.GREATER_THAN;
+ break;
+ case ">=":
+ res = SearchClause.Comparator.GREATER_OR_EQUALS;
+ break;
+ default:
+ // EQUALS to be used as default value
+ res = SearchClause.Comparator.EQUALS;
+ break;
+ }
+ return res;
+ }
+ };
+ }
+
+ @Override
+ public FieldPanel<SearchClause> clone() {
+ final SearchClausePanel panel = new SearchClausePanel(
+ getId(), name, null, required, types, anames, dnames, groupNames, resourceNames);
+ panel.setReadOnly(this.isReadOnly());
+ panel.setRequired(this.isRequired());
+ return panel;
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/c50dae60/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
new file mode 100644
index 0000000..bfbe314
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/search/SearchUtils.java
@@ -0,0 +1,266 @@
+/*
+ * 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.client.console.panels.search;
+
+import static org.apache.syncope.client.console.panels.search.AbstractSearchPanel.LOG;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.math.NumberUtils;
+import org.apache.cxf.jaxrs.ext.search.ConditionType;
+import org.apache.cxf.jaxrs.ext.search.SearchBean;
+import org.apache.cxf.jaxrs.ext.search.SearchCondition;
+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.SpecialAttr;
+import org.apache.syncope.common.lib.search.SyncopeProperty;
+import org.apache.syncope.common.lib.search.UserFiqlSearchConditionBuilder;
+
+public final class SearchUtils implements Serializable {
+
+ private static final long serialVersionUID = 398381905376547084L;
+
+ private SearchUtils() {
+
+ }
+
+ public static Map<String, List<SearchClause>> getSearchClauses(final Map<String, String> fiql) {
+ final Map<String, List<SearchClause>> res = new HashMap<>();
+ if (fiql != null && !fiql.isEmpty()) {
+ for (Map.Entry<String, String> entry : fiql.entrySet()) {
+ res.put(entry.getKey(), getSearchClauses(entry.getValue()));
+ }
+ }
+ return res;
+ }
+
+ public static List<SearchClause> getSearchClauses(final String fiql) {
+ final List<SearchClause> res = new ArrayList<>();
+ if (StringUtils.isNotBlank(fiql)) {
+ try {
+ FiqlParser<SearchBean> fiqlParser = new FiqlParser<>(
+ SearchBean.class, AbstractFiqlSearchConditionBuilder.CONTEXTUAL_PROPERTIES);
+ res.addAll(getSearchClauses(fiqlParser.parse(fiql)));
+ } catch (Exception e) {
+ LOG.error("Unparseable FIQL expression '{}'", fiql, e);
+ }
+ }
+ return res;
+ }
+
+ public static List<SearchClause> getSearchClauses(final SearchCondition<SearchBean> sc) {
+ List<SearchClause> res = new ArrayList<SearchClause>();
+
+ if (sc.getStatement() == null) {
+ res.addAll(getCompoundSearchClause(sc));
+ } else {
+ res.add(getPrimitiveSearchClause(sc));
+ }
+
+ return res;
+ }
+
+ public static List<SearchClause> getCompoundSearchClause(final SearchCondition<SearchBean> sc) {
+ List<SearchClause> res = new ArrayList<SearchClause>();
+
+ for (SearchCondition<SearchBean> searchCondition : sc.getSearchConditions()) {
+ if (searchCondition.getStatement() == null) {
+ res.addAll(getCompoundSearchClause(searchCondition));
+ } else {
+ SearchClause clause = getPrimitiveSearchClause(searchCondition);
+ if (sc.getConditionType() == ConditionType.AND) {
+ clause.setOperator(SearchClause.Operator.AND);
+ }
+ if (sc.getConditionType() == ConditionType.OR) {
+ clause.setOperator(SearchClause.Operator.OR);
+ }
+ res.add(clause);
+ }
+ }
+
+ return res;
+ }
+
+ public static SearchClause getPrimitiveSearchClause(final SearchCondition<SearchBean> sc) {
+ SearchClause res = new SearchClause();
+
+ String property = sc.getCondition().getKeySet().iterator().next();
+ res.setProperty(property);
+ String value = sc.getCondition().get(property);
+ res.setValue(value);
+
+ LOG.info("Condition: " + sc.getCondition());
+
+ if (SpecialAttr.GROUPS.toString().equals(property)) {
+ res.setType(SearchClause.Type.MEMBERSHIP);
+ // check if the following is really required
+
+// for (String label : groupNames.getObject()) {
+// if (value.equals(label.substring(0, label.indexOf(' ')))) {
+// searchClause.setProperty(label);
+// }
+// }
+ } else if (SpecialAttr.RESOURCES.toString().equals(property)) {
+ res.setType(SearchClause.Type.RESOURCE);
+ res.setProperty(value);
+ } else {
+ res.setType(SearchClause.Type.ATTRIBUTE);
+ }
+
+ switch (sc.getConditionType()) {
+ case EQUALS:
+ res.setComparator(SpecialAttr.NULL.toString().equals(value)
+ ? SearchClause.Comparator.IS_NULL : SearchClause.Comparator.EQUALS);
+ break;
+
+ case NOT_EQUALS:
+ res.setComparator(SpecialAttr.NULL.toString().equals(value)
+ ? SearchClause.Comparator.IS_NOT_NULL : SearchClause.Comparator.NOT_EQUALS);
+ break;
+
+ case GREATER_OR_EQUALS:
+ res.setComparator(SearchClause.Comparator.GREATER_OR_EQUALS);
+ break;
+
+ case GREATER_THAN:
+ res.setComparator(SearchClause.Comparator.GREATER_THAN);
+ break;
+
+ case LESS_OR_EQUALS:
+ res.setComparator(SearchClause.Comparator.LESS_OR_EQUALS);
+ break;
+
+ case LESS_THAN:
+ res.setComparator(SearchClause.Comparator.LESS_THAN);
+ break;
+
+ default:
+ break;
+ }
+
+ return res;
+ }
+
+ public static String buildFIQL(final List<SearchClause> clauses, final AbstractFiqlSearchConditionBuilder builder) {
+ LOG.debug("Generating FIQL from List<SearchClause>: {}", clauses);
+
+ CompleteCondition prevCondition;
+ CompleteCondition condition = null;
+
+ boolean notTheFirst = false;
+
+ for (SearchClause clause : clauses) {
+ if (clause.getType() != null && StringUtils.isNotBlank(clause.getProperty())) {
+ prevCondition = condition;
+
+ switch (clause.getType()) {
+ case MEMBERSHIP:
+ Long groupId = NumberUtils.toLong(clause.getProperty().split(" ")[0]);
+
+ if (builder instanceof UserFiqlSearchConditionBuilder) {
+ condition = clause.getComparator() == SearchClause.Comparator.EQUALS
+ ? ((UserFiqlSearchConditionBuilder) builder).inGroups(groupId)
+ : ((UserFiqlSearchConditionBuilder) builder).notInGroups(groupId);
+ } else {
+ condition = clause.getComparator() == SearchClause.Comparator.EQUALS
+ ? ((AnyObjectFiqlSearchConditionBuilder) builder).inGroups(groupId)
+ : ((AnyObjectFiqlSearchConditionBuilder) builder).notInGroups(groupId);
+ }
+ break;
+
+ case RESOURCE:
+ condition = clause.getComparator() == SearchClause.Comparator.EQUALS
+ ? builder.hasResources(clause.getProperty())
+ : builder.hasNotResources(clause.getProperty());
+ break;
+
+ case ATTRIBUTE:
+ SyncopeProperty property = builder.is(clause.getProperty());
+ switch (clause.getComparator()) {
+ case IS_NULL:
+ condition = builder.isNull(clause.getProperty());
+ break;
+
+ case IS_NOT_NULL:
+ condition = builder.isNotNull(clause.getProperty());
+ break;
+
+ case LESS_THAN:
+ condition = StringUtils.isNumeric(clause.getProperty())
+ ? property.lessThan(NumberUtils.toDouble(clause.getValue()))
+ : property.lexicalBefore(clause.getValue());
+ break;
+
+ case LESS_OR_EQUALS:
+ condition = StringUtils.isNumeric(clause.getProperty())
+ ? property.lessOrEqualTo(NumberUtils.toDouble(clause.getValue()))
+ : property.lexicalNotAfter(clause.getValue());
+ break;
+
+ case GREATER_THAN:
+ condition = StringUtils.isNumeric(clause.getProperty())
+ ? property.greaterThan(NumberUtils.toDouble(clause.getValue()))
+ : property.lexicalAfter(clause.getValue());
+ break;
+
+ case GREATER_OR_EQUALS:
+ condition = StringUtils.isNumeric(clause.getProperty())
+ ? property.greaterOrEqualTo(NumberUtils.toDouble(clause.getValue()))
+ : property.lexicalNotBefore(clause.getValue());
+ break;
+
+ case NOT_EQUALS:
+ condition = property.notEqualTo(clause.getValue());
+ break;
+
+ case EQUALS:
+ default:
+ condition = property.equalTo(clause.getValue());
+ break;
+ }
+ 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);
+ }
+ }
+
+ notTheFirst = true;
+ }
+ }
+
+ String fiql = condition == null ? null : condition.query();
+ LOG.debug("Generated FIQL: {}", fiql);
+
+ return fiql;
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/c50dae60/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
new file mode 100644
index 0000000..bf6a4fc
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/search/UserSearchPanel.java
@@ -0,0 +1,46 @@
+/*
+ * 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.client.console.panels.search;
+
+import java.util.List;
+import org.apache.syncope.common.lib.types.AnyTypeKind;
+import org.apache.wicket.model.PropertyModel;
+
+public final class UserSearchPanel extends AnyObjectSearchPanel {
+
+ private static final long serialVersionUID = -1769527800450203738L;
+
+ public static class Builder extends AnyObjectSearchPanel.Builder {
+
+ private static final long serialVersionUID = 6308997285778809578L;
+
+ public Builder(final PropertyModel<List<SearchClause>> model) {
+ super(model);
+ }
+
+ @Override
+ public UserSearchPanel build(final String id) {
+ return new UserSearchPanel(id, this);
+ }
+ }
+
+ private UserSearchPanel(final String id, final Builder builder) {
+ super(id, AnyTypeKind.USER, builder);
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/c50dae60/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/FieldPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/FieldPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/FieldPanel.java
index 5a44086..1d5171c 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/FieldPanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/FieldPanel.java
@@ -37,6 +37,8 @@ public abstract class FieldPanel<T extends Serializable> extends AbstractFieldPa
protected String title = null;
+ private final Model<Integer> index = Model.of(0);
+
public FieldPanel(final String id, final IModel<T> model) {
this(id, id, model);
}
@@ -164,6 +166,25 @@ public abstract class FieldPanel<T extends Serializable> extends AbstractFieldPa
});
}
+ public FieldPanel<T> setIndex(final int index) {
+ this.index.setObject(index);
+ return this;
+ }
+
+ public int getIndex() {
+ return index.getObject();
+ }
+
+ /**
+ * To be overridded to add settings depending components.
+ * It has to be used by default to add components depending by index model.
+ *
+ * @return the current field panel.
+ */
+ public FieldPanel<T> settingsDependingComponents() {
+ return this;
+ }
+
@Override
@SuppressWarnings("unchecked")
public FieldPanel<T> clone() {
http://git-wip-us.apache.org/repos/asf/syncope/blob/c50dae60/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/MultiFieldPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/MultiFieldPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/MultiFieldPanel.java
index 7b7ffcb..906ea02 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/MultiFieldPanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/MultiFieldPanel.java
@@ -34,7 +34,7 @@ import org.apache.wicket.markup.html.panel.Fragment;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.ResourceModel;
-public final class MultiFieldPanel<E extends Serializable> extends AbstractFieldPanel<List<E>> {
+public abstract class MultiFieldPanel<E extends Serializable> extends AbstractFieldPanel<List<E>> {
private static final long serialVersionUID = -6322397761456513324L;
@@ -71,7 +71,8 @@ public final class MultiFieldPanel<E extends Serializable> extends AbstractField
container.add(form);
// -----------------------
- if (model.getObject() != null && model.getObject().isEmpty()) {
+ final List<E> obj = model.getObject();
+ if (obj == null || obj.isEmpty()) {
form.addOrReplace(getNoDataFragment(model, name));
} else {
form.addOrReplace(getDataFragment(model, name));
@@ -94,8 +95,10 @@ public final class MultiFieldPanel<E extends Serializable> extends AbstractField
@Override
protected void populateItem(final ListItem<E> item) {
-
final FieldPanel<? extends Serializable> fieldPanel = panelTemplate.clone();
+ fieldPanel.setIndex(item.getIndex());
+ fieldPanel.setNewModel(item);
+ fieldPanel.settingsDependingComponents();
if (eventTemplate) {
fieldPanel.getField().add(new AjaxFormComponentUpdatingBehavior(Constants.ON_CHANGE) {
@@ -109,7 +112,6 @@ public final class MultiFieldPanel<E extends Serializable> extends AbstractField
});
}
- fieldPanel.setNewModel(item);
item.add(fieldPanel.hideLabel().setRenderBodyOnly(true));
final AjaxSubmitLink minus = new AjaxSubmitLink("drop") {
@@ -132,6 +134,12 @@ public final class MultiFieldPanel<E extends Serializable> extends AbstractField
send(getPage(), Broadcast.BREADTH, new MultiValueSelectorEvent(target));
}
}
+
+ @Override
+ protected void onError(final AjaxRequestTarget target, final Form<?> form) {
+ error(getString(Constants.OPERATION_ERROR));
+ super.onError(target, form);
+ }
};
item.add(minus);
@@ -143,7 +151,7 @@ public final class MultiFieldPanel<E extends Serializable> extends AbstractField
fragment = new Fragment("panelPlus", "emptyFragment", MultiFieldPanel.this);
}
- item.add(fragment);
+ item.add(fragment.setRenderBodyOnly(true));
}
};
@@ -160,7 +168,7 @@ public final class MultiFieldPanel<E extends Serializable> extends AbstractField
@Override
protected void onSubmit(final AjaxRequestTarget target, final Form<?> form) {
//Add current component
- model.getObject().add(null);
+ model.getObject().add(newModelObject());
if (model.getObject().size() == 1) {
form.addOrReplace(getDataFragment(model, label));
@@ -168,6 +176,12 @@ public final class MultiFieldPanel<E extends Serializable> extends AbstractField
target.add(container);
}
+
+ @Override
+ protected void onError(final AjaxRequestTarget target, final Form<?> form) {
+ error(getString(Constants.OPERATION_ERROR));
+ super.onError(target, form);
+ }
};
final Fragment fragment = new Fragment("panelPlus", "fragmentPlus", MultiFieldPanel.this);
@@ -200,7 +214,11 @@ public final class MultiFieldPanel<E extends Serializable> extends AbstractField
}
}
- public static class Builder<E extends Serializable> {
+ protected abstract E newModelObject();
+
+ public static class Builder<E extends Serializable> implements Serializable {
+
+ private static final long serialVersionUID = 1L;
private final IModel<List<E>> model;
@@ -261,8 +279,26 @@ public final class MultiFieldPanel<E extends Serializable> extends AbstractField
return this;
}
+ /**
+ * Default model object instance.
+ *
+ * @return default model object instance.
+ */
+ protected E newModelObject() {
+ return null;
+ }
+
public MultiFieldPanel<E> build(final String id, final String name, final FieldPanel<E> panelTemplate) {
- return new MultiFieldPanel<>(id, name, model, panelTemplate, eventTemplate);
+ return new MultiFieldPanel<E>(id, name, model, panelTemplate, eventTemplate) {
+
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ protected E newModelObject() {
+ return Builder.this.newModelObject();
+ }
+
+ };
}
}
}
http://git-wip-us.apache.org/repos/asf/syncope/blob/c50dae60/client/console/src/main/java/org/apache/syncope/client/console/wizards/AjaxWizardBuilder.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wizards/AjaxWizardBuilder.java b/client/console/src/main/java/org/apache/syncope/client/console/wizards/AjaxWizardBuilder.java
index ec4ccd9..173e4d5 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/wizards/AjaxWizardBuilder.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wizards/AjaxWizardBuilder.java
@@ -20,7 +20,9 @@ import org.apache.commons.lang3.SerializationUtils;
import org.apache.wicket.PageReference;
import org.apache.wicket.extensions.wizard.WizardModel;
-public abstract class AjaxWizardBuilder<T extends Serializable> {
+public abstract class AjaxWizardBuilder<T extends Serializable> implements Serializable {
+
+ private static final long serialVersionUID = 5241745929825564456L;
private final String id;
@@ -81,6 +83,10 @@ public abstract class AjaxWizardBuilder<T extends Serializable> {
return item;
}
+ public T getDefaultItem() {
+ return defaultItem;
+ }
+
private T newModelObject() {
if (item == null) {
// keep the original item: the which one before the changes performed during wizard browsing
http://git-wip-us.apache.org/repos/asf/syncope/blob/c50dae60/client/console/src/main/java/org/apache/syncope/client/console/wizards/AjaxWizardButton.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wizards/AjaxWizardButton.java b/client/console/src/main/java/org/apache/syncope/client/console/wizards/AjaxWizardButton.java
index 0732f3a..b9f1325 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/wizards/AjaxWizardButton.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wizards/AjaxWizardButton.java
@@ -24,7 +24,7 @@ import org.apache.wicket.model.ResourceModel;
public abstract class AjaxWizardButton extends AjaxButton {
- private static final long serialVersionUID = 1L;
+ private static final long serialVersionUID = -9147736051493629209L;
private final IWizard wizard;
http://git-wip-us.apache.org/repos/asf/syncope/blob/c50dae60/client/console/src/main/java/org/apache/syncope/client/console/wizards/AjaxWizardButtonBar.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wizards/AjaxWizardButtonBar.java b/client/console/src/main/java/org/apache/syncope/client/console/wizards/AjaxWizardButtonBar.java
index 0719c50..2711e28 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/wizards/AjaxWizardButtonBar.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wizards/AjaxWizardButtonBar.java
@@ -24,14 +24,14 @@ import org.apache.wicket.markup.html.form.Form;
public class AjaxWizardButtonBar extends WizardButtonBar {
- private static final long serialVersionUID = 1L;
+ private static final long serialVersionUID = 5641095671558703391L;
public AjaxWizardButtonBar(final String id, final AjaxWizard<?> wizard, final boolean edit) {
super(id, wizard);
addOrReplace(new AjaxWizardButton("next", wizard, "next") {
- private static final long serialVersionUID = 1L;
+ private static final long serialVersionUID = 1773811852118436784L;
@Override
protected void onClick(final AjaxRequestTarget target, final Form<?> form) {
@@ -66,7 +66,7 @@ public class AjaxWizardButtonBar extends WizardButtonBar {
addOrReplace(new AjaxWizardButton("previous", wizard, "prev", false) {
- private static final long serialVersionUID = 1L;
+ private static final long serialVersionUID = 5704878742768853867L;
@Override
protected void onClick(final AjaxRequestTarget target, final Form<?> form) {
@@ -83,7 +83,7 @@ public class AjaxWizardButtonBar extends WizardButtonBar {
addOrReplace(new AjaxWizardButton("cancel", wizard, "cancel", false) {
- private static final long serialVersionUID = 1L;
+ private static final long serialVersionUID = 5704878742768853867L;
@Override
protected void onClick(final AjaxRequestTarget target, final Form<?> form) {
@@ -99,7 +99,7 @@ public class AjaxWizardButtonBar extends WizardButtonBar {
addOrReplace(new AjaxWizardButton("finish", wizard, "finish") {
- private static final long serialVersionUID = 1L;
+ private static final long serialVersionUID = 1773811852118436784L;
@Override
protected void onClick(final AjaxRequestTarget target, final Form<?> form) {
http://git-wip-us.apache.org/repos/asf/syncope/blob/c50dae60/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/Details.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/Details.java b/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/Details.java
index 2e967f4..974d3dd 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/Details.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/Details.java
@@ -27,7 +27,7 @@ import org.apache.wicket.model.IModel;
public class Details<T extends AnyTO> extends WizardStep {
- private static final long serialVersionUID = 6592027822510220463L;
+ private static final long serialVersionUID = -8995647450549098844L;
protected final PageReference pageRef;
http://git-wip-us.apache.org/repos/asf/syncope/blob/c50dae60/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/GroupDetails.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/GroupDetails.java b/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/GroupDetails.java
index 582e56b..9705fc4 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/GroupDetails.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/GroupDetails.java
@@ -18,12 +18,24 @@
*/
package org.apache.syncope.client.console.wizards.any;
+import de.agilecoders.wicket.core.markup.html.bootstrap.tabs.Collapsible;
+import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.collections4.Predicate;
+import org.apache.commons.lang3.StringUtils;
import org.apache.syncope.client.console.commons.JexlHelpUtils;
import org.apache.syncope.client.console.commons.status.StatusBean;
+import org.apache.syncope.client.console.panels.search.AnyObjectSearchPanel;
+import org.apache.syncope.client.console.panels.search.MapOfListModel;
+import org.apache.syncope.client.console.panels.search.SearchClause;
+import org.apache.syncope.client.console.panels.search.UserSearchPanel;
+import org.apache.syncope.client.console.rest.AnyTypeRestClient;
import org.apache.syncope.client.console.rest.GroupRestClient;
import org.apache.syncope.client.console.rest.UserRestClient;
import org.apache.syncope.client.console.wicket.markup.html.form.AjaxTextFieldPanel;
+import org.apache.syncope.common.lib.to.AnyTypeTO;
import org.apache.syncope.common.lib.to.GroupTO;
import org.apache.syncope.common.lib.to.UserTO;
import org.apache.syncope.common.lib.types.AnyTypeKind;
@@ -34,9 +46,18 @@ import org.apache.wicket.ajax.markup.html.AjaxLink;
import org.apache.wicket.event.IEvent;
import org.apache.wicket.extensions.ajax.markup.html.IndicatingAjaxLink;
import org.apache.wicket.extensions.ajax.markup.html.modal.ModalWindow;
+import org.apache.wicket.extensions.markup.html.tabs.AbstractTab;
+import org.apache.wicket.extensions.markup.html.tabs.ITab;
import org.apache.wicket.markup.html.WebMarkupContainer;
+import org.apache.wicket.markup.html.list.ListItem;
+import org.apache.wicket.markup.html.list.ListView;
+import org.apache.wicket.markup.html.panel.Panel;
import org.apache.wicket.model.IModel;
+import org.apache.wicket.model.LoadableDetachableModel;
+import org.apache.wicket.model.Model;
import org.apache.wicket.model.PropertyModel;
+import org.apache.wicket.model.ResourceModel;
+import org.apache.wicket.model.StringResourceModel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -50,11 +71,13 @@ public class GroupDetails extends Details<GroupTO> {
private final GroupRestClient groupRestClient = new GroupRestClient();
+ private final AnyTypeRestClient anyTypeRestClient = new AnyTypeRestClient();
+
private final WebMarkupContainer ownerContainer;
- private final OwnerModel userOwnerModel;
+ private final OwnerModel uOwnerModel;
- private final OwnerModel groupOwnerModel;
+ private final OwnerModel gOwnerModel;
public GroupDetails(
final GroupTO groupTO,
@@ -64,6 +87,22 @@ public class GroupDetails extends Details<GroupTO> {
final boolean includeStatusPanel) {
super(groupTO, statusModel, pageRef, includeStatusPanel);
+ final LoadableDetachableModel<List<AnyTypeTO>> types = new LoadableDetachableModel<List<AnyTypeTO>>() {
+
+ private static final long serialVersionUID = 5275935387613157437L;
+
+ @Override
+ protected List<AnyTypeTO> load() {
+ return CollectionUtils.select(anyTypeRestClient.getAll(), new Predicate<AnyTypeTO>() {
+
+ @Override
+ public boolean evaluate(final AnyTypeTO t) {
+ return AnyTypeKind.USER != t.getKind() && AnyTypeKind.GROUP != t.getKind();
+ }
+ }, new ArrayList<AnyTypeTO>());
+ }
+ };
+
ownerContainer = new WebMarkupContainer("ownerContainer");
ownerContainer.setOutputMarkupId(true);
this.add(ownerContainer);
@@ -77,8 +116,8 @@ public class GroupDetails extends Details<GroupTO> {
groupOwnerSelectWin.setCookieName("create-groupOwnerSelect-modal");
this.add(groupOwnerSelectWin);
- final AjaxTextFieldPanel name =
- new AjaxTextFieldPanel("name", "name", new PropertyModel<String>(groupTO, "name"), false);
+ final AjaxTextFieldPanel name = new AjaxTextFieldPanel("name", "name",
+ new PropertyModel<String>(groupTO, "name"), false);
final WebMarkupContainer jexlHelp = JexlHelpUtils.getJexlHelpWebContainer("jexlHelp");
@@ -92,11 +131,12 @@ public class GroupDetails extends Details<GroupTO> {
}
this.add(name);
- userOwnerModel = new OwnerModel(groupTO, AnyTypeKind.USER);
+ uOwnerModel = new OwnerModel(groupTO, AnyTypeKind.USER);
@SuppressWarnings("unchecked")
- final AjaxTextFieldPanel userOwner = new AjaxTextFieldPanel("userOwner", "userOwner", userOwnerModel, false);
- userOwner.setReadOnly(true);
- userOwner.setOutputMarkupId(true);
+ final AjaxTextFieldPanel userOwner = new AjaxTextFieldPanel("userOwner", "userOwner", uOwnerModel, false);
+ userOwner.setPlaceholder("userOwner");
+ userOwner.hideLabel();
+ userOwner.setReadOnly(true).setOutputMarkupId(true);
ownerContainer.add(userOwner);
final AjaxLink<Void> userOwnerSelect = new IndicatingAjaxLink<Void>("userOwnerSelect") {
@@ -124,18 +164,18 @@ public class GroupDetails extends Details<GroupTO> {
@Override
public void onClick(final AjaxRequestTarget target) {
- userOwnerModel.setObject(null);
+ uOwnerModel.setObject(null);
target.add(userOwner);
}
};
ownerContainer.add(userOwnerReset.setEnabled(false));
- groupOwnerModel = new OwnerModel(groupTO, AnyTypeKind.GROUP);
+ gOwnerModel = new OwnerModel(groupTO, AnyTypeKind.GROUP);
@SuppressWarnings("unchecked")
- final AjaxTextFieldPanel groupOwner =
- new AjaxTextFieldPanel("groupOwner", "groupOwner", groupOwnerModel, false);
- groupOwner.setReadOnly(true);
- groupOwner.setOutputMarkupId(true);
+ final AjaxTextFieldPanel groupOwner = new AjaxTextFieldPanel("groupOwner", "groupOwner", gOwnerModel, false);
+ groupOwner.setPlaceholder("groupOwner");
+ groupOwner.hideLabel();
+ groupOwner.setReadOnly(true).setOutputMarkupId(true);
ownerContainer.add(groupOwner);
final AjaxLink<Void> groupOwnerSelect = new IndicatingAjaxLink<Void>("groupOwnerSelect") {
@@ -164,11 +204,56 @@ public class GroupDetails extends Details<GroupTO> {
@Override
public void onClick(final AjaxRequestTarget target) {
- groupOwnerModel.setObject(null);
+ gOwnerModel.setObject(null);
target.add(groupOwner);
}
};
ownerContainer.add(groupOwnerReset.setEnabled(false));
+
+ // ------------------------
+ // uDynMembershipCond
+ // ------------------------
+ add(new Collapsible("uDynMembershipCond", Collections.<ITab>singletonList(
+ new AbstractTab(new ResourceModel("uDynMembershipCond", "Dynamic USER Membership Conditions")) {
+
+ private static final long serialVersionUID = 1037272333056449378L;
+
+ @Override
+ public Panel getPanel(final String panelId) {
+ return new UserSearchPanel.Builder(new PropertyModel<List<SearchClause>>(groupTO, "uDynClauses")).
+ required(false).build(panelId);
+ }
+ }), Model.of(StringUtils.isBlank(groupTO.getUDynMembershipCond()) ? -1 : 0)).setOutputMarkupId(true));
+ // ------------------------
+
+ // ------------------------
+ // aDynMembershipConds
+ // ------------------------
+ add(new ListView<AnyTypeTO>("aDynMembershipCond", types) {
+
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ protected void populateItem(final ListItem<AnyTypeTO> item) {
+ final String key = item.getModelObject().getKey();
+ item.add(new Collapsible("aDynMembershipCond", Collections.<ITab>singletonList(
+ new AbstractTab(new StringResourceModel(
+ "aDynMembershipCond", this, new Model<AnyTypeTO>(item.getModelObject()))) {
+
+ private static final long serialVersionUID = 1037272333056449378L;
+
+ @Override
+ public Panel getPanel(final String panelId) {
+ return new AnyObjectSearchPanel.Builder(
+ new MapOfListModel<SearchClause>(groupTO, "aDynClauses",
+ item.getModelObject().getKey())).
+ required(false).build(panelId);
+ }
+ }), Model.of(StringUtils.isBlank(groupTO.getADynMembershipConds().get(key)) ? -1 : 0))
+ .setOutputMarkupId(true));
+ }
+ });
+ // ------------------------
}
/**
@@ -182,10 +267,10 @@ public class GroupDetails extends Details<GroupTO> {
super.onEvent(event);
if (event.getPayload() instanceof UserOwnerSelectPayload) {
- userOwnerModel.setObject(((UserOwnerSelectPayload) event.getPayload()).getUserId());
+ uOwnerModel.setObject(((UserOwnerSelectPayload) event.getPayload()).getUserId());
}
if (event.getPayload() instanceof GroupOwnerSelectPayload) {
- groupOwnerModel.setObject(((GroupOwnerSelectPayload) event.getPayload()).getGroupId());
+ gOwnerModel.setObject(((GroupOwnerSelectPayload) event.getPayload()).getGroupId());
}
if (event.getPayload() instanceof AjaxRequestTarget) {