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/06/08 22:28:06 UTC
[17/17] syncope git commit: [SYNCOPE-156] working with resource and
connector topology
[SYNCOPE-156] working with resource and connector topology
Project: http://git-wip-us.apache.org/repos/asf/syncope/repo
Commit: http://git-wip-us.apache.org/repos/asf/syncope/commit/34ec6712
Tree: http://git-wip-us.apache.org/repos/asf/syncope/tree/34ec6712
Diff: http://git-wip-us.apache.org/repos/asf/syncope/diff/34ec6712
Branch: refs/heads/master
Commit: 34ec6712df74f0e7267363f0ea044295af35b5aa
Parents: eb5915f
Author: fmartelli <fa...@gmail.com>
Authored: Mon Jun 8 22:26:38 2015 +0200
Committer: fmartelli <fa...@gmail.com>
Committed: Mon Jun 8 22:26:38 2015 +0200
----------------------------------------------------------------------
client/console/pom.xml | 12 +
.../client/console/SyncopeConsoleSession.java | 3 +-
.../console/commons/ActionTableCheckGroup.java | 40 +
.../commons/AttributableDataProvider.java | 103 +
.../client/console/commons/JexlHelpUtils.java | 59 +
.../client/console/pages/AbstractBasePage.java | 6 +
.../console/pages/AbstractStatusModalPage.java | 30 +
.../syncope/client/console/pages/BasePage.java | 7 +-
.../console/pages/BulkActionModalPage.java | 166 +
.../pages/BulkActionResultModalPage.java | 99 +
.../console/pages/ConnectorModalPage.java | 477 ++
.../console/pages/ProvisioningModalPage.java | 253 ++
.../syncope/client/console/pages/Realms.java | 147 +
.../client/console/pages/ResourceModalPage.java | 204 +
.../panels/AbstractSearchResultPanel.java | 346 ++
.../client/console/panels/AccountPolicy.java | 35 +
.../console/panels/ActionDataTablePanel.java | 145 +
.../console/panels/AjaxDataTablePanel.java | 142 +
.../console/panels/AnnotatedBeanPanel.java | 66 +
.../syncope/client/console/panels/Any.java | 35 +
.../client/console/panels/Connectors.java | 385 ++
.../client/console/panels/DataTablePanel.java | 113 +
.../client/console/panels/PasswordPolicy.java | 35 +
.../syncope/client/console/panels/Realm.java | 49 +
.../client/console/panels/RealmDetails.java | 41 +
.../console/panels/ResourceConnConfPanel.java | 189 +
.../console/panels/ResourceDetailsPanel.java | 306 ++
.../console/panels/ResourceMappingPanel.java | 644 +++
.../console/panels/ResourceSecurityPanel.java | 186 +
.../client/console/panels/Resources.java | 485 +++
.../console/rest/ConnectorRestClient.java | 6 +-
.../client/console/rest/RealmRestClient.java | 38 +
.../client/console/topology/Topology.java | 521 +++
.../client/console/topology/TopologyNode.java | 123 +
.../console/topology/TopologyNodePanel.java | 205 +
.../topology/TopologyReloadBehavior.java | 61 +
.../markup/html/ClearIndicatingAjaxButton.java | 76 +
.../markup/html/ClearIndicatingAjaxLink.java | 61 +
.../repeater/data/table/ActionResultColumn.java | 77 +
.../data/table/CheckBoxGroupSelectorPanel.java | 34 +
.../html/repeater/data/table/CheckBoxPanel.java | 43 +
.../repeater/data/table/CheckGroupColumn.java | 54 +
.../wicket/markup/html/form/ActionLink.java | 85 +
.../markup/html/form/ActionLinksPanel.java | 609 +++
.../markup/html/form/AjaxTextFieldPanel.java | 4 +-
.../html/form/IndicatingOnConfirmAjaxLink.java | 58 +
.../META-INF/resources/css/console.css | 4066 ------------------
.../META-INF/resources/css/fieldstyle.css | 191 +
.../META-INF/resources/css/syncopeConsole.css | 170 +-
.../META-INF/resources/css/topology.css | 160 +
.../resources/META-INF/resources/js/topology.js | 244 ++
.../console/pages/AbstractStatusModalPage.html | 122 +
.../pages/AbstractStatusModalPage.properties | 19 +
.../pages/AbstractStatusModalPage_it.properties | 19 +
.../AbstractStatusModalPage_pt_BR.properties | 19 +
.../client/console/pages/BaseModalPage.html | 23 +-
.../syncope/client/console/pages/BasePage.html | 11 +-
.../console/pages/BulkActionModalPage.html | 45 +
.../pages/BulkActionModalPage.properties | 17 +
.../pages/BulkActionModalPage_it.properties | 17 +
.../pages/BulkActionModalPage_pt_BR.properties | 17 +
.../pages/BulkActionResultModalPage.html | 57 +
.../pages/BulkActionResultModalPage.properties | 19 +
.../BulkActionResultModalPage_it.properties | 19 +
.../BulkActionResultModalPage_pt_BR.properties | 19 +
.../console/pages/ConnectorModalPage.html | 161 +
.../console/pages/ConnectorModalPage.properties | 43 +
.../pages/ConnectorModalPage_it.properties | 43 +
.../pages/ConnectorModalPage_pt_BR.properties | 43 +
.../syncope/client/console/pages/Realms.html | 91 +-
.../client/console/pages/ResourceModalPage.html | 56 +
.../console/pages/ResourceModalPage.properties | 60 +
.../pages/ResourceModalPage_it.properties | 60 +
.../pages/ResourceModalPage_pt_BR.properties | 60 +
.../panels/AbstractSearchResultPanel.html | 43 +
.../panels/AbstractSearchResultPanel.properties | 30 +
.../AbstractSearchResultPanel_it.properties | 30 +
.../AbstractSearchResultPanel_pt_BR.properties | 30 +
.../client/console/panels/AccountPolicy.html | 29 +
.../console/panels/ActionDataTablePanel.html | 45 +
.../console/panels/AjaxDataTablePanel.html | 47 +
.../console/panels/AnnotatedBeanPanel.html | 98 +
.../panels/AnnotatedBeanPanel.properties | 20 +
.../panels/AnnotatedBeanPanel_it.properties | 20 +
.../panels/AnnotatedBeanPanel_pt_BR.properties | 20 +
.../syncope/client/console/panels/Any.html | 29 +
.../client/console/panels/Connectors.html | 57 +
.../client/console/panels/Connectors.properties | 34 +
.../console/panels/Connectors_it.properties | 34 +
.../console/panels/Connectors_pt_BR.properties | 32 +
.../client/console/panels/PasswordPolicy.html | 29 +
.../syncope/client/console/panels/Realm.html | 93 +
.../client/console/panels/RealmDetails.html | 45 +
.../console/panels/ResourceConnConfPanel.html | 40 +
.../console/panels/ResourceDetailsPanel.html | 137 +
.../console/panels/ResourceMappingPanel.html | 114 +
.../console/panels/ResourceSecurityPanel.html | 56 +
.../panels/ResourceSecurityPanel.properties | 19 +
.../panels/ResourceSecurityPanel_it.properties | 19 +
.../ResourceSecurityPanel_pt_BR.properties | 19 +
.../client/console/panels/Resources.html | 52 +
.../client/console/panels/Resources.properties | 34 +
.../console/panels/Resources_it.properties | 34 +
.../console/panels/Resources_pt_BR.properties | 32 +
.../client/console/topology/Topology.html | 52 +
.../client/console/topology/Topology.properties | 17 +
.../console/topology/TopologyNodePanel.html | 67 +
.../topology/TopologyNodePanel.properties | 20 +
.../topology/TopologyNodePanel_it.properties | 20 +
.../topology/TopologyNodePanel_pt_BR.properties | 20 +
.../console/topology/Topology_it.properties | 17 +
.../console/topology/Topology_pt_BR.properties | 17 +
.../data/table/CheckBoxGroupSelectorPanel.html | 21 +
.../html/repeater/data/table/CheckBoxPanel.html | 23 +
.../markup/html/form/ActionLinksPanel.html | 173 +
.../markup/html/form/AjaxCheckBoxPanel.html | 21 +
.../html/form/AjaxDropDownChoicePanel.html | 24 +
.../markup/html/form/AjaxNumberFieldPanel.html | 22 +
.../markup/html/form/AjaxPalettePanel.html | 23 +
.../html/form/AjaxPasswordFieldPanel.html | 22 +
.../markup/html/form/AjaxTextFieldPanel.html | 23 +
.../markup/html/form/AjaxTextFieldPanel_1.html | 23 +
.../markup/html/form/BinaryFieldPanel.html | 44 +
.../form/CheckBoxMultipleChoiceFieldPanel.html | 23 +
.../markup/html/form/DateTextFieldPanel.html | 22 +
.../markup/html/form/DateTimeFieldPanel.html | 21 +
.../html/form/DateTimeFieldPanel.properties | 17 +
.../html/form/DateTimeFieldPanel_it.properties | 17 +
.../form/DateTimeFieldPanel_pt_BR.properties | 17 +
.../wicket/markup/html/form/FieldPanel.html | 34 +
.../wicket/markup/html/form/FieldPanel_1.html | 34 +
.../wicket/markup/html/form/LinkPanel.html | 23 +
.../wicket/markup/html/form/LinkPanel_1.html | 23 +
.../markup/html/form/MappingPurposePanel.html | 31 +
.../markup/html/form/MultiFieldPanel.html | 35 +
.../markup/html/form/MultiFieldPanel.properties | 22 +
.../html/form/MultiFieldPanel_it.properties | 22 +
.../html/form/MultiFieldPanel_pt_BR.properties | 22 +
.../wicket/markup/html/form/NonI18nPalette.html | 69 +
.../markup/html/form/SpinnerFieldPanel.html | 29 +
.../rest/api/service/ConnectorService.java | 1 -
pom.xml | 13 +
142 files changed, 10983 insertions(+), 4196 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/syncope/blob/34ec6712/client/console/pom.xml
----------------------------------------------------------------------
diff --git a/client/console/pom.xml b/client/console/pom.xml
index a558d30..4ef7c9c 100644
--- a/client/console/pom.xml
+++ b/client/console/pom.xml
@@ -110,6 +110,18 @@ under the License.
<groupId>org.webjars</groupId>
<artifactId>codemirror</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.webjars</groupId>
+ <artifactId>jsplumb</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.webjars</groupId>
+ <artifactId>jquery-cookie</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.webjars</groupId>
+ <artifactId>jquery-ui</artifactId>
+ </dependency>
</dependencies>
<build>
http://git-wip-us.apache.org/repos/asf/syncope/blob/34ec6712/client/console/src/main/java/org/apache/syncope/client/console/SyncopeConsoleSession.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/SyncopeConsoleSession.java b/client/console/src/main/java/org/apache/syncope/client/console/SyncopeConsoleSession.java
index f162357..25394c7 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/SyncopeConsoleSession.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/SyncopeConsoleSession.java
@@ -157,7 +157,8 @@ public class SyncopeConsoleSession extends AuthenticatedWebSession {
public <T> T getService(final String etag, final Class<T> serviceClass) {
T serviceInstance = getCachedService(serviceClass);
- WebClient.client(serviceInstance).match(new EntityTag(etag), false);
+ WebClient.client(serviceInstance).match(new EntityTag(etag), false).
+ type(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON);
return serviceInstance;
}
http://git-wip-us.apache.org/repos/asf/syncope/blob/34ec6712/client/console/src/main/java/org/apache/syncope/client/console/commons/ActionTableCheckGroup.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/commons/ActionTableCheckGroup.java b/client/console/src/main/java/org/apache/syncope/client/console/commons/ActionTableCheckGroup.java
new file mode 100644
index 0000000..453e0c0
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/commons/ActionTableCheckGroup.java
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.client.console.commons;
+
+import java.util.Collection;
+import org.apache.wicket.markup.html.form.CheckGroup;
+import org.apache.wicket.model.IModel;
+
+public class ActionTableCheckGroup<T> extends CheckGroup<T> {
+
+ private static final long serialVersionUID = 1288270558573401394L;
+
+ public ActionTableCheckGroup(final String id, final Collection<T> collection) {
+ super(id, collection);
+ }
+
+ public ActionTableCheckGroup(final String id, final IModel<Collection<T>> model) {
+ super(id, model);
+ }
+
+ public boolean isCheckable(final T element) {
+ return true;
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/34ec6712/client/console/src/main/java/org/apache/syncope/client/console/commons/AttributableDataProvider.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/commons/AttributableDataProvider.java b/client/console/src/main/java/org/apache/syncope/client/console/commons/AttributableDataProvider.java
new file mode 100644
index 0000000..1890a80
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/commons/AttributableDataProvider.java
@@ -0,0 +1,103 @@
+/*
+ * 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.commons;
+
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import org.apache.syncope.client.console.rest.AbstractSubjectRestClient;
+import org.apache.syncope.common.lib.to.AbstractAttributableTO;
+import org.apache.wicket.extensions.markup.html.repeater.data.sort.SortOrder;
+import org.apache.wicket.extensions.markup.html.repeater.util.SortableDataProvider;
+import org.apache.wicket.model.CompoundPropertyModel;
+import org.apache.wicket.model.IModel;
+
+public class AttributableDataProvider extends SortableDataProvider<AbstractAttributableTO, String> {
+
+ private static final long serialVersionUID = 6267494272884913376L;
+
+ private final SortableAttributableProviderComparator comparator;
+
+ private String fiql = null;
+
+ private final int paginatorRows;
+
+ private final boolean filtered;
+
+ private final AbstractSubjectRestClient restClient;
+
+ private final String realm = "/";
+
+ public AttributableDataProvider(final AbstractSubjectRestClient restClient,
+ final int paginatorRows, final boolean filtered) {
+
+ super();
+
+ this.restClient = restClient;
+ this.filtered = filtered;
+ this.paginatorRows = paginatorRows;
+
+ // default sorting
+ setSort("key", SortOrder.ASCENDING);
+
+ this.comparator = new SortableAttributableProviderComparator(this);
+ }
+
+ public void setFIQL(final String fiql) {
+ this.fiql = fiql;
+ }
+
+ @Override
+ public Iterator<? extends AbstractAttributableTO> iterator(final long first, final long count) {
+ List<? extends AbstractAttributableTO> result;
+
+ final int page = ((int) first / paginatorRows);
+
+ if (filtered) {
+ result = fiql == null
+ ? Collections.<AbstractAttributableTO>emptyList()
+ : restClient.search(realm, fiql, (page < 0 ? 0 : page) + 1, paginatorRows, getSort());
+ } else {
+ result = restClient.list(realm, (page < 0 ? 0 : page) + 1, paginatorRows, getSort());
+ }
+
+ Collections.sort(result, comparator);
+ return result.iterator();
+ }
+
+ @Override
+ public long size() {
+ long result;
+
+ if (filtered) {
+ result = fiql == null
+ ? 0
+ : restClient.searchCount(realm, fiql);
+ } else {
+ result = restClient.count(realm);
+ }
+
+ return result;
+ }
+
+ @Override
+ public IModel<AbstractAttributableTO> model(final AbstractAttributableTO object) {
+ return new CompoundPropertyModel<>(object);
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/34ec6712/client/console/src/main/java/org/apache/syncope/client/console/commons/JexlHelpUtils.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/commons/JexlHelpUtils.java b/client/console/src/main/java/org/apache/syncope/client/console/commons/JexlHelpUtils.java
new file mode 100644
index 0000000..ab8dcfb
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/commons/JexlHelpUtils.java
@@ -0,0 +1,59 @@
+/*
+ * 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.commons;
+
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.ajax.markup.html.AjaxLink;
+import org.apache.wicket.markup.html.WebMarkupContainer;
+import org.apache.wicket.markup.html.link.ExternalLink;
+
+public final class JexlHelpUtils {
+
+ private static final String JEXL_SYNTAX_URL = "http://commons.apache.org/jexl/reference/syntax.html";
+
+ private JexlHelpUtils() {
+ // private constructor for static utility class
+ }
+
+ public static WebMarkupContainer getJexlHelpWebContainer(final String wicketId) {
+ final WebMarkupContainer jexlHelp = new WebMarkupContainer(wicketId);
+ jexlHelp.setVisible(false);
+ jexlHelp.setOutputMarkupPlaceholderTag(true);
+ jexlHelp.setOutputMarkupId(true);
+ jexlHelp.add(new ExternalLink("jexlLink", JEXL_SYNTAX_URL));
+ return jexlHelp;
+ }
+
+ public static AjaxLink<Void> getAjaxLink(final WebMarkupContainer wmc, final String wicketId) {
+ AjaxLink<Void> questionMarkJexlHelp = new AjaxLink<Void>(wicketId) {
+
+ private static final long serialVersionUID = -1838017408000591382L;
+
+ private boolean toogle = false;
+
+ @Override
+ public void onClick(final AjaxRequestTarget target) {
+ toogle ^= true;
+ wmc.setVisible(toogle);
+ target.add(wmc);
+ }
+ };
+ return questionMarkJexlHelp;
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/34ec6712/client/console/src/main/java/org/apache/syncope/client/console/pages/AbstractBasePage.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/pages/AbstractBasePage.java b/client/console/src/main/java/org/apache/syncope/client/console/pages/AbstractBasePage.java
index d63de02..bd88711 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/pages/AbstractBasePage.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/pages/AbstractBasePage.java
@@ -22,6 +22,7 @@ import org.apache.syncope.client.console.commons.Constants;
import org.apache.syncope.client.console.init.MIMETypesLoader;
import org.apache.syncope.client.console.panels.NotificationPanel;
import org.apache.syncope.client.console.rest.ConfigurationRestClient;
+import org.apache.syncope.client.console.rest.ConnectorRestClient;
import org.apache.syncope.client.console.rest.ReportRestClient;
import org.apache.syncope.client.console.rest.ResourceRestClient;
import org.apache.syncope.client.console.rest.GroupRestClient;
@@ -51,6 +52,8 @@ public class AbstractBasePage extends WebPage {
protected static final String APPLY = "apply";
+ protected static final String FORM = "form";
+
protected final HeaderItem meta = new MetaHeaderItem("X-UA-Compatible", "IE=edge");
@SpringBean
@@ -72,6 +75,9 @@ public class AbstractBasePage extends WebPage {
protected ResourceRestClient resourceRestClient;
@SpringBean
+ protected ConnectorRestClient connectorRestClient;
+
+ @SpringBean
protected ReportRestClient reportRestClient;
@SpringBean
http://git-wip-us.apache.org/repos/asf/syncope/blob/34ec6712/client/console/src/main/java/org/apache/syncope/client/console/pages/AbstractStatusModalPage.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/pages/AbstractStatusModalPage.java b/client/console/src/main/java/org/apache/syncope/client/console/pages/AbstractStatusModalPage.java
new file mode 100644
index 0000000..f5dfbca
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/pages/AbstractStatusModalPage.java
@@ -0,0 +1,30 @@
+/*
+ * 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.pages;
+
+import org.apache.wicket.markup.html.panel.Fragment;
+
+public class AbstractStatusModalPage extends BaseModalPage {
+
+ private static final long serialVersionUID = 6633408683036028540L;
+
+ public AbstractStatusModalPage() {
+ add(new Fragment("pwdMgtFields", "emptyFragment", this));
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/34ec6712/client/console/src/main/java/org/apache/syncope/client/console/pages/BasePage.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/pages/BasePage.java b/client/console/src/main/java/org/apache/syncope/client/console/pages/BasePage.java
index 71a9c7f..20c3458 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/pages/BasePage.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/pages/BasePage.java
@@ -21,6 +21,7 @@ package org.apache.syncope.client.console.pages;
import org.apache.syncope.client.console.SyncopeConsoleSession;
import org.apache.syncope.client.console.commons.Constants;
import org.apache.syncope.client.console.rest.UserWorkflowRestClient;
+import org.apache.syncope.client.console.topology.Topology;
import org.apache.syncope.common.lib.types.Entitlement;
import org.apache.wicket.Component;
import org.apache.wicket.Page;
@@ -92,6 +93,10 @@ public class BasePage extends AbstractBasePage implements IAjaxIndicatorAware {
add(liContainer);
liContainer.add(new BookmarkablePageLink<>("realms", Realms.class));
+ liContainer = new WebMarkupContainer(getLIContainerId("topology"));
+ add(liContainer);
+ liContainer.add(new BookmarkablePageLink<>("topology", Topology.class));
+
add(new BookmarkablePageLink<Page>("logout", Logout.class));
// set 'active' menu item
@@ -150,7 +155,7 @@ public class BasePage extends AbstractBasePage implements IAjaxIndicatorAware {
* @param window window
* @param container container
*/
- protected void setWindowClosedCallback(final ModalWindow window, final WebMarkupContainer container) {
+ public void setWindowClosedCallback(final ModalWindow window, final WebMarkupContainer container) {
window.setWindowClosedCallback(new ModalWindow.WindowClosedCallback() {
private static final long serialVersionUID = 8804221891699487139L;
http://git-wip-us.apache.org/repos/asf/syncope/blob/34ec6712/client/console/src/main/java/org/apache/syncope/client/console/pages/BulkActionModalPage.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/pages/BulkActionModalPage.java b/client/console/src/main/java/org/apache/syncope/client/console/pages/BulkActionModalPage.java
new file mode 100644
index 0000000..65dfa58
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/pages/BulkActionModalPage.java
@@ -0,0 +1,166 @@
+/*
+ * 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.pages;
+
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import org.apache.syncope.client.console.commons.Constants;
+import org.apache.syncope.client.console.rest.BaseRestClient;
+import org.apache.syncope.client.console.wicket.ajax.markup.html.ClearIndicatingAjaxButton;
+import org.apache.syncope.client.console.wicket.markup.html.form.ActionLink;
+import org.apache.syncope.client.console.wicket.markup.html.form.ActionLinksPanel;
+import org.apache.syncope.common.lib.to.BulkAction;
+import org.apache.syncope.common.lib.to.BulkActionResult;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.ajax.markup.html.form.AjaxButton;
+import org.apache.wicket.extensions.ajax.markup.html.modal.ModalWindow;
+import org.apache.wicket.extensions.ajax.markup.html.repeater.data.table.AjaxFallbackDefaultDataTable;
+import org.apache.wicket.extensions.markup.html.repeater.data.table.IColumn;
+import org.apache.wicket.extensions.markup.html.repeater.util.SortableDataProvider;
+import org.apache.wicket.markup.html.form.Form;
+import org.apache.wicket.model.CompoundPropertyModel;
+import org.apache.wicket.model.IModel;
+import org.apache.wicket.model.Model;
+import org.apache.wicket.model.ResourceModel;
+import org.springframework.beans.BeanUtils;
+
+public class BulkActionModalPage<T, S> extends BaseModalPage {
+
+ private static final long serialVersionUID = 4114026480146090962L;
+
+ public BulkActionModalPage(
+ final ModalWindow window,
+ final Collection<T> items,
+ final List<IColumn<T, S>> columns,
+ final Collection<ActionLink.ActionType> actions,
+ final BaseRestClient bulkActionExecutor,
+ final String idFieldName,
+ final String pageId) {
+
+ super();
+
+ final SortableDataProvider<T, S> dataProvider = new SortableDataProvider<T, S>() {
+
+ private static final long serialVersionUID = 5291903859908641954L;
+
+ @Override
+ public Iterator<? extends T> iterator(final long first, final long count) {
+ return items.iterator();
+ }
+
+ @Override
+ public long size() {
+ return items.size();
+ }
+
+ @Override
+ public IModel<T> model(final T object) {
+ return new CompoundPropertyModel<>(object);
+ }
+ };
+
+ add(new AjaxFallbackDefaultDataTable<>(
+ "selectedObjects",
+ new ArrayList<>(columns.subList(1, columns.size() - 1)),
+ dataProvider,
+ Integer.MAX_VALUE).setVisible(items != null && !items.isEmpty()));
+
+ @SuppressWarnings("rawtypes")
+ final ActionLinksPanel actionPanel = new ActionLinksPanel("actions", new Model(), getPageReference());
+ add(actionPanel);
+
+ for (ActionLink.ActionType action : actions) {
+ final BulkAction bulkAction = new BulkAction();
+ for (T item : items) {
+ try {
+ bulkAction.getTargets().add(getTargetId(item, idFieldName).toString());
+ } catch (IllegalAccessException | InvocationTargetException e) {
+ LOG.error("Error retrieving item id {}", idFieldName, e);
+ }
+ }
+
+ switch (action) {
+ case DELETE:
+ bulkAction.setOperation(BulkAction.Type.DELETE);
+ break;
+ case SUSPEND:
+ bulkAction.setOperation(BulkAction.Type.SUSPEND);
+ break;
+ case REACTIVATE:
+ bulkAction.setOperation(BulkAction.Type.REACTIVATE);
+ break;
+ case EXECUTE:
+ bulkAction.setOperation(BulkAction.Type.EXECUTE);
+ break;
+ case DRYRUN:
+ bulkAction.setOperation(BulkAction.Type.DRYRUN);
+ break;
+ default:
+ LOG.error("Bulk action type not supported");
+ }
+
+ actionPanel.add(new ActionLink() {
+
+ private static final long serialVersionUID = -3722207913631435501L;
+
+ @Override
+ public void onClick(final AjaxRequestTarget target) {
+ try {
+ final BulkActionResult res = (BulkActionResult) bulkActionExecutor.getClass().
+ getMethod("bulkAction", BulkAction.class).invoke(bulkActionExecutor, bulkAction);
+
+ setResponsePage(new BulkActionResultModalPage<>(window, items, columns, res, idFieldName));
+ } catch (NoSuchMethodException | SecurityException | IllegalAccessException
+ | IllegalArgumentException | InvocationTargetException e) {
+ error(getString(Constants.ERROR)
+ + ": Operation " + bulkAction.getOperation() + " not supported");
+ feedbackPanel.refresh(target);
+ }
+
+ }
+ }, action, pageId, !items.isEmpty());
+ }
+
+ final Form<Void> form = new Form<>(FORM);
+ add(form);
+
+ final AjaxButton cancel = new ClearIndicatingAjaxButton(CANCEL, new ResourceModel(CANCEL), getPageReference()) {
+
+ private static final long serialVersionUID = -958724007591692537L;
+
+ @Override
+ protected void onSubmitInternal(final AjaxRequestTarget target, final Form<?> form) {
+ window.close(target);
+ }
+ };
+
+ cancel.setDefaultFormProcessing(false);
+ form.add(cancel);
+ }
+
+ private Object getTargetId(final Object target, final String idFieldName)
+ throws IllegalAccessException, InvocationTargetException {
+
+ return BeanUtils.getPropertyDescriptor(target.getClass(), idFieldName).
+ getReadMethod().invoke(target, new Object[0]);
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/34ec6712/client/console/src/main/java/org/apache/syncope/client/console/pages/BulkActionResultModalPage.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/pages/BulkActionResultModalPage.java b/client/console/src/main/java/org/apache/syncope/client/console/pages/BulkActionResultModalPage.java
new file mode 100644
index 0000000..72a789f
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/pages/BulkActionResultModalPage.java
@@ -0,0 +1,99 @@
+/*
+ * 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.pages;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import org.apache.syncope.client.console.wicket.extensions.markup.html.repeater.data.table.ActionResultColumn;
+import org.apache.syncope.common.lib.to.BulkActionResult;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.ajax.markup.html.AjaxLink;
+import org.apache.wicket.extensions.ajax.markup.html.IndicatingAjaxLink;
+import org.apache.wicket.extensions.ajax.markup.html.modal.ModalWindow;
+import org.apache.wicket.extensions.ajax.markup.html.repeater.data.table.AjaxFallbackDefaultDataTable;
+import org.apache.wicket.extensions.markup.html.repeater.data.table.IColumn;
+import org.apache.wicket.extensions.markup.html.repeater.util.SortableDataProvider;
+import org.apache.wicket.model.CompoundPropertyModel;
+import org.apache.wicket.model.IModel;
+
+/**
+ * Show user or group status after performing a successful operation.
+ * @param <T>
+ * @param <S>
+ */
+public class BulkActionResultModalPage<T, S> extends BaseModalPage {
+
+ /**
+ * Serial version id.
+ */
+ private static final long serialVersionUID = 2646115294319713724L;
+
+ public BulkActionResultModalPage(
+ final ModalWindow window,
+ final Collection<T> items,
+ final List<IColumn<T, S>> columns,
+ final BulkActionResult results,
+ final String idFieldName) {
+
+ super();
+
+ final List<IColumn<T, S>> newColumnList = new ArrayList<>(columns.subList(1, columns.size() - 1));
+ newColumnList.add(newColumnList.size(), new ActionResultColumn<T, S>(results, idFieldName));
+
+ final SortableDataProvider<T, S> dataProvider = new SortableDataProvider<T, S>() {
+
+ private static final long serialVersionUID = 5291903859908641954L;
+
+ @Override
+ public Iterator<? extends T> iterator(final long first, final long count) {
+ return items.iterator();
+ }
+
+ @Override
+ public long size() {
+ return items.size();
+ }
+
+ @Override
+ public IModel<T> model(final T object) {
+ return new CompoundPropertyModel<>(object);
+ }
+ };
+
+ add(new AjaxFallbackDefaultDataTable<>(
+ "selectedObjects",
+ newColumnList,
+ dataProvider,
+ Integer.MAX_VALUE).setVisible(items != null && !items.isEmpty()));
+
+ final AjaxLink<Void> close = new IndicatingAjaxLink<Void>("close") {
+
+ private static final long serialVersionUID = -7978723352517770644L;
+
+ @Override
+ public void onClick(final AjaxRequestTarget target) {
+ window.close(target);
+ }
+ };
+
+ add(close);
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/34ec6712/client/console/src/main/java/org/apache/syncope/client/console/pages/ConnectorModalPage.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/pages/ConnectorModalPage.java b/client/console/src/main/java/org/apache/syncope/client/console/pages/ConnectorModalPage.java
new file mode 100644
index 0000000..f35da6a
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/pages/ConnectorModalPage.java
@@ -0,0 +1,477 @@
+/*
+ * 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.pages;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.syncope.client.console.commons.Constants;
+import org.apache.syncope.client.console.rest.ConnectorRestClient;
+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.SpinnerFieldPanel;
+import org.apache.syncope.client.console.wicket.markup.html.list.ConnConfPropertyListView;
+import org.apache.syncope.common.lib.SyncopeClientException;
+import org.apache.syncope.common.lib.to.ConnBundleTO;
+import org.apache.syncope.common.lib.to.ConnInstanceTO;
+import org.apache.syncope.common.lib.to.ConnPoolConfTO;
+import org.apache.syncope.common.lib.types.ConnConfPropSchema;
+import org.apache.syncope.common.lib.types.ConnConfProperty;
+import org.apache.syncope.common.lib.types.ConnectorCapability;
+import org.apache.syncope.common.lib.types.Entitlement;
+import org.apache.wicket.PageReference;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.ajax.form.AjaxFormChoiceComponentUpdatingBehavior;
+import org.apache.wicket.ajax.form.AjaxFormComponentUpdatingBehavior;
+import org.apache.wicket.ajax.markup.html.form.AjaxButton;
+import org.apache.wicket.authroles.authorization.strategies.role.metadata.MetaDataRoleAuthorizationStrategy;
+import org.apache.wicket.extensions.ajax.markup.html.IndicatingAjaxButton;
+import org.apache.wicket.extensions.ajax.markup.html.modal.ModalWindow;
+import org.apache.wicket.markup.html.WebMarkupContainer;
+import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.markup.html.form.CheckBoxMultipleChoice;
+import org.apache.wicket.markup.html.form.DropDownChoice;
+import org.apache.wicket.markup.html.form.Form;
+import org.apache.wicket.markup.html.list.ListView;
+import org.apache.wicket.model.CompoundPropertyModel;
+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.spring.injection.annot.SpringBean;
+import org.apache.wicket.validation.validator.RangeValidator;
+
+/**
+ * Modal window with Connector form.
+ */
+public class ConnectorModalPage extends BaseModalPage {
+
+ private static final long serialVersionUID = -2025535531121434050L;
+
+ @SpringBean
+ private ConnectorRestClient restClient;
+
+ private final Map<String, Map<String, Map<String, ConnBundleTO>>> mapConnBundleTOs;
+
+ private final List<ConnectorCapability> selectedCapabilities;
+
+ private ConnBundleTO bundleTO;
+
+ private List<ConnConfProperty> properties;
+
+ private final WebMarkupContainer propertiesContainer;
+
+ public ConnectorModalPage(final PageReference pageRef, final ModalWindow window,
+ final ConnInstanceTO connInstanceTO) {
+
+ super();
+
+ this.add(new Label("new", connInstanceTO.getKey() == 0
+ ? new ResourceModel("new")
+ : new Model<>(StringUtils.EMPTY)));
+ this.add(new Label("key", connInstanceTO.getKey() == 0
+ ? StringUtils.EMPTY
+ : connInstanceTO.getKey()));
+
+ // general data setup
+ selectedCapabilities = new ArrayList<>(connInstanceTO.getKey() == 0
+ ? EnumSet.noneOf(ConnectorCapability.class)
+ : connInstanceTO.getCapabilities());
+
+ mapConnBundleTOs = new HashMap<>();
+ for (ConnBundleTO connBundleTO : restClient.getAllBundles()) {
+ // by location
+ if (!mapConnBundleTOs.containsKey(connBundleTO.getLocation())) {
+ mapConnBundleTOs.put(connBundleTO.getLocation(), new HashMap<String, Map<String, ConnBundleTO>>());
+ }
+ final Map<String, Map<String, ConnBundleTO>> byLocation = mapConnBundleTOs.get(connBundleTO.getLocation());
+
+ // by name
+ if (!byLocation.containsKey(connBundleTO.getBundleName())) {
+ byLocation.put(connBundleTO.getBundleName(), new HashMap<String, ConnBundleTO>());
+ }
+ final Map<String, ConnBundleTO> byName = byLocation.get(connBundleTO.getBundleName());
+
+ // by version
+ if (!byName.containsKey(connBundleTO.getVersion())) {
+ byName.put(connBundleTO.getVersion(), connBundleTO);
+ }
+ }
+
+ bundleTO = getSelectedBundleTO(connInstanceTO);
+ properties = fillProperties(bundleTO, connInstanceTO);
+
+ // form - first tab
+ final Form<ConnInstanceTO> connectorForm = new Form<>(FORM);
+ connectorForm.setModel(new CompoundPropertyModel<>(connInstanceTO));
+ connectorForm.setOutputMarkupId(true);
+ add(connectorForm);
+
+ propertiesContainer = new WebMarkupContainer("container");
+ propertiesContainer.setOutputMarkupId(true);
+ connectorForm.add(propertiesContainer);
+
+ final Form<ConnInstanceTO> connectorPropForm = new Form<>("connectorPropForm");
+ connectorPropForm.setModel(new CompoundPropertyModel<>(connInstanceTO));
+ connectorPropForm.setOutputMarkupId(true);
+ propertiesContainer.add(connectorPropForm);
+
+ final AjaxTextFieldPanel displayName = new AjaxTextFieldPanel(
+ "displayName", "display name", new PropertyModel<String>(connInstanceTO, "displayName"));
+ displayName.setOutputMarkupId(true);
+ displayName.addRequiredLabel();
+ connectorForm.add(displayName);
+
+ final AjaxDropDownChoicePanel<String> location = new AjaxDropDownChoicePanel<>("location", "location",
+ new Model<>(bundleTO == null ? null : bundleTO.getLocation()));
+ ((DropDownChoice<String>) location.getField()).setNullValid(true);
+ location.setStyleSheet("long_dynamicsize");
+ location.setChoices(new ArrayList<>(mapConnBundleTOs.keySet()));
+ location.setRequired(true);
+ location.addRequiredLabel();
+ location.setOutputMarkupId(true);
+ location.setEnabled(connInstanceTO.getKey() == 0);
+ location.getField().setOutputMarkupId(true);
+ connectorForm.add(location);
+
+ final AjaxDropDownChoicePanel<String> connectorName = new AjaxDropDownChoicePanel<>("connectorName",
+ "connectorName",
+ new Model<>(bundleTO == null ? null : bundleTO.getBundleName()));
+ ((DropDownChoice<String>) connectorName.getField()).setNullValid(true);
+ connectorName.setStyleSheet("long_dynamicsize");
+ connectorName.setChoices(bundleTO == null
+ ? new ArrayList<String>()
+ : new ArrayList<>(mapConnBundleTOs.get(connInstanceTO.getLocation()).keySet()));
+ connectorName.setRequired(true);
+ connectorName.addRequiredLabel();
+ connectorName.setEnabled(connInstanceTO.getLocation() != null);
+ connectorName.setOutputMarkupId(true);
+ connectorName.setEnabled(connInstanceTO.getKey() == 0);
+ connectorName.getField().setOutputMarkupId(true);
+ connectorForm.add(connectorName);
+
+ final AjaxDropDownChoicePanel<String> version = new AjaxDropDownChoicePanel<>("version", "version",
+ new Model<>(bundleTO == null ? null : bundleTO.getVersion()));
+ version.setStyleSheet("long_dynamicsize");
+ version.setChoices(bundleTO == null
+ ? new ArrayList<String>()
+ : new ArrayList<>(mapConnBundleTOs.get(connInstanceTO.getLocation()).
+ get(connInstanceTO.getBundleName()).keySet()));
+ version.setRequired(true);
+ version.addRequiredLabel();
+ version.setEnabled(connInstanceTO.getBundleName() != null);
+ version.setOutputMarkupId(true);
+ version.addRequiredLabel();
+ version.getField().setOutputMarkupId(true);
+ connectorForm.add(version);
+
+ final SpinnerFieldPanel<Integer> connRequestTimeout = new SpinnerFieldPanel<>("connRequestTimeout",
+ "connRequestTimeout", Integer.class,
+ new PropertyModel<Integer>(connInstanceTO, "connRequestTimeout"), 0, null);
+ connRequestTimeout.getField().add(new RangeValidator<>(0, Integer.MAX_VALUE));
+ connectorForm.add(connRequestTimeout);
+
+ if (connInstanceTO.getPoolConf() == null) {
+ connInstanceTO.setPoolConf(new ConnPoolConfTO());
+ }
+ final SpinnerFieldPanel<Integer> poolMaxObjects = new SpinnerFieldPanel<>("poolMaxObjects", "poolMaxObjects",
+ Integer.class,
+ new PropertyModel<Integer>(connInstanceTO.getPoolConf(), "maxObjects"), 0, null);
+ poolMaxObjects.getField().add(new RangeValidator<>(0, Integer.MAX_VALUE));
+ connectorForm.add(poolMaxObjects);
+ final SpinnerFieldPanel<Integer> poolMinIdle = new SpinnerFieldPanel<>("poolMinIdle", "poolMinIdle",
+ Integer.class,
+ new PropertyModel<Integer>(connInstanceTO.getPoolConf(), "minIdle"), 0, null);
+ poolMinIdle.getField().add(new RangeValidator<>(0, Integer.MAX_VALUE));
+ connectorForm.add(poolMinIdle);
+ final SpinnerFieldPanel<Integer> poolMaxIdle = new SpinnerFieldPanel<>("poolMaxIdle", "poolMaxIdle",
+ Integer.class,
+ new PropertyModel<Integer>(connInstanceTO.getPoolConf(), "maxIdle"), 0, null);
+ poolMaxIdle.getField().add(new RangeValidator<>(0, Integer.MAX_VALUE));
+ connectorForm.add(poolMaxIdle);
+ final SpinnerFieldPanel<Long> poolMaxWait = new SpinnerFieldPanel<>("poolMaxWait", "poolMaxWait", Long.class,
+ new PropertyModel<Long>(connInstanceTO.getPoolConf(), "maxWait"), 0L, null);
+ poolMaxWait.getField().add(new RangeValidator<>(0L, Long.MAX_VALUE));
+ connectorForm.add(poolMaxWait);
+ final SpinnerFieldPanel<Long> poolMinEvictableIdleTime = new SpinnerFieldPanel<>("poolMinEvictableIdleTime",
+ "poolMinEvictableIdleTime", Long.class,
+ new PropertyModel<Long>(connInstanceTO.getPoolConf(), "minEvictableIdleTimeMillis"),
+ 0L, null);
+ poolMinEvictableIdleTime.getField().add(new RangeValidator<>(0L, Long.MAX_VALUE));
+ connectorForm.add(poolMinEvictableIdleTime);
+
+ // form - first tab - onchange()
+ location.getField().add(new AjaxFormComponentUpdatingBehavior(Constants.ON_CHANGE) {
+
+ private static final long serialVersionUID = -1107858522700306810L;
+
+ @Override
+ protected void onUpdate(final AjaxRequestTarget target) {
+ ((DropDownChoice<String>) location.getField()).setNullValid(false);
+ connInstanceTO.setLocation(location.getModelObject());
+ target.add(location);
+
+ connectorName.setChoices(new ArrayList<>(
+ mapConnBundleTOs.get(location.getModelObject()).keySet()));
+ connectorName.setEnabled(true);
+ connectorName.getField().setModelValue(null);
+ target.add(connectorName);
+
+ version.setChoices(new ArrayList<String>());
+ version.getField().setModelValue(null);
+ version.setEnabled(false);
+ target.add(version);
+
+ properties.clear();
+ target.add(propertiesContainer);
+ }
+ });
+ connectorName.getField().add(new AjaxFormComponentUpdatingBehavior(Constants.ON_CHANGE) {
+
+ private static final long serialVersionUID = -1107858522700306810L;
+
+ @Override
+ protected void onUpdate(final AjaxRequestTarget target) {
+ ((DropDownChoice<String>) connectorName.getField()).setNullValid(false);
+ connInstanceTO.setBundleName(connectorName.getModelObject());
+ target.add(connectorName);
+
+ List<String> versions = new ArrayList<>(
+ mapConnBundleTOs.get(location.getModelObject()).get(connectorName.getModelObject()).keySet());
+ version.setChoices(versions);
+ version.setEnabled(true);
+ if (versions.size() == 1) {
+ selectVersion(target, connInstanceTO, version, versions.get(0));
+ version.getField().setModelObject(versions.get(0));
+ } else {
+ version.getField().setModelValue(null);
+ properties.clear();
+ target.add(propertiesContainer);
+ }
+ target.add(version);
+ }
+ });
+ version.getField().add(new AjaxFormComponentUpdatingBehavior(Constants.ON_CHANGE) {
+
+ private static final long serialVersionUID = -1107858522700306810L;
+
+ @Override
+ protected void onUpdate(final AjaxRequestTarget target) {
+ selectVersion(target, connInstanceTO, version, version.getModelObject());
+ }
+ });
+
+ // form - second tab (properties)
+ final ListView<ConnConfProperty> connPropView = new ConnConfPropertyListView("connectorProperties",
+ new PropertyModel<List<ConnConfProperty>>(this, "properties"),
+ true, connInstanceTO.getConfiguration());
+ connPropView.setOutputMarkupId(true);
+ connectorPropForm.add(connPropView);
+
+ final AjaxButton check = new IndicatingAjaxButton("check", new ResourceModel("check")) {
+
+ private static final long serialVersionUID = -7978723352517770644L;
+
+ @Override
+ public void onSubmit(final AjaxRequestTarget target, final Form<?> form) {
+ final ConnInstanceTO conn = (ConnInstanceTO) form.getModelObject();
+
+ // ensure that connector bundle information is in sync
+ conn.setBundleName(bundleTO.getBundleName());
+ conn.setVersion(bundleTO.getVersion());
+ conn.setConnectorName(bundleTO.getConnectorName());
+
+ if (restClient.check(conn)) {
+ info(getString("success_connection"));
+ } else {
+ error(getString("error_connection"));
+ }
+
+ feedbackPanel.refresh(target);
+ }
+ };
+ connectorPropForm.add(check);
+
+ // form - third tab (capabilities)
+ final IModel<List<ConnectorCapability>> capabilities
+ = new LoadableDetachableModel<List<ConnectorCapability>>() {
+
+ private static final long serialVersionUID = 5275935387613157437L;
+
+ @Override
+ protected List<ConnectorCapability> load() {
+ return Arrays.asList(ConnectorCapability.values());
+ }
+ };
+ CheckBoxMultipleChoice<ConnectorCapability> capabilitiesPalette = new CheckBoxMultipleChoice<>(
+ "capabilitiesPalette",
+ new PropertyModel<List<ConnectorCapability>>(this, "selectedCapabilities"), capabilities);
+
+ capabilitiesPalette.add(new AjaxFormChoiceComponentUpdatingBehavior() {
+
+ private static final long serialVersionUID = -1107858522700306810L;
+
+ @Override
+ protected void onUpdate(final AjaxRequestTarget target) {
+ }
+ });
+
+ connectorForm.add(capabilitiesPalette);
+
+ // form - submit / cancel buttons
+ final AjaxButton submit = new IndicatingAjaxButton(APPLY, new Model<>(getString(SUBMIT))) {
+
+ private static final long serialVersionUID = -958724007591692537L;
+
+ @Override
+ protected void onSubmit(final AjaxRequestTarget target, final Form<?> form) {
+ final ConnInstanceTO conn = (ConnInstanceTO) form.getModelObject();
+
+ conn.setConnectorName(bundleTO.getConnectorName());
+ conn.setBundleName(bundleTO.getBundleName());
+ conn.setVersion(bundleTO.getVersion());
+ conn.getConfiguration().clear();
+ conn.getConfiguration().addAll(connPropView.getModelObject());
+
+ // Set the model object's capabilities to capabilitiesPalette's converted Set
+ conn.getCapabilities().clear();
+ conn.getCapabilities().addAll(selectedCapabilities.isEmpty()
+ ? EnumSet.noneOf(ConnectorCapability.class)
+ : EnumSet.copyOf(selectedCapabilities));
+
+ // Reset pool configuration if all fields are null
+ if (conn.getPoolConf() != null
+ && conn.getPoolConf().getMaxIdle() == null
+ && conn.getPoolConf().getMaxObjects() == null
+ && conn.getPoolConf().getMaxWait() == null
+ && conn.getPoolConf().getMinEvictableIdleTimeMillis() == null
+ && conn.getPoolConf().getMinIdle() == null) {
+
+ conn.setPoolConf(null);
+ }
+
+ try {
+ if (connInstanceTO.getKey() == 0) {
+ restClient.create(conn);
+ } else {
+ restClient.update(conn);
+ }
+
+ ((BasePage) pageRef.getPage()).setModalResult(true);
+ window.close(target);
+ } catch (SyncopeClientException e) {
+ error(getString(Constants.ERROR) + ": " + e.getMessage());
+ feedbackPanel.refresh(target);
+ ((BasePage) pageRef.getPage()).setModalResult(false);
+ LOG.error("While creating or updating connector {}", conn, e);
+ }
+ }
+
+ @Override
+ protected void onError(final AjaxRequestTarget target, final Form<?> form) {
+ feedbackPanel.refresh(target);
+ }
+ };
+ String entitlements = connInstanceTO.getKey() == 0
+ ? Entitlement.CONNECTOR_CREATE : Entitlement.CONNECTOR_UPDATE;
+
+ MetaDataRoleAuthorizationStrategy.authorize(submit, ENABLE, entitlements);
+ connectorForm.add(submit);
+
+ final IndicatingAjaxButton cancel = new IndicatingAjaxButton(CANCEL, new ResourceModel(CANCEL)) {
+
+ private static final long serialVersionUID = -958724007591692537L;
+
+ @Override
+ protected void onSubmit(final AjaxRequestTarget target, final Form<?> form) {
+ window.close(target);
+ }
+ };
+ cancel.setDefaultFormProcessing(false);
+ connectorForm.add(cancel);
+ }
+
+ private ConnBundleTO getSelectedBundleTO(final ConnInstanceTO connInstanceTO) {
+ ConnBundleTO result = null;
+ if (connInstanceTO != null
+ && StringUtils.isNotBlank(connInstanceTO.getLocation())
+ && StringUtils.isNotBlank(connInstanceTO.getBundleName())
+ && StringUtils.isNotBlank(connInstanceTO.getVersion())
+ && mapConnBundleTOs.containsKey(connInstanceTO.getLocation())) {
+
+ Map<String, Map<String, ConnBundleTO>> byLocation = mapConnBundleTOs.get(connInstanceTO.getLocation());
+ if (byLocation.containsKey(connInstanceTO.getBundleName())) {
+ Map<String, ConnBundleTO> byName = byLocation.get(connInstanceTO.getBundleName());
+ if (byName.containsKey(connInstanceTO.getVersion())) {
+ result = byName.get(connInstanceTO.getVersion());
+ }
+ }
+ }
+ return result;
+ }
+
+ private List<ConnConfProperty> fillProperties(final ConnBundleTO bundleTO, final ConnInstanceTO connInstanceTO) {
+ final List<ConnConfProperty> props = new ArrayList<>();
+
+ if (bundleTO != null) {
+ for (ConnConfPropSchema key : bundleTO.getProperties()) {
+ final ConnConfProperty property = new ConnConfProperty();
+ property.setSchema(key);
+ if (connInstanceTO.getKey() != 0
+ && connInstanceTO.getConfigurationMap().containsKey(key.getName())
+ && connInstanceTO.getConfigurationMap().get(key.getName()).getValues() != null) {
+
+ property.getValues().addAll(connInstanceTO.getConfigurationMap().get(key.getName()).getValues());
+ property.setOverridable(connInstanceTO.getConfigurationMap().get(key.getName()).isOverridable());
+ }
+
+ if (property.getValues().isEmpty() && !key.getDefaultValues().isEmpty()) {
+ property.getValues().addAll(key.getDefaultValues());
+ }
+
+ props.add(property);
+ }
+ }
+
+ // re-order properties (implements Comparable)
+ Collections.sort(props);
+ return props;
+ }
+
+ private void selectVersion(final AjaxRequestTarget target, final ConnInstanceTO connInstanceTO,
+ final AjaxDropDownChoicePanel<String> version, final String versionValue) {
+
+ connInstanceTO.setVersion(versionValue);
+ target.add(version);
+
+ bundleTO = getSelectedBundleTO(connInstanceTO);
+ properties = fillProperties(bundleTO, connInstanceTO);
+ target.add(propertiesContainer);
+ }
+
+ public List<ConnConfProperty> getProperties() {
+ return properties;
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/34ec6712/client/console/src/main/java/org/apache/syncope/client/console/pages/ProvisioningModalPage.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/pages/ProvisioningModalPage.java b/client/console/src/main/java/org/apache/syncope/client/console/pages/ProvisioningModalPage.java
new file mode 100644
index 0000000..af1d0b5
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/pages/ProvisioningModalPage.java
@@ -0,0 +1,253 @@
+/*
+ * 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.pages;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.List;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.syncope.client.console.commons.Constants;
+import org.apache.syncope.client.console.commons.status.AbstractStatusBeanProvider;
+import org.apache.syncope.client.console.commons.status.ConnObjectWrapper;
+import org.apache.syncope.client.console.commons.status.StatusBean;
+import org.apache.syncope.client.console.commons.status.StatusUtils;
+import org.apache.syncope.client.console.panels.ActionDataTablePanel;
+import org.apache.syncope.client.console.wicket.markup.html.form.ActionLink;
+import org.apache.syncope.client.lib.SyncopeClient;
+import org.apache.syncope.common.lib.to.AbstractAttributableTO;
+import org.apache.syncope.common.lib.to.AbstractSubjectTO;
+import org.apache.syncope.common.lib.to.BulkActionResult;
+import org.apache.syncope.common.lib.to.ResourceTO;
+import org.apache.syncope.common.lib.to.GroupTO;
+import org.apache.syncope.common.lib.to.UserTO;
+import org.apache.syncope.common.lib.types.ResourceDeassociationActionType;
+import org.apache.syncope.common.lib.wrap.AbstractWrappable;
+import org.apache.syncope.common.lib.wrap.SubjectKey;
+import org.apache.wicket.PageReference;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.extensions.ajax.markup.html.modal.ModalWindow;
+import org.apache.wicket.extensions.markup.html.repeater.data.grid.ICellPopulator;
+import org.apache.wicket.extensions.markup.html.repeater.data.table.AbstractColumn;
+import org.apache.wicket.extensions.markup.html.repeater.data.table.IColumn;
+import org.apache.wicket.extensions.markup.html.repeater.data.table.ISortableDataProvider;
+import org.apache.wicket.extensions.markup.html.repeater.data.table.PropertyColumn;
+import org.apache.wicket.extensions.markup.html.repeater.util.SortParam;
+import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.markup.repeater.Item;
+import org.apache.wicket.model.IModel;
+import org.apache.wicket.model.StringResourceModel;
+
+public class ProvisioningModalPage<T extends AbstractAttributableTO> extends AbstractStatusModalPage {
+
+ private static final long serialVersionUID = -4285220460543213901L;
+
+ private static final int ROWS_PER_PAGE = 10;
+
+ private final ResourceTO resourceTO;
+
+ private final Class<? extends AbstractAttributableTO> typeRef;
+
+ private final PageReference pageRef;
+
+ private final ModalWindow window;
+
+ private final StatusUtils statusUtils;
+
+ private final String realm = "/";
+
+ public ProvisioningModalPage(
+ final PageReference pageRef,
+ final ModalWindow window,
+ final ResourceTO resourceTO,
+ final Class<T> typeRef) {
+
+ super();
+
+ this.pageRef = pageRef;
+ this.window = window;
+ this.resourceTO = resourceTO;
+ this.typeRef = typeRef;
+
+ statusUtils = new StatusUtils((UserTO.class.isAssignableFrom(typeRef) ? userRestClient : groupRestClient));
+
+ add(new Label("displayName", StringUtils.EMPTY));
+
+ final List<IColumn<StatusBean, String>> columns = new ArrayList<>();
+ columns.add(new PropertyColumn<StatusBean, String>(
+ new StringResourceModel("key", this, null, "Attributable key"),
+ "attributableKey", "attributableKey"));
+ columns.add(new PropertyColumn<StatusBean, String>(
+ new StringResourceModel("name", this, null, "Attributable name"),
+ "attributableName", "attributableName"));
+ columns.add(new PropertyColumn<StatusBean, String>(
+ new StringResourceModel("resourceName", this, null, "Resource name"),
+ "resourceName", "resourceName"));
+ columns.add(new PropertyColumn<StatusBean, String>(
+ new StringResourceModel("accountLink", this, null, "Account link"),
+ "accountLink", "accountLink"));
+ columns.add(new AbstractColumn<StatusBean, String>(
+ new StringResourceModel("status", this, null, "")) {
+
+ private static final long serialVersionUID = -3503023501954863131L;
+
+ @Override
+ public String getCssClass() {
+ return "action";
+ }
+
+ @Override
+ public void populateItem(
+ final Item<ICellPopulator<StatusBean>> cellItem,
+ final String componentId,
+ final IModel<StatusBean> model) {
+ cellItem.
+ add(statusUtils.getStatusImagePanel(componentId, model.getObject().getStatus()));
+ }
+ });
+
+ final ActionDataTablePanel<StatusBean, String> table = new ActionDataTablePanel<>(
+ "resourceDatatable",
+ columns,
+ (ISortableDataProvider<StatusBean, String>) new StatusBeanProvider(),
+ ROWS_PER_PAGE,
+ pageRef);
+
+ final String pageId = "Resources";
+
+ table.addAction(new ActionLink() {
+
+ private static final long serialVersionUID = -3722207913631435501L;
+
+ @Override
+ public void onClick(final AjaxRequestTarget target) {
+ try {
+ bulkAssociationAction(target, ResourceDeassociationActionType.UNLINK, table, columns);
+ } catch (Exception e) {
+ LOG.error("Error unlinkink resources", e);
+ error(getString(Constants.ERROR) + ": " + e.getMessage());
+ feedbackPanel.refresh(target);
+ }
+ }
+ }, ActionLink.ActionType.UNLINK, pageId);
+
+ table.addAction(new ActionLink() {
+
+ private static final long serialVersionUID = -3722207913631435501L;
+
+ @Override
+ public void onClick(final AjaxRequestTarget target) {
+ try {
+ bulkAssociationAction(target, ResourceDeassociationActionType.DEPROVISION, table, columns);
+ } catch (Exception e) {
+ LOG.error("Error de-provisioning user", e);
+ error(getString(Constants.ERROR) + ": " + e.getMessage());
+ feedbackPanel.refresh(target);
+ }
+ }
+ }, ActionLink.ActionType.DEPROVISION, pageId);
+
+ table.addAction(new ActionLink() {
+
+ private static final long serialVersionUID = -3722207913631435501L;
+
+ @Override
+ public void onClick(final AjaxRequestTarget target) {
+ try {
+ bulkAssociationAction(target, ResourceDeassociationActionType.UNASSIGN, table, columns);
+ } catch (Exception e) {
+ LOG.error("Error unassigning resources", e);
+ error(getString(Constants.ERROR) + ": " + e.getMessage());
+ feedbackPanel.refresh(target);
+ }
+ }
+ }, ActionLink.ActionType.UNASSIGN, pageId);
+
+ table.addCancelButton(window);
+
+ add(table);
+ }
+
+ private class StatusBeanProvider extends AbstractStatusBeanProvider {
+
+ private static final long serialVersionUID = 4287357360778016173L;
+
+ public StatusBeanProvider() {
+ super("accountLink");
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public List<StatusBean> getStatusBeans() {
+ final String fiql = SyncopeClient.getUserSearchConditionBuilder().hasResources(resourceTO.getKey()).query();
+
+ final List<T> subjects = new ArrayList<>();
+ if (UserTO.class.isAssignableFrom(typeRef)) {
+ subjects.addAll((List<T>) userRestClient.search(
+ realm, fiql, 1, ROWS_PER_PAGE, new SortParam<>("key", true)));
+ } else {
+ subjects.addAll((List<T>) groupRestClient.search(
+ realm, fiql, 1, ROWS_PER_PAGE, new SortParam<>("key", true)));
+ }
+
+ final List<ConnObjectWrapper> connObjects = statusUtils.getConnectorObjects(
+ (List<AbstractSubjectTO>) subjects, Collections.<String>singleton(resourceTO.getKey()));
+
+ final List<StatusBean> statusBeans = new ArrayList<>(connObjects.size() + 1);
+ final LinkedHashMap<String, StatusBean> initialStatusBeanMap = new LinkedHashMap<>(connObjects.size());
+
+ for (ConnObjectWrapper entry : connObjects) {
+ final StatusBean statusBean = statusUtils.getStatusBean(entry.getAttributable(),
+ entry.getResourceName(),
+ entry.getConnObjectTO(),
+ GroupTO.class.isAssignableFrom(typeRef));
+
+ initialStatusBeanMap.put(entry.getResourceName(), statusBean);
+ statusBeans.add(statusBean);
+ }
+
+ return statusBeans;
+ }
+ }
+
+ private void bulkAssociationAction(
+ final AjaxRequestTarget target,
+ final ResourceDeassociationActionType type,
+ final ActionDataTablePanel<StatusBean, String> table,
+ final List<IColumn<StatusBean, String>> columns) {
+
+ final List<StatusBean> beans = new ArrayList<>(table.getModelObject());
+ List<SubjectKey> subjectKeys = new ArrayList<>();
+ for (StatusBean bean : beans) {
+ LOG.debug("Selected bean {}", bean);
+ subjectKeys.add(AbstractWrappable.getInstance(SubjectKey.class, bean.getAttributableId()));
+ }
+
+ if (beans.isEmpty()) {
+ window.close(target);
+ } else {
+ final BulkActionResult res = resourceRestClient.bulkAssociationAction(
+ resourceTO.getKey(), typeRef, type, subjectKeys);
+
+ ((BasePage) pageRef.getPage()).setModalResult(true);
+
+ setResponsePage(new BulkActionResultModalPage<>(window, beans, columns, res, "attributableKey"));
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/34ec6712/client/console/src/main/java/org/apache/syncope/client/console/pages/Realms.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/pages/Realms.java b/client/console/src/main/java/org/apache/syncope/client/console/pages/Realms.java
index 6ff73f4..daee99c 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/pages/Realms.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/pages/Realms.java
@@ -18,13 +18,160 @@
*/
package org.apache.syncope.client.console.pages;
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import org.apache.syncope.client.console.panels.Realm;
+import org.apache.syncope.client.console.rest.RealmRestClient;
+import org.apache.syncope.common.lib.to.RealmTO;
+import org.apache.wicket.MarkupContainer;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.ajax.markup.html.AjaxLink;
+import org.apache.wicket.event.Broadcast;
+import org.apache.wicket.event.IEvent;
+import org.apache.wicket.markup.html.WebMarkupContainer;
+import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.markup.html.panel.Fragment;
+import org.apache.wicket.markup.repeater.RepeatingView;
+import org.apache.wicket.model.PropertyModel;
import org.apache.wicket.request.mapper.parameter.PageParameters;
+import org.apache.wicket.spring.injection.annot.SpringBean;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
public class Realms extends BasePage {
private static final long serialVersionUID = -1100228004207271270L;
+ protected static final Logger LOG = LoggerFactory.getLogger(Realms.class);
+
+ @SpringBean
+ private RealmRestClient realmRestClient;
+
+ private final WebMarkupContainer content;
+
public Realms(final PageParameters parameters) {
super(parameters);
+
+ final List<RealmTO> realms = realmRestClient.list();
+ Collections.sort(realms, new RealmNameComparator());
+
+ add(getParentMap(realms), 0L, Realms.this);
+
+ content = new WebMarkupContainer("content");
+ content.setOutputMarkupId(true);
+ add(content);
+
+ content.add(new Label("header", "Root realm"));
+ content.add(new Label("body", "Root realm"));
+ }
+
+ private void add(final Map<Long, List<RealmTO>> parentMap, final Long key, final MarkupContainer container) {
+ final RepeatingView listItems = new RepeatingView("list");
+ container.add(listItems);
+
+ for (final RealmTO realm : parentMap.get(key)) {
+ final Fragment fragment;
+
+ final AjaxLink<Void> link = new AjaxLink<Void>("link") {
+
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public void onClick(final AjaxRequestTarget target) {
+ send(Realms.this, Broadcast.EXACT, new ControlSidebarClick<>(realm, target));
+ }
+ };
+
+ link.add(new Label("name", new PropertyModel<String>(realm, "name")));
+
+ if (parentMap.containsKey(realm.getKey()) && !parentMap.get(realm.getKey()).isEmpty()) {
+ fragment = new Fragment(String.valueOf(realm.getKey()), "withChildren", Realms.this);
+ add(parentMap, realm.getKey(), fragment);
+ } else {
+ fragment = new Fragment(String.valueOf(realm.getKey()), "withoutChildren", Realms.this);
+ }
+
+ fragment.add(link);
+ listItems.add(fragment);
+ }
+ }
+
+ private Map<Long, List<RealmTO>> getParentMap(final List<RealmTO> realms) {
+ final Map<Long, List<RealmTO>> res = new HashMap<>();
+ res.put(0L, new ArrayList<RealmTO>());
+
+ final Map<Long, List<RealmTO>> cache = new HashMap<>();
+
+ for (RealmTO realm : realms) {
+ if (res.containsKey(realm.getParent())) {
+ res.get(realm.getParent()).add(realm);
+
+ final List<RealmTO> children = new ArrayList<>();
+ res.put(realm.getKey(), children);
+
+ if (cache.containsKey(realm.getKey())) {
+ children.addAll(cache.get(realm.getKey()));
+ cache.remove(realm.getKey());
+ }
+ } else if (cache.containsKey(realm.getParent())) {
+ cache.get(realm.getParent()).add(realm);
+ } else {
+ final List<RealmTO> children = new ArrayList<>();
+ children.add(realm);
+ cache.put(realm.getParent(), children);
+ }
+ }
+
+ return res;
+ }
+
+ private static class RealmNameComparator implements Comparator<RealmTO>, Serializable {
+
+ private static final long serialVersionUID = 7085057398406518811L;
+
+ @Override
+ public int compare(final RealmTO r1, final RealmTO r2) {
+ return r1.getName().compareTo(r2.getName());
+ }
+ }
+
+ @Override
+ public void onEvent(final IEvent<?> event) {
+ super.onEvent(event);
+
+ if (event.getPayload() instanceof ControlSidebarClick) {
+ @SuppressWarnings("unchecked")
+ final ControlSidebarClick<RealmTO> controlSidebarClick = ControlSidebarClick.class.cast(event.getPayload());
+ content.addOrReplace(new Label("header", controlSidebarClick.getObj().getName()));
+ content.addOrReplace(new Realm("body", controlSidebarClick.getObj()));
+ controlSidebarClick.getTarget().add(content);
+ }
+ }
+
+ private static class ControlSidebarClick<T> {
+
+ private final AjaxRequestTarget target;
+
+ private final T obj;
+
+ public ControlSidebarClick(
+ final T obj, final AjaxRequestTarget target) {
+ this.obj = obj;
+ this.target = target;
+ }
+
+ public T getObj() {
+ return obj;
+ }
+
+ public AjaxRequestTarget getTarget() {
+ return target;
+ }
+
}
}
http://git-wip-us.apache.org/repos/asf/syncope/blob/34ec6712/client/console/src/main/java/org/apache/syncope/client/console/pages/ResourceModalPage.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/pages/ResourceModalPage.java b/client/console/src/main/java/org/apache/syncope/client/console/pages/ResourceModalPage.java
new file mode 100644
index 0000000..aa9dbfc
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/pages/ResourceModalPage.java
@@ -0,0 +1,204 @@
+/*
+ * 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.pages;
+
+import org.apache.syncope.client.console.commons.Constants;
+import org.apache.syncope.client.console.panels.AnnotatedBeanPanel;
+import org.apache.syncope.client.console.panels.ResourceConnConfPanel;
+import org.apache.syncope.client.console.panels.ResourceDetailsPanel;
+import org.apache.syncope.client.console.panels.ResourceMappingPanel;
+import org.apache.syncope.client.console.panels.ResourceSecurityPanel;
+import org.apache.syncope.common.lib.to.MappingItemTO;
+import org.apache.syncope.common.lib.to.ResourceTO;
+import org.apache.syncope.common.lib.types.AttributableType;
+import org.apache.syncope.common.lib.types.Entitlement;
+import org.apache.wicket.PageReference;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.ajax.markup.html.form.AjaxButton;
+import org.apache.wicket.authroles.authorization.strategies.role.metadata.MetaDataRoleAuthorizationStrategy;
+import org.apache.wicket.extensions.ajax.markup.html.IndicatingAjaxButton;
+import org.apache.wicket.extensions.ajax.markup.html.modal.ModalWindow;
+import org.apache.wicket.markup.html.form.Form;
+import org.apache.wicket.model.CompoundPropertyModel;
+import org.apache.wicket.model.ResourceModel;
+
+/**
+ * Modal window with Resource form.
+ */
+public class ResourceModalPage extends BaseModalPage {
+
+ private static final long serialVersionUID = 1734415311027284221L;
+
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ public ResourceModalPage(final PageReference pageRef, final ModalWindow window, final ResourceTO resourceTO,
+ final boolean createFlag) {
+
+ super();
+
+ final Form<ResourceTO> form = new Form<>(FORM);
+ form.setModel(new CompoundPropertyModel<>(resourceTO));
+
+ //--------------------------------
+ // Resource details panel
+ //--------------------------------
+ form.add(new ResourceDetailsPanel("details", resourceTO,
+ resourceRestClient.getPropagationActionsClasses(), createFlag));
+
+ form.add(new AnnotatedBeanPanel("systeminformation", resourceTO));
+ //--------------------------------
+
+ //--------------------------------
+ // Resource mapping panels
+ //--------------------------------
+ form.add(new ResourceMappingPanel("umapping", resourceTO, AttributableType.USER));
+ form.add(new ResourceMappingPanel("gmapping", resourceTO, AttributableType.GROUP));
+ //--------------------------------
+
+ //--------------------------------
+ // Resource connector configuration panel
+ //--------------------------------
+ ResourceConnConfPanel resourceConnConfPanel = new ResourceConnConfPanel("connconf", resourceTO, createFlag);
+ MetaDataRoleAuthorizationStrategy.authorize(resourceConnConfPanel, ENABLE, Entitlement.CONNECTOR_READ);
+ form.add(resourceConnConfPanel);
+ //--------------------------------
+
+ //--------------------------------
+ // Resource security panel
+ //--------------------------------
+ form.add(new ResourceSecurityPanel("security", resourceTO));
+ //--------------------------------
+
+ final AjaxButton submit = new IndicatingAjaxButton(APPLY, new ResourceModel(SUBMIT, SUBMIT)) {
+
+ private static final long serialVersionUID = -958724007591692537L;
+
+ @Override
+ protected void onSubmit(final AjaxRequestTarget target, final Form<?> form) {
+ final ResourceTO resourceTO = (ResourceTO) form.getDefaultModelObject();
+
+ boolean accountIdError = false;
+
+ if (resourceTO.getUmapping() == null || resourceTO.getUmapping().getItems().isEmpty()) {
+ resourceTO.setUmapping(null);
+ } else {
+ int uAccountIdCount = 0;
+ for (MappingItemTO item : resourceTO.getUmapping().getItems()) {
+ if (item.isAccountid()) {
+ uAccountIdCount++;
+ }
+ }
+ accountIdError = uAccountIdCount != 1;
+ }
+
+ if (resourceTO.getGmapping() == null || resourceTO.getGmapping().getItems().isEmpty()) {
+ resourceTO.setGmapping(null);
+ } else {
+ int rAccountIdCount = 0;
+ for (MappingItemTO item : resourceTO.getGmapping().getItems()) {
+ if (item.isAccountid()) {
+ rAccountIdCount++;
+ }
+ }
+ accountIdError |= rAccountIdCount != 1;
+ }
+
+ if (accountIdError) {
+ error(getString("accountIdValidation"));
+ feedbackPanel.refresh(target);
+ } else {
+ try {
+ if (createFlag) {
+ resourceRestClient.create(resourceTO);
+ } else {
+ resourceRestClient.update(resourceTO);
+ }
+
+ if (pageRef != null && pageRef.getPage() instanceof AbstractBasePage) {
+ ((AbstractBasePage) pageRef.getPage()).setModalResult(true);
+ }
+ window.close(target);
+ } catch (Exception e) {
+ LOG.error("Failure managing resource {}", resourceTO, e);
+ error(getString(Constants.ERROR) + ": " + e.getMessage());
+ feedbackPanel.refresh(target);
+ }
+ }
+ }
+
+ @Override
+ protected void onError(final AjaxRequestTarget target, final Form<?> form) {
+ feedbackPanel.refresh(target);
+ }
+ };
+
+ form.add(submit);
+ form.setDefaultButton(submit);
+
+ final AjaxButton cancel = new IndicatingAjaxButton(CANCEL, new ResourceModel(CANCEL)) {
+
+ private static final long serialVersionUID = -958724007591692537L;
+
+ @Override
+ protected void onSubmit(final AjaxRequestTarget target, final Form<?> form) {
+ window.close(target);
+ }
+
+ @Override
+ protected void onError(final AjaxRequestTarget target, final Form<?> form) {
+ }
+ };
+
+ cancel.setDefaultFormProcessing(false);
+ form.add(cancel);
+
+ add(form);
+
+ MetaDataRoleAuthorizationStrategy.authorize(
+ submit, ENABLE, createFlag ? Entitlement.RESOURCE_CREATE : Entitlement.RESOURCE_UPDATE);
+ }
+
+ /**
+ * Generic resource event.
+ */
+ public static class ResourceEvent {
+
+ /**
+ * Request target.
+ */
+ private final AjaxRequestTarget target;
+
+ /**
+ * Constructor.
+ *
+ * @param target request target.
+ */
+ public ResourceEvent(final AjaxRequestTarget target) {
+ this.target = target;
+ }
+
+ /**
+ * Target getter.
+ *
+ * @return request target.
+ */
+ public AjaxRequestTarget getTarget() {
+ return target;
+ }
+ }
+}