You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@syncope.apache.org by il...@apache.org on 2015/06/10 14:34:52 UTC

[17/27] syncope git commit: [SYNCOPE-156] working with resource and connector topology

http://git-wip-us.apache.org/repos/asf/syncope/blob/34ec6712/client/console/src/main/java/org/apache/syncope/client/console/topology/TopologyNodePanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/topology/TopologyNodePanel.java b/client/console/src/main/java/org/apache/syncope/client/console/topology/TopologyNodePanel.java
new file mode 100644
index 0000000..e0b9066
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/topology/TopologyNodePanel.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.topology;
+
+import java.text.MessageFormat;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.syncope.client.console.commons.Constants;
+import org.apache.syncope.client.console.pages.ResourceModalPage;
+import org.apache.syncope.client.console.rest.BaseRestClient;
+import org.apache.syncope.client.console.rest.ResourceRestClient;
+import org.apache.syncope.common.lib.SyncopeClientException;
+import org.apache.wicket.AttributeModifier;
+import org.apache.wicket.Page;
+import org.apache.wicket.PageReference;
+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.markup.html.basic.Label;
+import org.apache.wicket.markup.html.panel.Fragment;
+import org.apache.wicket.markup.html.panel.Panel;
+import org.apache.wicket.model.ResourceModel;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class TopologyNodePanel extends Panel {
+
+    private static final long serialVersionUID = -8775095410207013913L;
+
+    protected static final Logger LOG = LoggerFactory.getLogger(TopologyNodePanel.class);
+
+    private static final int RESOURCE_MODAL_WIN_HEIGHT = 600;
+
+    private static final int RESOURCE_MODAL_WIN_WIDTH = 800;
+
+    public TopologyNodePanel(
+            final String id, final TopologyNode node, final PageReference pageRef, final BaseRestClient restClient) {
+        super(id);
+
+        final String resourceName = node.getDisplayName().length() > 20
+                ? node.getDisplayName().subSequence(0, 19) + "..."
+                : node.getDisplayName();
+
+        add(new Label("label", resourceName));
+
+        final String title;
+
+        switch (node.getKind()) {
+            case SYNCOPE:
+                title = "";
+                add(getSyncopeFragment(node, (ResourceRestClient) restClient, pageRef));
+                break;
+            case CONNECTOR_SERVER:
+                title = node.getDisplayName();
+                add(getConnectorServerFragment(node, (ResourceRestClient) restClient, pageRef));
+                break;
+            case CONNECTOR:
+                title = (StringUtils.isBlank(node.getConnectionDisplayName())
+                        ? "" : node.getConnectionDisplayName() + ":") + node.getDisplayName();
+                add(getConnectorFragment(node, (ResourceRestClient) restClient, pageRef));
+                break;
+            default:
+                title = node.getDisplayName().length() > 20 ? node.getDisplayName() : "";
+                add(getResurceFragment(node, (ResourceRestClient) restClient, pageRef));
+        }
+
+        if (StringUtils.isNotEmpty(title)) {
+            add(AttributeModifier.append("data-original-title", title));
+        }
+
+        this.setMarkupId(node.getDisplayName());
+    }
+
+    private Fragment getSyncopeFragment(
+            final TopologyNode node, final ResourceRestClient restClient, final PageReference pageRef) {
+        final Fragment fragment = new Fragment("actions", "syncopeActions", this);
+
+        final ModalWindow createWin = new ModalWindow("createWin");
+        fragment.add(createWin);
+
+        createWin.setCssClassName(ModalWindow.CSS_CLASS_GRAY);
+        createWin.setInitialHeight(RESOURCE_MODAL_WIN_HEIGHT);
+        createWin.setInitialWidth(RESOURCE_MODAL_WIN_WIDTH);
+        createWin.setTitle(new ResourceModel("connector.new"));
+        createWin.setCookieName("connector-modal");
+
+        return fragment;
+    }
+
+    private Fragment getConnectorServerFragment(
+            final TopologyNode node, final ResourceRestClient restClient, final PageReference pageRef) {
+        final Fragment fragment = new Fragment("actions", "syncopeActions", this);
+
+        final ModalWindow createWin = new ModalWindow("createWin");
+        fragment.add(createWin);
+
+        createWin.setCssClassName(ModalWindow.CSS_CLASS_GRAY);
+        createWin.setInitialHeight(RESOURCE_MODAL_WIN_HEIGHT);
+        createWin.setInitialWidth(RESOURCE_MODAL_WIN_WIDTH);
+        createWin.setCookieName("connector-modal");
+        createWin.setTitle(new ResourceModel("connector.new"));
+
+        return fragment;
+    }
+
+    private Fragment getConnectorFragment(
+            final TopologyNode node, final ResourceRestClient restClient, final PageReference pageRef) {
+        final Fragment fragment = new Fragment("actions", "connectorWithNoResourceActions", this);
+
+        final ModalWindow createWin = new ModalWindow("createWin");
+        fragment.add(createWin);
+
+        createWin.setCssClassName(ModalWindow.CSS_CLASS_GRAY);
+        createWin.setInitialHeight(RESOURCE_MODAL_WIN_HEIGHT);
+        createWin.setInitialWidth(RESOURCE_MODAL_WIN_WIDTH);
+        createWin.setCookieName("resource-modal");
+        createWin.setTitle(new ResourceModel("resource.new"));
+
+        final ModalWindow editWin = new ModalWindow("editWin");
+        fragment.add(editWin);
+
+        editWin.setCssClassName(ModalWindow.CSS_CLASS_GRAY);
+        editWin.setInitialHeight(RESOURCE_MODAL_WIN_HEIGHT);
+        editWin.setInitialWidth(RESOURCE_MODAL_WIN_WIDTH);
+        editWin.setCookieName("connector-modal");
+        editWin.setTitle(MessageFormat.format(getString("connector.edit"), node.getKey()));
+
+        return fragment;
+    }
+
+    private Fragment getResurceFragment(
+            final TopologyNode node, final ResourceRestClient restClient, final PageReference pageRef) {
+        final Fragment fragment = new Fragment("actions", "resourceActions", this);
+
+        final ModalWindow editWin = new ModalWindow("editWin");
+        fragment.add(editWin);
+
+        editWin.setCssClassName(ModalWindow.CSS_CLASS_GRAY);
+        editWin.setInitialHeight(RESOURCE_MODAL_WIN_HEIGHT);
+        editWin.setInitialWidth(RESOURCE_MODAL_WIN_WIDTH);
+        editWin.setCookieName("resource-modal");
+        editWin.setTitle(MessageFormat.format(getString("resource.edit"), node.getKey()));
+
+        final AjaxLink<String> delete = new IndicatingAjaxLink<String>("delete") {
+
+            private static final long serialVersionUID = 3776750333491622263L;
+
+            @Override
+            public void onClick(final AjaxRequestTarget target) {
+                try {
+                    restClient.delete(node.getKey().toString());
+                    target.appendJavaScript(String.format("jsPlumb.remove('%s');", node.getDisplayName()));
+                    info(getString(Constants.OPERATION_SUCCEEDED));
+                } catch (SyncopeClientException e) {
+                    error(getString(Constants.ERROR) + ": " + e.getMessage());
+                    LOG.error("While deleting resource {}", node.getKey(), e);
+                }
+            }
+        };
+        fragment.add(delete);
+
+        final AjaxLink<String> edit = new IndicatingAjaxLink<String>("edit") {
+
+            private static final long serialVersionUID = 3776750333491622263L;
+
+            @Override
+            public void onClick(final AjaxRequestTarget target) {
+                editWin.setPageCreator(new ModalWindow.PageCreator() {
+
+                    private static final long serialVersionUID = -7834632442532690940L;
+
+                    @Override
+                    public Page createPage() {
+                        return new ResourceModalPage(
+                                pageRef,
+                                editWin,
+                                restClient.read(node.getKey().toString()),
+                                false);
+                    }
+                });
+
+                editWin.show(target);
+            }
+        };
+        fragment.add(edit);
+
+        return fragment;
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/34ec6712/client/console/src/main/java/org/apache/syncope/client/console/topology/TopologyReloadBehavior.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/topology/TopologyReloadBehavior.java b/client/console/src/main/java/org/apache/syncope/client/console/topology/TopologyReloadBehavior.java
new file mode 100644
index 0000000..434c7ea
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/topology/TopologyReloadBehavior.java
@@ -0,0 +1,61 @@
+/*
+ * 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.topology;
+
+import org.apache.wicket.Component;
+import org.apache.wicket.behavior.Behavior;
+import org.apache.wicket.markup.head.IHeaderResponse;
+import org.apache.wicket.markup.head.OnLoadHeaderItem;
+
+public class TopologyReloadBehavior extends Behavior {
+
+    private static final long serialVersionUID = 1L;
+
+    private final String source;
+
+    private final String target;
+
+    private final TopologyNode.Status status;
+
+    public TopologyReloadBehavior(final String source, final String target, final TopologyNode.Status status) {
+        this.source = source;
+        this.target = target;
+        this.status = status;
+    }
+
+    @Override
+    public void renderHead(final Component component, final IHeaderResponse response) {
+
+        switch (status) {
+            case UNKNOWN:
+                response.render(OnLoadHeaderItem.forScript(String.format("unknown('%s', '%s')", source, target)));
+                break;
+            case REACHABLE:
+                response.render(OnLoadHeaderItem.forScript(String.format("enable('%s', '%s')", source, target)));
+                break;
+            case UNREACHABLE:
+                response.render(OnLoadHeaderItem.forScript(String.format("disable('%s', '%s')", source, target)));
+                break;
+            default:
+                response.render(OnLoadHeaderItem.forScript(String.format("failure('%s', '%s')", source, target)));
+            // remove subtree
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/34ec6712/client/console/src/main/java/org/apache/syncope/client/console/wicket/ajax/markup/html/ClearIndicatingAjaxButton.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wicket/ajax/markup/html/ClearIndicatingAjaxButton.java b/client/console/src/main/java/org/apache/syncope/client/console/wicket/ajax/markup/html/ClearIndicatingAjaxButton.java
new file mode 100644
index 0000000..37cc455
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wicket/ajax/markup/html/ClearIndicatingAjaxButton.java
@@ -0,0 +1,76 @@
+/*
+ * 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.wicket.ajax.markup.html;
+
+import org.apache.syncope.client.console.pages.BasePage;
+import org.apache.wicket.Page;
+import org.apache.wicket.PageReference;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.extensions.ajax.markup.html.IndicatingAjaxButton;
+import org.apache.wicket.markup.html.form.Form;
+import org.apache.wicket.model.IModel;
+
+public abstract class ClearIndicatingAjaxButton extends IndicatingAjaxButton {
+
+    private static final long serialVersionUID = 7206379812788748287L;
+
+    private final PageReference pageRef;
+
+    private boolean reloadFeebackPanel = true;
+
+    public ClearIndicatingAjaxButton(final String id, final PageReference pageRef) {
+        super(id);
+        this.pageRef = pageRef;
+    }
+
+    public ClearIndicatingAjaxButton(final String id, final Form<?> form, final PageReference pageRef) {
+        super(id, form);
+        this.pageRef = pageRef;
+    }
+
+    public ClearIndicatingAjaxButton(final String id, final IModel<String> model, final PageReference pageRef) {
+        super(id, model);
+        this.pageRef = pageRef;
+    }
+
+    public ClearIndicatingAjaxButton(final String id, final IModel<String> model, final Form<?> form,
+            final PageReference pageRef) {
+
+        super(id, model, form);
+        this.pageRef = pageRef;
+    }
+
+    protected abstract void onSubmitInternal(final AjaxRequestTarget target, final Form<?> form);
+
+    public ClearIndicatingAjaxButton feedbackPanelAutomaticReload(final boolean reloadFeedbackPanel) {
+        this.reloadFeebackPanel = reloadFeedbackPanel;
+        return this;
+    }
+
+    @Override
+    protected final void onSubmit(final AjaxRequestTarget target, final Form<?> form) {
+        super.onSubmit(target, form);
+
+        Page page = pageRef.getPage();
+        if (reloadFeebackPanel && page instanceof BasePage) {
+            target.add(((BasePage) page).getFeedbackPanel());
+        }
+        onSubmitInternal(target, form);
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/34ec6712/client/console/src/main/java/org/apache/syncope/client/console/wicket/ajax/markup/html/ClearIndicatingAjaxLink.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wicket/ajax/markup/html/ClearIndicatingAjaxLink.java b/client/console/src/main/java/org/apache/syncope/client/console/wicket/ajax/markup/html/ClearIndicatingAjaxLink.java
new file mode 100644
index 0000000..e052846
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wicket/ajax/markup/html/ClearIndicatingAjaxLink.java
@@ -0,0 +1,61 @@
+/*
+ * 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.wicket.ajax.markup.html;
+
+import org.apache.syncope.client.console.pages.BasePage;
+import org.apache.wicket.Page;
+import org.apache.wicket.PageReference;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.extensions.ajax.markup.html.IndicatingAjaxLink;
+import org.apache.wicket.model.IModel;
+
+public abstract class ClearIndicatingAjaxLink<T> extends IndicatingAjaxLink<T> {
+
+    private static final long serialVersionUID = 7913625094362339643L;
+
+    private final PageReference pageRef;
+
+    private boolean reloadFeedbackPanel = true;
+
+    public ClearIndicatingAjaxLink(final String id, final PageReference pageRef) {
+        super(id);
+        this.pageRef = pageRef;
+    }
+
+    public ClearIndicatingAjaxLink(final String id, final IModel<T> model, final PageReference pageRef) {
+        super(id, model);
+        this.pageRef = pageRef;
+    }
+
+    public ClearIndicatingAjaxLink<T> feedbackPanelAutomaticReload(final boolean reloadFeedbackPanel) {
+        this.reloadFeedbackPanel = reloadFeedbackPanel;
+        return this;
+    }
+
+    protected abstract void onClickInternal(final AjaxRequestTarget target);
+
+    @Override
+    public final void onClick(final AjaxRequestTarget target) {
+        Page page = pageRef.getPage();
+        if (reloadFeedbackPanel && page instanceof BasePage) {
+            target.add(((BasePage) page).getFeedbackPanel());
+        }
+        onClickInternal(target);
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/34ec6712/client/console/src/main/java/org/apache/syncope/client/console/wicket/extensions/markup/html/repeater/data/table/ActionResultColumn.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wicket/extensions/markup/html/repeater/data/table/ActionResultColumn.java b/client/console/src/main/java/org/apache/syncope/client/console/wicket/extensions/markup/html/repeater/data/table/ActionResultColumn.java
new file mode 100644
index 0000000..013fa3a
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wicket/extensions/markup/html/repeater/data/table/ActionResultColumn.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.wicket.extensions.markup.html.repeater.data.table;
+
+import java.beans.PropertyDescriptor;
+import org.apache.syncope.common.lib.to.BulkActionResult;
+import org.apache.syncope.common.lib.to.BulkActionResult.Status;
+import org.apache.wicket.Component;
+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.markup.html.basic.Label;
+import org.apache.wicket.markup.repeater.Item;
+import org.apache.wicket.model.IModel;
+import org.apache.wicket.model.Model;
+import org.apache.wicket.model.ResourceModel;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.BeanUtils;
+
+public class ActionResultColumn<T, S> extends AbstractColumn<T, S> {
+
+    private static final long serialVersionUID = 7955560320949560716L;
+
+    /**
+     * Logger.
+     */
+    private static final Logger LOG = LoggerFactory.getLogger(ActionResultColumn.class);
+
+    private final BulkActionResult results;
+
+    private final String idFieldName;
+
+    public ActionResultColumn(final BulkActionResult results, final String idFieldName) {
+        super(new Model<String>());
+        this.results = results;
+        this.idFieldName = idFieldName;
+    }
+
+    @Override
+    public String getCssClass() {
+        return "bulkResultColumn";
+    }
+
+    @Override
+    public Component getHeader(final String componentId) {
+        return new Label(componentId, new ResourceModel("bulkActionResultLabel", "Result"));
+    }
+
+    @Override
+    public void populateItem(final Item<ICellPopulator<T>> item, final String componentId, final IModel<T> rowModel) {
+        try {
+            final PropertyDescriptor propDesc = BeanUtils.getPropertyDescriptor(rowModel.getObject().getClass(),
+                    idFieldName);
+            final Object id = propDesc.getReadMethod().invoke(rowModel.getObject(), new Object[0]);
+            final Status status = id == null ? null : results.getResultMap().get(id.toString());
+            item.add(new Label(componentId, status == null ? Status.SUCCESS : status.toString()));
+        } catch (Exception e) {
+            LOG.error("Errore retrieving target id value", e);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/34ec6712/client/console/src/main/java/org/apache/syncope/client/console/wicket/extensions/markup/html/repeater/data/table/CheckBoxGroupSelectorPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wicket/extensions/markup/html/repeater/data/table/CheckBoxGroupSelectorPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/wicket/extensions/markup/html/repeater/data/table/CheckBoxGroupSelectorPanel.java
new file mode 100644
index 0000000..8f880b7
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wicket/extensions/markup/html/repeater/data/table/CheckBoxGroupSelectorPanel.java
@@ -0,0 +1,34 @@
+/*
+ * 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.wicket.extensions.markup.html.repeater.data.table;
+
+import org.apache.wicket.markup.html.form.CheckGroup;
+import org.apache.wicket.markup.html.form.CheckGroupSelector;
+import org.apache.wicket.markup.html.panel.Panel;
+
+public class CheckBoxGroupSelectorPanel<T> extends Panel {
+
+    private static final long serialVersionUID = 4062106303929176865L;
+
+    public CheckBoxGroupSelectorPanel(final String componentId, final CheckGroup<T> group) {
+
+        super(componentId);
+        add(new CheckGroupSelector("groupselector", group));
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/34ec6712/client/console/src/main/java/org/apache/syncope/client/console/wicket/extensions/markup/html/repeater/data/table/CheckBoxPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wicket/extensions/markup/html/repeater/data/table/CheckBoxPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/wicket/extensions/markup/html/repeater/data/table/CheckBoxPanel.java
new file mode 100644
index 0000000..6270a0f
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wicket/extensions/markup/html/repeater/data/table/CheckBoxPanel.java
@@ -0,0 +1,43 @@
+/*
+ * 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.wicket.extensions.markup.html.repeater.data.table;
+
+import org.apache.syncope.client.console.commons.ActionTableCheckGroup;
+import org.apache.wicket.markup.html.form.Check;
+import org.apache.wicket.markup.html.form.CheckGroup;
+import org.apache.wicket.markup.html.panel.Panel;
+import org.apache.wicket.model.IModel;
+
+public class CheckBoxPanel<T> extends Panel {
+
+    private static final long serialVersionUID = 4062106303929176865L;
+
+    private final Check<T> check;
+
+    public CheckBoxPanel(final String componentId, final IModel<T> model, final CheckGroup<T> checkGroup) {
+        super(componentId, model);
+        this.check = new Check<>("check", model, checkGroup);
+        if (checkGroup instanceof ActionTableCheckGroup) {
+            boolean checkable = ((ActionTableCheckGroup<T>) checkGroup).isCheckable(model.getObject());
+            this.check.setEnabled(checkable);
+            this.check.setVisible(checkable);
+        }
+        add(this.check);
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/34ec6712/client/console/src/main/java/org/apache/syncope/client/console/wicket/extensions/markup/html/repeater/data/table/CheckGroupColumn.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wicket/extensions/markup/html/repeater/data/table/CheckGroupColumn.java b/client/console/src/main/java/org/apache/syncope/client/console/wicket/extensions/markup/html/repeater/data/table/CheckGroupColumn.java
new file mode 100644
index 0000000..6a9dcd6
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wicket/extensions/markup/html/repeater/data/table/CheckGroupColumn.java
@@ -0,0 +1,54 @@
+/*
+ * 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.wicket.extensions.markup.html.repeater.data.table;
+
+import org.apache.wicket.Component;
+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.markup.html.form.CheckGroup;
+import org.apache.wicket.markup.repeater.Item;
+import org.apache.wicket.model.IModel;
+import org.apache.wicket.model.Model;
+
+public class CheckGroupColumn<T, S> extends AbstractColumn<T, S> {
+
+    private static final long serialVersionUID = 7955560320949560715L;
+
+    private final CheckGroup<T> group;
+
+    public CheckGroupColumn(final CheckGroup<T> checkGroup) {
+        super(new Model<String>());
+        this.group = checkGroup;
+    }
+
+    @Override
+    public String getCssClass() {
+        return "checkGroupColumn";
+    }
+
+    @Override
+    public Component getHeader(final String componentId) {
+        return new CheckBoxGroupSelectorPanel<>(componentId, group);
+    }
+
+    @Override
+    public void populateItem(final Item<ICellPopulator<T>> item, final String componentId, final IModel<T> rowModel) {
+        item.add(new CheckBoxPanel<>(componentId, rowModel, group));
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/34ec6712/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/ActionLink.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/ActionLink.java b/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/ActionLink.java
new file mode 100644
index 0000000..71bcc0f
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/ActionLink.java
@@ -0,0 +1,85 @@
+/*
+ * 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.wicket.markup.html.form;
+
+import java.io.Serializable;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+
+public abstract class ActionLink implements Serializable {
+
+    private static final long serialVersionUID = 7031329706998320639L;
+
+    private boolean reloadFeedbackPanel = true;
+
+    public enum ActionType {
+
+        CREATE("create"),
+        EDIT("read"),
+        USER_TEMPLATE("read"),
+        GROUP_TEMPLATE("read"),
+        RESET("update"),
+        ENABLE("update"),
+        SEARCH("read"),
+        DELETE("delete"),
+        EXECUTE("execute"),
+        DRYRUN("execute"),
+        CLAIM("claim"),
+        SELECT("read"),
+        EXPORT("read"),
+        SUSPEND("update"),
+        REACTIVATE("update"),
+        RELOAD("reload"),
+        CHANGE_VIEW("changeView"),
+        UNLINK("update"),
+        LINK("update"),
+        UNASSIGN("update"),
+        ASSIGN("update"),
+        DEPROVISION("update"),
+        PROVISION("update"),
+        MANAGE_RESOURCES("update"),
+        MANAGE_USERS("update"),
+        MANAGE_GROUPS("update"),
+        ZOOM_IN("zoomin"),
+        ZOOM_OUT("zoomout");
+
+        private final String actionId;
+
+        private ActionType(final String actionId) {
+            this.actionId = actionId;
+        }
+
+        public String getActionId() {
+            return actionId;
+        }
+    }
+
+    public abstract void onClick(final AjaxRequestTarget target);
+
+    public void postClick() {
+    }
+
+    public boolean feedbackPanelAutomaticReload() {
+        return reloadFeedbackPanel;
+    }
+
+    public ActionLink feedbackPanelAutomaticReload(final boolean reloadFeedbackPanel) {
+        this.reloadFeedbackPanel = reloadFeedbackPanel;
+        return this;
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/34ec6712/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/ActionLinksPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/ActionLinksPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/ActionLinksPanel.java
new file mode 100644
index 0000000..433f9f5
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/ActionLinksPanel.java
@@ -0,0 +1,609 @@
+/*
+ * 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.wicket.markup.html.form;
+
+import org.apache.syncope.client.console.wicket.ajax.markup.html.ClearIndicatingAjaxLink;
+import org.apache.syncope.client.console.wicket.ajax.markup.html.IndicatingOnConfirmAjaxLink;
+import org.apache.wicket.PageReference;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.authroles.authorization.strategies.role.metadata.MetaDataRoleAuthorizationStrategy;
+import org.apache.wicket.markup.html.panel.Fragment;
+import org.apache.wicket.markup.html.panel.Panel;
+import org.apache.wicket.model.IModel;
+
+/**
+ * This empty class must exist because there not seems to be alternative to provide specialized HTML for edit links.
+ */
+public class ActionLinksPanel extends Panel {
+
+    private static final long serialVersionUID = 322966537010107771L;
+
+    private final PageReference pageRef;
+
+    public ActionLinksPanel(final String componentId, final IModel<?> model, final PageReference pageRef) {
+        super(componentId, model);
+        this.pageRef = pageRef;
+
+        super.add(new Fragment("panelClaim", "emptyFragment", this));
+        super.add(new Fragment("panelManageResources", "emptyFragment", this));
+        super.add(new Fragment("panelManageUsers", "emptyFragment", this));
+        super.add(new Fragment("panelManageGroups", "emptyFragment", this));
+        super.add(new Fragment("panelCreate", "emptyFragment", this));
+        super.add(new Fragment("panelEdit", "emptyFragment", this));
+        super.add(new Fragment("panelReset", "emptyFragment", this));
+        super.add(new Fragment("panelUserTemplate", "emptyFragment", this));
+        super.add(new Fragment("panelGroupTemplate", "emptyFragment", this));
+        super.add(new Fragment("panelEnable", "emptyFragment", this));
+        super.add(new Fragment("panelSearch", "emptyFragment", this));
+        super.add(new Fragment("panelDelete", "emptyFragment", this));
+        super.add(new Fragment("panelExecute", "emptyFragment", this));
+        super.add(new Fragment("panelDryRun", "emptyFragment", this));
+        super.add(new Fragment("panelSelect", "emptyFragment", this));
+        super.add(new Fragment("panelExport", "emptyFragment", this));
+        super.add(new Fragment("panelSuspend", "emptyFragment", this));
+        super.add(new Fragment("panelReactivate", "emptyFragment", this));
+        super.add(new Fragment("panelReload", "emptyFragment", this));
+        super.add(new Fragment("panelChangeView", "emptyFragment", this));
+        super.add(new Fragment("panelUnlink", "emptyFragment", this));
+        super.add(new Fragment("panelLink", "emptyFragment", this));
+        super.add(new Fragment("panelUnassign", "emptyFragment", this));
+        super.add(new Fragment("panelAssign", "emptyFragment", this));
+        super.add(new Fragment("panelDeprovision", "emptyFragment", this));
+        super.add(new Fragment("panelProvision", "emptyFragment", this));
+        super.add(new Fragment("panelZoomIn", "emptyFragment", this));
+        super.add(new Fragment("panelZoomOut", "emptyFragment", this));
+
+    }
+
+    public ActionLinksPanel add(
+            final ActionLink link, final ActionLink.ActionType type, final String entitlements) {
+
+        return addWithRoles(link, type, entitlements, true);
+    }
+
+    public ActionLinksPanel add(
+            final ActionLink link, final ActionLink.ActionType type, final String entitlement, final boolean enabled) {
+
+        return addWithRoles(link, type, entitlement, enabled);
+    }
+
+    public ActionLinksPanel addWithRoles(
+            final ActionLink link, final ActionLink.ActionType type, final String entitlements) {
+
+        return addWithRoles(link, type, entitlements, true);
+    }
+
+    public ActionLinksPanel addWithRoles(
+            final ActionLink link, final ActionLink.ActionType type, final String entitlements, final boolean enabled) {
+
+        Fragment fragment = null;
+
+        switch (type) {
+
+            case CLAIM:
+                fragment = new Fragment("panelClaim", "fragmentClaim", this);
+
+                fragment.addOrReplace(new ClearIndicatingAjaxLink<Void>("claimLink", pageRef) {
+
+                    private static final long serialVersionUID = -7978723352517770644L;
+
+                    @Override
+                    protected void onClickInternal(final AjaxRequestTarget target) {
+                        link.onClick(target);
+                    }
+                }.feedbackPanelAutomaticReload(link.feedbackPanelAutomaticReload()));
+                break;
+
+            case MANAGE_RESOURCES:
+                fragment = new Fragment("panelManageResources", "fragmentManageResources", this);
+
+                fragment.addOrReplace(new ClearIndicatingAjaxLink<Void>("manageResourcesLink", pageRef) {
+
+                    private static final long serialVersionUID = -6957616042924610291L;
+
+                    @Override
+                    protected void onClickInternal(final AjaxRequestTarget target) {
+                        link.onClick(target);
+                    }
+                }.feedbackPanelAutomaticReload(link.feedbackPanelAutomaticReload()));
+                break;
+
+            case MANAGE_USERS:
+                fragment = new Fragment("panelManageUsers", "fragmentManageUsers", this);
+
+                fragment.addOrReplace(new ClearIndicatingAjaxLink<Void>("manageUsersLink", pageRef) {
+
+                    private static final long serialVersionUID = -6957616042924610292L;
+
+                    @Override
+                    protected void onClickInternal(final AjaxRequestTarget target) {
+                        link.onClick(target);
+                    }
+                }.feedbackPanelAutomaticReload(link.feedbackPanelAutomaticReload()));
+                break;
+
+            case MANAGE_GROUPS:
+                fragment = new Fragment("panelManageGroups", "fragmentManageGroups", this);
+
+                fragment.addOrReplace(new ClearIndicatingAjaxLink<Void>("manageGroupsLink", pageRef) {
+
+                    private static final long serialVersionUID = -6957616042924610293L;
+
+                    @Override
+                    protected void onClickInternal(final AjaxRequestTarget target) {
+                        link.onClick(target);
+                    }
+                }.feedbackPanelAutomaticReload(link.feedbackPanelAutomaticReload()));
+                break;
+
+            case CREATE:
+                fragment = new Fragment("panelCreate", "fragmentCreate", this);
+
+                fragment.addOrReplace(new ClearIndicatingAjaxLink<Void>("createLink", pageRef) {
+
+                    private static final long serialVersionUID = -7978723352517770644L;
+
+                    @Override
+                    protected void onClickInternal(final AjaxRequestTarget target) {
+                        link.onClick(target);
+                    }
+                }.feedbackPanelAutomaticReload(link.feedbackPanelAutomaticReload()));
+                break;
+
+            case RESET:
+                fragment = new Fragment("panelReset", "fragmentReset", this);
+
+                fragment.addOrReplace(new ClearIndicatingAjaxLink<Void>("resetLink", pageRef) {
+
+                    private static final long serialVersionUID = -6957616042924610290L;
+
+                    @Override
+                    protected void onClickInternal(final AjaxRequestTarget target) {
+                        link.onClick(target);
+                    }
+                });
+                break;
+
+            case EDIT:
+                fragment = new Fragment("panelEdit", "fragmentEdit", this);
+
+                fragment.addOrReplace(new ClearIndicatingAjaxLink<Void>("editLink", pageRef) {
+
+                    private static final long serialVersionUID = -7978723352517770644L;
+
+                    @Override
+                    protected void onClickInternal(final AjaxRequestTarget target) {
+                        link.onClick(target);
+                    }
+                }.feedbackPanelAutomaticReload(link.feedbackPanelAutomaticReload()));
+                break;
+
+            case USER_TEMPLATE:
+                fragment = new Fragment("panelUserTemplate", "fragmentUserTemplate", this);
+
+                fragment.addOrReplace(new ClearIndicatingAjaxLink<Void>("userTemplateLink", pageRef) {
+
+                    private static final long serialVersionUID = -7978723352517770644L;
+
+                    @Override
+                    protected void onClickInternal(final AjaxRequestTarget target) {
+                        link.onClick(target);
+                    }
+                }.feedbackPanelAutomaticReload(link.feedbackPanelAutomaticReload()));
+                break;
+
+            case GROUP_TEMPLATE:
+                fragment = new Fragment("panelGroupTemplate", "fragmentGroupTemplate", this);
+
+                fragment.addOrReplace(new ClearIndicatingAjaxLink<Void>("groupTemplateLink", pageRef) {
+
+                    private static final long serialVersionUID = -7978723352517770644L;
+
+                    @Override
+                    protected void onClickInternal(final AjaxRequestTarget target) {
+                        link.onClick(target);
+                    }
+                }.feedbackPanelAutomaticReload(link.feedbackPanelAutomaticReload()));
+                break;
+
+            case ENABLE:
+                fragment = new Fragment("panelEnable", "fragmentEnable", this);
+
+                fragment.addOrReplace(new ClearIndicatingAjaxLink<Void>("enableLink", pageRef) {
+
+                    private static final long serialVersionUID = -7978723352517770644L;
+
+                    @Override
+                    protected void onClickInternal(final AjaxRequestTarget target) {
+                        link.onClick(target);
+                    }
+                }.feedbackPanelAutomaticReload(link.feedbackPanelAutomaticReload()));
+                break;
+
+            case SEARCH:
+                fragment = new Fragment("panelSearch", "fragmentSearch", this);
+
+                fragment.addOrReplace(new ClearIndicatingAjaxLink<Void>("searchLink", pageRef) {
+
+                    private static final long serialVersionUID = -7978723352517770644L;
+
+                    @Override
+                    protected void onClickInternal(final AjaxRequestTarget target) {
+                        link.onClick(target);
+                    }
+                }.feedbackPanelAutomaticReload(link.feedbackPanelAutomaticReload()));
+                break;
+
+            case EXECUTE:
+                fragment = new Fragment("panelExecute", "fragmentExecute", this);
+
+                fragment.addOrReplace(new ClearIndicatingAjaxLink<Void>("executeLink", pageRef) {
+
+                    private static final long serialVersionUID = -7978723352517770644L;
+
+                    @Override
+                    protected void onClickInternal(final AjaxRequestTarget target) {
+                        link.onClick(target);
+                    }
+                }.feedbackPanelAutomaticReload(link.feedbackPanelAutomaticReload()));
+                break;
+
+            case DRYRUN:
+                fragment = new Fragment("panelDryRun", "fragmentDryRun", this);
+
+                fragment.addOrReplace(new ClearIndicatingAjaxLink<Void>("dryRunLink", pageRef) {
+
+                    private static final long serialVersionUID = -7978723352517770644L;
+
+                    @Override
+                    protected void onClickInternal(final AjaxRequestTarget target) {
+                        link.onClick(target);
+                    }
+                }.feedbackPanelAutomaticReload(link.feedbackPanelAutomaticReload()));
+                break;
+
+            case DELETE:
+                fragment = new Fragment("panelDelete", "fragmentDelete", this);
+
+                fragment.addOrReplace(new IndicatingOnConfirmAjaxLink<Void>("deleteLink", pageRef) {
+
+                    private static final long serialVersionUID = -7978723352517770644L;
+
+                    @Override
+                    protected void onClickInternal(final AjaxRequestTarget target) {
+                        link.onClick(target);
+                    }
+                }.feedbackPanelAutomaticReload(link.feedbackPanelAutomaticReload()));
+
+                break;
+
+            case SELECT:
+                fragment = new Fragment("panelSelect", "fragmentSelect", this);
+
+                fragment.addOrReplace(new ClearIndicatingAjaxLink<Void>("selectLink", pageRef) {
+
+                    private static final long serialVersionUID = -7978723352517770644L;
+
+                    @Override
+                    protected void onClickInternal(final AjaxRequestTarget target) {
+                        link.onClick(target);
+                    }
+                }.feedbackPanelAutomaticReload(link.feedbackPanelAutomaticReload()));
+
+                break;
+
+            case EXPORT:
+                fragment = new Fragment("panelExport", "fragmentExport", this);
+
+                fragment.addOrReplace(new ClearIndicatingAjaxLink<Void>("exportLink", pageRef) {
+
+                    private static final long serialVersionUID = -7978723352517770644L;
+
+                    @Override
+                    protected void onClickInternal(final AjaxRequestTarget target) {
+                        link.onClick(target);
+                    }
+                }.feedbackPanelAutomaticReload(link.feedbackPanelAutomaticReload()));
+                break;
+
+            case SUSPEND:
+                fragment = new Fragment("panelSuspend", "fragmentSuspend", this);
+
+                fragment.addOrReplace(new ClearIndicatingAjaxLink<Void>("suspendLink", pageRef) {
+
+                    private static final long serialVersionUID = -6957616042924610291L;
+
+                    @Override
+                    protected void onClickInternal(final AjaxRequestTarget target) {
+                        link.onClick(target);
+                    }
+                }.feedbackPanelAutomaticReload(link.feedbackPanelAutomaticReload()));
+                break;
+
+            case REACTIVATE:
+                fragment = new Fragment("panelReactivate", "fragmentReactivate", this);
+
+                fragment.addOrReplace(new ClearIndicatingAjaxLink<Void>("reactivateLink", pageRef) {
+
+                    private static final long serialVersionUID = -6957616042924610292L;
+
+                    @Override
+                    protected void onClickInternal(final AjaxRequestTarget target) {
+                        link.onClick(target);
+                    }
+                }.feedbackPanelAutomaticReload(link.feedbackPanelAutomaticReload()));
+                break;
+
+            case RELOAD:
+                fragment = new Fragment("panelReload", "fragmentReload", this);
+
+                fragment.addOrReplace(new ClearIndicatingAjaxLink<Void>("reloadLink", pageRef) {
+
+                    private static final long serialVersionUID = -6957616042924610293L;
+
+                    @Override
+                    protected void onClickInternal(final AjaxRequestTarget target) {
+                        link.onClick(target);
+                    }
+                }.feedbackPanelAutomaticReload(link.feedbackPanelAutomaticReload()));
+                break;
+
+            case CHANGE_VIEW:
+                fragment = new Fragment("panelChangeView", "fragmentChangeView", this);
+
+                fragment.addOrReplace(new ClearIndicatingAjaxLink<Void>("changeViewLink", pageRef) {
+
+                    private static final long serialVersionUID = -6957616042924610292L;
+
+                    @Override
+                    protected void onClickInternal(final AjaxRequestTarget target) {
+                        link.onClick(target);
+                    }
+                }.feedbackPanelAutomaticReload(link.feedbackPanelAutomaticReload()));
+                break;
+
+            case UNLINK:
+                fragment = new Fragment("panelUnlink", "fragmentUnlink", this);
+
+                fragment.addOrReplace(
+                        new IndicatingOnConfirmAjaxLink<Void>("unlinkLink", pageRef, "confirmUnlink") {
+
+                            private static final long serialVersionUID = -6957616042924610293L;
+
+                            @Override
+                            protected void onClickInternal(final AjaxRequestTarget target) {
+                                link.onClick(target);
+                            }
+                        }.feedbackPanelAutomaticReload(link.feedbackPanelAutomaticReload()));
+                break;
+
+            case LINK:
+                fragment = new Fragment("panelLink", "fragmentLink", this);
+
+                fragment.addOrReplace(new ClearIndicatingAjaxLink<Void>("linkLink", pageRef) {
+
+                    private static final long serialVersionUID = -6957616042924610303L;
+
+                    @Override
+                    protected void onClickInternal(final AjaxRequestTarget target) {
+                        link.onClick(target);
+                    }
+                }.feedbackPanelAutomaticReload(link.feedbackPanelAutomaticReload()));
+                break;
+
+            case UNASSIGN:
+                fragment = new Fragment("panelUnassign", "fragmentUnassign", this);
+
+                fragment.addOrReplace(
+                        new IndicatingOnConfirmAjaxLink<Void>("unassignLink", pageRef, "confirmUnassign") {
+
+                            private static final long serialVersionUID = -6957616042924610294L;
+
+                            @Override
+                            protected void onClickInternal(final AjaxRequestTarget target) {
+                                link.onClick(target);
+                            }
+                        }.feedbackPanelAutomaticReload(link.feedbackPanelAutomaticReload()));
+                break;
+
+            case ASSIGN:
+                fragment = new Fragment("panelAssign", "fragmentAssign", this);
+
+                fragment.addOrReplace(new ClearIndicatingAjaxLink<Void>("assignLink", pageRef) {
+
+                    private static final long serialVersionUID = -6957616042924610304L;
+
+                    @Override
+                    protected void onClickInternal(final AjaxRequestTarget target) {
+                        link.onClick(target);
+                    }
+                }.feedbackPanelAutomaticReload(link.feedbackPanelAutomaticReload()));
+                break;
+
+            case DEPROVISION:
+                fragment = new Fragment("panelDeprovision", "fragmentDeprovision", this);
+
+                fragment.addOrReplace(
+                        new IndicatingOnConfirmAjaxLink<Void>("deprovisionLink", pageRef, "confirmDeprovision") {
+
+                            private static final long serialVersionUID = -6957616042924610295L;
+
+                            @Override
+                            protected void onClickInternal(final AjaxRequestTarget target) {
+                                link.onClick(target);
+                            }
+                        }.feedbackPanelAutomaticReload(link.feedbackPanelAutomaticReload()));
+                break;
+
+            case PROVISION:
+                fragment = new Fragment("panelProvision", "fragmentProvision", this);
+
+                fragment.addOrReplace(new ClearIndicatingAjaxLink<Void>("provisionLink", pageRef) {
+
+                    private static final long serialVersionUID = -6957616042924610305L;
+
+                    @Override
+                    protected void onClickInternal(final AjaxRequestTarget target) {
+                        link.onClick(target);
+                    }
+                }.feedbackPanelAutomaticReload(link.feedbackPanelAutomaticReload()));
+                break;
+            case ZOOM_IN:
+                fragment = new Fragment("panelZoomIn", "fragmentZoomIn", this);
+
+                fragment.addOrReplace(new ClearIndicatingAjaxLink<Void>("zoomInLink", pageRef) {
+
+                    private static final long serialVersionUID = -6957616042924610305L;
+
+                    @Override
+                    protected void onClickInternal(final AjaxRequestTarget target) {
+                        link.onClick(target);
+                    }
+                }.feedbackPanelAutomaticReload(link.feedbackPanelAutomaticReload()));
+                break;
+            case ZOOM_OUT:
+                fragment = new Fragment("panelZoomOut", "fragmentZoomOut", this);
+
+                fragment.addOrReplace(new ClearIndicatingAjaxLink<Void>("zoomOutLink", pageRef) {
+
+                    private static final long serialVersionUID = -6957616042924610305L;
+
+                    @Override
+                    protected void onClickInternal(final AjaxRequestTarget target) {
+                        link.onClick(target);
+                    }
+                }.feedbackPanelAutomaticReload(link.feedbackPanelAutomaticReload()));
+                break;
+            default:
+            // do nothing
+        }
+
+        if (fragment != null) {
+            fragment.setEnabled(enabled);
+            MetaDataRoleAuthorizationStrategy.authorize(fragment, ENABLE, entitlements);
+            super.addOrReplace(fragment);
+        }
+
+        return this;
+    }
+
+    public void remove(final ActionLink.ActionType type) {
+        switch (type) {
+            case CLAIM:
+                super.addOrReplace(new Fragment("panelClaim", "emptyFragment", this));
+                break;
+
+            case MANAGE_RESOURCES:
+                super.addOrReplace(new Fragment("panelManageResources", "emptyFragment", this));
+                break;
+
+            case MANAGE_USERS:
+                super.addOrReplace(new Fragment("panelManageUsers", "emptyFragment", this));
+                break;
+
+            case MANAGE_GROUPS:
+                super.addOrReplace(new Fragment("panelManageGroups", "emptyFragment", this));
+                break;
+
+            case CREATE:
+                super.addOrReplace(new Fragment("panelCreate", "emptyFragment", this));
+                break;
+
+            case EDIT:
+                super.addOrReplace(new Fragment("panelEdit", "emptyFragment", this));
+                break;
+
+            case USER_TEMPLATE:
+                super.addOrReplace(new Fragment("panelUserTemplate", "emptyFragment", this));
+                break;
+
+            case SEARCH:
+                super.addOrReplace(new Fragment("panelSearch", "emptyFragment", this));
+                break;
+
+            case EXECUTE:
+                super.addOrReplace(new Fragment("panelExecute", "emptyFragment", this));
+                break;
+
+            case DRYRUN:
+                super.addOrReplace(new Fragment("panelDryRun", "emptyFragment", this));
+                break;
+
+            case DELETE:
+                super.addOrReplace(new Fragment("panelDelete", "emptyFragment", this));
+                break;
+
+            case SELECT:
+                super.addOrReplace(new Fragment("panelSelect", "emptyFragment", this));
+                break;
+
+            case EXPORT:
+                super.addOrReplace(new Fragment("panelExport", "emptyFragment", this));
+                break;
+
+            case SUSPEND:
+                super.addOrReplace(new Fragment("panelSuspend", "emptyFragment", this));
+                break;
+
+            case REACTIVATE:
+                super.addOrReplace(new Fragment("panelReactivate", "emptyFragment", this));
+                break;
+
+            case RELOAD:
+                super.addOrReplace(new Fragment("panelReload", "emptyFragment", this));
+                break;
+
+            case CHANGE_VIEW:
+                super.addOrReplace(new Fragment("panelChangeView", "emptyFragment", this));
+                break;
+
+            case UNLINK:
+                super.addOrReplace(new Fragment("panelUnlink", "emptyFragment", this));
+                break;
+
+            case LINK:
+                super.addOrReplace(new Fragment("panelLink", "emptyFragment", this));
+                break;
+
+            case UNASSIGN:
+                super.addOrReplace(new Fragment("panelUnassign", "emptyFragment", this));
+                break;
+
+            case ASSIGN:
+                super.addOrReplace(new Fragment("panelAssign", "emptyFragment", this));
+                break;
+
+            case DEPROVISION:
+                super.addOrReplace(new Fragment("panelDeprovision", "emptyFragment", this));
+                break;
+
+            case PROVISION:
+                super.addOrReplace(new Fragment("panelProvision", "emptyFragment", this));
+                break;
+            case ZOOM_IN:
+                super.addOrReplace(new Fragment("panelZoomIn", "emptyFragment", this));
+                break;
+            case ZOOM_OUT:
+                super.addOrReplace(new Fragment("panelZoomOut", "emptyFragment", this));
+                break;
+            default:
+            // do nothing
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/34ec6712/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/AjaxTextFieldPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/AjaxTextFieldPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/AjaxTextFieldPanel.java
index 6854fb0..df8e808 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/AjaxTextFieldPanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/AjaxTextFieldPanel.java
@@ -53,7 +53,7 @@ public class AjaxTextFieldPanel extends FieldPanel<String> implements Cloneable
             protected Iterator<String> getChoices(final String input) {
                 final Pattern pattern = Pattern.compile(".*" + Pattern.quote(input) + ".*", Pattern.CASE_INSENSITIVE);
 
-                final List<String> result = new ArrayList<String>();
+                final List<String> result = new ArrayList<>();
 
                 for (String choice : choices) {
                     if (pattern.matcher(choice).matches()) {
@@ -64,7 +64,7 @@ public class AjaxTextFieldPanel extends FieldPanel<String> implements Cloneable
                 return result.iterator();
             }
         };
-        add(field.setLabel(new Model<String>(name)).setOutputMarkupId(true));
+        add(field.setLabel(new Model<>(name)).setOutputMarkupId(true));
 
         if (!isReadOnly()) {
             field.add(new AjaxFormComponentUpdatingBehavior(Constants.ON_CHANGE) {

http://git-wip-us.apache.org/repos/asf/syncope/blob/34ec6712/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/IndicatingOnConfirmAjaxLink.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/IndicatingOnConfirmAjaxLink.java b/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/IndicatingOnConfirmAjaxLink.java
new file mode 100644
index 0000000..86db915
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/IndicatingOnConfirmAjaxLink.java
@@ -0,0 +1,58 @@
+/*
+ * 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.wicket.ajax.markup.html;
+
+import org.apache.wicket.Component;
+import org.apache.wicket.PageReference;
+import org.apache.wicket.ajax.attributes.AjaxCallListener;
+import org.apache.wicket.ajax.attributes.AjaxRequestAttributes;
+
+public abstract class IndicatingOnConfirmAjaxLink<T> extends ClearIndicatingAjaxLink<T> {
+
+    private static final long serialVersionUID = 2228670850922265663L;
+
+    private final String msg;
+
+    public IndicatingOnConfirmAjaxLink(final String id, final PageReference pageRef) {
+        this(id, pageRef, "confirmDelete");
+    }
+
+    public IndicatingOnConfirmAjaxLink(final String id, final PageReference pageRef, final String msg) {
+        super(id, pageRef);
+        this.msg = msg;
+    }
+
+    @Override
+    protected void updateAjaxAttributes(final AjaxRequestAttributes attributes) {
+        super.updateAjaxAttributes(attributes);
+
+        final AjaxCallListener ajaxCallListener = new AjaxCallListener() {
+
+            private static final long serialVersionUID = 7160235486520935153L;
+
+            @Override
+            public CharSequence getPrecondition(final Component component) {
+                return "if (!confirm('"
+                        + getString(IndicatingOnConfirmAjaxLink.this.msg)
+                        + "')) {return false;} else {return true;}";
+            }
+        };
+        attributes.getAjaxCallListeners().add(ajaxCallListener);
+    }
+}