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 2018/04/17 15:09:42 UTC

[4/8] syncope git commit: [SYNCOPE-1299] Console features implemented

[SYNCOPE-1299] Console features implemented


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

Branch: refs/heads/2_0_X
Commit: a660a26b5c1fd4198009f08535ec437e80cf86e3
Parents: 5965dfa
Author: Francesco Chicchiriccò <il...@apache.org>
Authored: Tue Apr 17 16:01:13 2018 +0200
Committer: Francesco Chicchiriccò <il...@apache.org>
Committed: Tue Apr 17 16:01:13 2018 +0200

----------------------------------------------------------------------
 .../approvals/ApprovalDirectoryPanel.java       |  18 +-
 .../client/console/bulk/BulkContent.java        |  19 +-
 .../client/console/commons/AnyDataProvider.java |   4 +-
 .../commons/ResourceStatusDataProvider.java     | 143 -----------
 .../status/AbstractStatusBeanProvider.java      |  15 +-
 .../commons/status/ConnObjectWrapper.java       |  10 +-
 .../console/commons/status/StatusBean.java      |  13 +-
 .../console/commons/status/StatusUtils.java     | 118 ++++------
 .../console/panels/AjaxDataTablePanel.java      |  10 +-
 .../console/panels/AnyDirectoryPanel.java       |  17 +-
 .../console/panels/ConnObjectDetails.java       |   9 +-
 .../client/console/panels/ConnObjects.java      |   2 +-
 .../client/console/panels/MultilevelPanel.java  |   6 +-
 .../console/panels/PropagationErrorPanel.java   |  30 +++
 .../syncope/client/console/panels/Realm.java    |  39 ++-
 .../console/panels/RealmWizardBuilder.java      |   8 +-
 .../console/panels/RemoteObjectPanel.java       |   5 +-
 .../console/rest/AbstractAnyRestClient.java     |   2 +-
 .../console/rest/AnyObjectRestClient.java       |   2 +-
 .../client/console/rest/GroupRestClient.java    |   2 +-
 .../console/rest/ReconciliationRestClient.java  |  52 ++++
 .../client/console/rest/UserRestClient.java     |  47 ++--
 .../console/status/AnyStatusDirectoryPanel.java | 236 +++++++++++++------
 .../client/console/status/ReconStatusPanel.java |  68 ++++++
 .../client/console/status/ReconTaskPanel.java   | 155 ++++++++++++
 .../status/ResourceStatusDirectoryPanel.java    | 210 ++++++++++++++---
 .../client/console/status/StatusModal.java      |   4 +-
 .../console/tasks/SchedTaskWizardBuilder.java   |   2 +-
 .../console/topology/TopologyTogglePanel.java   |   7 +-
 .../wicket/markup/html/form/ActionLink.java     |   2 +
 .../console/widgets/ReconDetailsModalPanel.java | 178 ++++++++++++++
 .../ReconciliationDetailsModalPanel.java        | 177 --------------
 .../console/widgets/ReconciliationWidget.java   |   2 +-
 .../wizards/any/AnyObjectWizardBuilder.java     |  12 +-
 .../console/wizards/any/ConnObjectPanel.java    |  61 ++---
 .../console/wizards/any/GroupWizardBuilder.java |  12 +-
 .../client/console/wizards/any/StatusPanel.java | 110 +++++----
 .../console/wizards/any/UserWizardBuilder.java  |  12 +-
 .../SyncopeConsoleApplication.properties        |   2 +
 .../SyncopeConsoleApplication_it.properties     |   2 +
 .../SyncopeConsoleApplication_ja.properties     |   2 +
 .../SyncopeConsoleApplication_pt_BR.properties  |   2 +
 .../SyncopeConsoleApplication_ru.properties     |   2 +
 .../client/console/approvals/ApprovalModal.html |   9 +-
 .../client/console/bulk/BulkActionModal.html    |   9 +-
 .../client/console/bulk/BulkContent.html        |  25 +-
 .../notifications/NotificationTasks.html        |   1 -
 .../NotificationWizardBuilder$Abouts.html       |  13 +-
 .../NotificationWizardBuilder$Details.html      |  37 ++-
 .../NotificationWizardBuilder$Events.html       |   9 +-
 .../NotificationWizardBuilder$Recipients.html   |  48 ++--
 .../client/console/panels/MultilevelPanel.html  |   1 -
 .../console/panels/PropagationErrorPanel.html   |  24 ++
 .../console/panels/RemoteObjectPanel.html       |   3 +-
 .../panels/search/SearchClausePanel.html        |  41 ++--
 .../reports/ReportWizardBuilder$Schedule.html   |   9 +-
 .../client/console/status/AnyStatusModal.html   |   3 +-
 .../client/console/status/ReconTaskPanel.html   |  37 +++
 .../console/topology/TopologyTogglePanel.html   |   4 +-
 .../topology/TopologyTogglePanel.properties     |   4 +-
 .../topology/TopologyTogglePanel_it.properties  |   4 +-
 .../topology/TopologyTogglePanel_ja.properties  |   4 +-
 .../TopologyTogglePanel_pt_BR.properties        |   4 +-
 .../topology/TopologyTogglePanel_ru.properties  |   4 +-
 .../markup/html/form/ActionPanel.properties     |  10 +-
 .../markup/html/form/ActionPanel_it.properties  |   8 +-
 .../markup/html/form/ActionPanel_ja.properties  |   8 +-
 .../html/form/ActionPanel_pt_BR.properties      |   8 +-
 .../markup/html/form/ActionPanel_ru.properties  |   8 +-
 .../markup/html/form/ActionsPanel.properties    |  10 +-
 .../markup/html/form/ActionsPanel_it.properties |   8 +-
 .../markup/html/form/ActionsPanel_ja.properties |   8 +-
 .../html/form/ActionsPanel_pt_BR.properties     |   8 +-
 .../markup/html/form/ActionsPanel_ru.properties |   8 +-
 .../form/preview/AbstractBinaryPreviewer.html   |  11 +-
 .../html/form/preview/BinaryImagePreviewer.html |   9 +-
 .../html/form/preview/BinaryPDFPreviewer.html   |  28 +--
 .../html/form/preview/DefaultPreviewer.html     |  15 +-
 .../console/widgets/ReconDetailsModalPanel.html |  23 ++
 .../ReconciliationDetailsModalPanel.html        |  23 --
 .../console/wizards/AbstractMappingPanel.html   | 147 ++++++------
 .../console/wizards/any/AnnotatedBeanPanel.html |  69 +++---
 .../console/wizards/any/ConnObjectPanel.html    |  10 +-
 .../client/console/wizards/any/Details.html     |  23 +-
 .../console/wizards/any/DynamicMemberships.html |  15 +-
 .../client/console/wizards/any/Ownership.html   |  59 +++--
 .../any/Relationships$Specification.html        |  39 ++-
 .../console/wizards/any/Relationships.html      |  35 ++-
 .../client/console/wizards/any/Resources.html   |  29 +--
 .../client/console/wizards/any/ResultPage.html  |  15 +-
 .../client/console/wizards/any/Roles.html       |  49 ++--
 .../client/console/wizards/any/StatusPanel.html |   1 -
 .../wizards/any/UserInformationPanel.html       |  77 +++---
 .../wizards/role/RoleWizardBuilder$Details.html |  15 +-
 .../role/RoleWizardBuilder$DynRealms.html       |  13 +-
 .../role/RoleWizardBuilder$Entitlements.html    |  13 +-
 .../wizards/role/RoleWizardBuilder$Realms.html  |  13 +-
 .../syncope/common/lib/to/ReconStatus.java      |  67 ++++++
 .../common/lib/to/ReconciliationStatus.java     |  56 -----
 .../syncope/common/lib/types/AnyTypeKind.java   |   8 +
 .../rest/api/service/ReconciliationService.java |   4 +-
 .../syncope/core/logic/ReconciliationLogic.java |  10 +-
 .../core/persistence/jpa/dao/JPARoleDAO.java    |   3 +-
 .../java/pushpull/SinglePullJobDelegate.java    |   1 +
 .../java/pushpull/SinglePushJobDelegate.java    |   1 +
 .../cxf/service/ReconciliationServiceImpl.java  |   4 +-
 .../syncope/fit/console/BulkActionITCase.java   |  20 +-
 .../syncope/fit/console/RealmsITCase.java       |  17 +-
 .../syncope/fit/console/TopologyITCase.java     |   2 +-
 .../syncope/fit/core/ReconciliationITCase.java  |   6 +-
 110 files changed, 1812 insertions(+), 1324 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/syncope/blob/a660a26b/client/console/src/main/java/org/apache/syncope/client/console/approvals/ApprovalDirectoryPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/approvals/ApprovalDirectoryPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/approvals/ApprovalDirectoryPanel.java
index a324ea3..72d2916 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/approvals/ApprovalDirectoryPanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/approvals/ApprovalDirectoryPanel.java
@@ -327,13 +327,13 @@ public class ApprovalDirectoryPanel
         protected Serializable onApplyInternal(final AnyWrapper<UserTO> modelObject) {
             UserTO inner = modelObject.getInnerObject();
 
-            ProvisioningResult<UserTO> actual;
+            ProvisioningResult<UserTO> result;
 
             if (formTO.getUserPatch() == null) {
-                actual = new ProvisioningResult<>();
+                result = new ProvisioningResult<>();
                 UserTO user = new UserWorkflowRestClient().executeTask("default", inner);
-                actual.setEntity(user);
-                claimForm(restClient.getFormForUser(actual.getEntity().getKey()).getTaskId());
+                result.setEntity(user);
+                claimForm(restClient.getFormForUser(result.getEntity().getKey()).getTaskId());
             } else {
                 UserPatch patch = AnyOperations.diff(inner, formTO.getUserTO(), false);
 
@@ -346,11 +346,11 @@ public class ApprovalDirectoryPanel
                 }
                 // update just if it is changed
                 if (patch.isEmpty()) {
-                    actual = new ProvisioningResult<>();
-                    actual.setEntity(inner);
+                    result = new ProvisioningResult<>();
+                    result.setEntity(inner);
                 } else {
-                    actual = userRestClient.update(getOriginalItem().getInnerObject().getETagValue(), patch);
-                    WorkflowFormTO workFlowTO = restClient.getFormForUser(actual.getEntity().getKey());
+                    result = userRestClient.update(getOriginalItem().getInnerObject().getETagValue(), patch);
+                    WorkflowFormTO workFlowTO = restClient.getFormForUser(result.getEntity().getKey());
                     if (workFlowTO != null) {
                         claimForm(workFlowTO.getTaskId());
                     }
@@ -358,7 +358,7 @@ public class ApprovalDirectoryPanel
 
             }
 
-            return actual;
+            return result;
         }
     }
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/a660a26b/client/console/src/main/java/org/apache/syncope/client/console/bulk/BulkContent.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/bulk/BulkContent.java b/client/console/src/main/java/org/apache/syncope/client/console/bulk/BulkContent.java
index c58bce0..a72de6a 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/bulk/BulkContent.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/bulk/BulkContent.java
@@ -202,37 +202,36 @@ public class BulkContent<T extends Serializable, S> extends MultilevelPanel.Seco
 
                             for (Map.Entry<String, List<StatusBean>> entry : beans.entrySet()) {
                                 final String etag = anyRestClient.read(entry.getKey()).getETagValue();
-                                switch (actionToBeAddresed.name()) {
-                                    case "DEPROVISION":
+                                switch (actionToBeAddresed) {
+                                    case DEPROVISION:
                                         res = anyRestClient.deprovision(etag, entry.getKey(), entry.getValue());
                                         break;
-                                    case "UNASSIGN":
+                                    case UNASSIGN:
                                         res = anyRestClient.unassign(etag, entry.getKey(), entry.getValue());
                                         break;
-                                    case "UNLINK":
+                                    case UNLINK:
                                         res = anyRestClient.unlink(etag, entry.getKey(), entry.getValue());
                                         break;
-                                    case "ASSIGN":
+                                    case ASSIGN:
                                         res = anyRestClient.assign(etag, entry.getKey(), entry.getValue());
                                         break;
-                                    case "LINK":
+                                    case LINK:
                                         res = anyRestClient.link(etag, entry.getKey(), entry.getValue());
                                         break;
-                                    case "PROVISION":
+                                    case PROVISION:
                                         res = anyRestClient.provision(etag, entry.getKey(), entry.getValue());
                                         break;
-                                    case "REACTIVATE":
+                                    case REACTIVATE:
                                         res = ((UserRestClient) anyRestClient).
                                                 reactivate(etag, entry.getKey(), entry.getValue());
                                         fieldName = "resource";
                                         break;
-                                    case "SUSPEND":
+                                    case SUSPEND:
                                         res = ((UserRestClient) anyRestClient).
                                                 suspend(etag, entry.getKey(), entry.getValue());
                                         fieldName = "resource";
                                         break;
                                     default:
-                                        break;
                                 }
                             }
                         }

http://git-wip-us.apache.org/repos/asf/syncope/blob/a660a26b/client/console/src/main/java/org/apache/syncope/client/console/commons/AnyDataProvider.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/commons/AnyDataProvider.java b/client/console/src/main/java/org/apache/syncope/client/console/commons/AnyDataProvider.java
index ff4161c..0eca373 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/commons/AnyDataProvider.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/commons/AnyDataProvider.java
@@ -121,9 +121,9 @@ public class AnyDataProvider<A extends AnyTO> extends DirectoryDataProvider<A> {
 
         try {
             if (filtered) {
-                result = fiql == null ? 0 : restClient.searchCount(realm, fiql, type);
+                result = fiql == null ? 0 : restClient.count(realm, fiql, type);
             } else {
-                result = restClient.searchCount(realm, null, type);
+                result = restClient.count(realm, null, type);
             }
         } catch (Exception e) {
             LOG.error("While requesting for size() with FIQL {}", fiql, e);

http://git-wip-us.apache.org/repos/asf/syncope/blob/a660a26b/client/console/src/main/java/org/apache/syncope/client/console/commons/ResourceStatusDataProvider.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/commons/ResourceStatusDataProvider.java b/client/console/src/main/java/org/apache/syncope/client/console/commons/ResourceStatusDataProvider.java
deleted file mode 100644
index e54e4e6..0000000
--- a/client/console/src/main/java/org/apache/syncope/client/console/commons/ResourceStatusDataProvider.java
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * 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.ArrayList;
-import java.util.Collections;
-import java.util.Iterator;
-import java.util.List;
-import org.apache.commons.collections4.CollectionUtils;
-import org.apache.commons.collections4.Transformer;
-import org.apache.commons.lang3.StringUtils;
-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.rest.AbstractAnyRestClient;
-import org.apache.syncope.client.console.rest.AnyObjectRestClient;
-import org.apache.syncope.client.console.rest.GroupRestClient;
-import org.apache.syncope.client.console.rest.UserRestClient;
-import org.apache.syncope.client.lib.SyncopeClient;
-import org.apache.syncope.common.lib.search.AbstractFiqlSearchConditionBuilder;
-import org.apache.syncope.common.lib.to.AnyTO;
-import org.apache.syncope.common.lib.to.GroupTO;
-import org.apache.wicket.extensions.markup.html.repeater.data.sort.SortOrder;
-import org.apache.wicket.model.CompoundPropertyModel;
-import org.apache.wicket.model.IModel;
-
-public class ResourceStatusDataProvider extends DirectoryDataProvider<StatusBean> {
-
-    private static final long serialVersionUID = 6267494272884913376L;
-
-    private final StatusUtils statusUtils;
-
-    private final String resource;
-
-    private final SortableDataProviderComparator<StatusBean> comparator;
-
-    private final AbstractAnyRestClient<? extends AnyTO> restClient;
-
-    protected String fiql;
-
-    private final String realm;
-
-    private final String type;
-
-    public ResourceStatusDataProvider(
-            final String type,
-            final String resource,
-            final int paginatorRows,
-            final String realm) {
-
-        super(paginatorRows);
-        statusUtils = new StatusUtils();
-        this.resource = resource;
-
-        AbstractFiqlSearchConditionBuilder bld;
-
-        if (StringUtils.isEmpty(type)) {
-            this.fiql = null;
-            restClient = null;
-        } else {
-            switch (type) {
-                case "USER":
-                    bld = SyncopeClient.getUserSearchConditionBuilder();
-                    restClient = new UserRestClient();
-                    break;
-                case "GROUP":
-                    bld = SyncopeClient.getGroupSearchConditionBuilder();
-                    restClient = new GroupRestClient();
-                    break;
-                default:
-                    bld = SyncopeClient.getAnyObjectSearchConditionBuilder(type);
-                    restClient = new AnyObjectRestClient();
-            }
-
-            this.fiql = bld.hasResources(resource).query();
-        }
-
-        setSort("connObjectLink", SortOrder.ASCENDING);
-
-        this.comparator = new SortableDataProviderComparator<>(this);
-
-        this.realm = realm;
-        this.type = type;
-    }
-
-    @Override
-    public Iterator<StatusBean> iterator(final long first, final long count) {
-        if (fiql == null) {
-            return Collections.<StatusBean>emptyList().iterator();
-        }
-
-        final int page = ((int) first / paginatorRows);
-        List<? extends AnyTO> result =
-                restClient.search(realm, fiql, (page < 0 ? 0 : page) + 1, paginatorRows, getSort(), type);
-
-        List<StatusBean> res = CollectionUtils.collect(result, new Transformer<AnyTO, StatusBean>() {
-
-            @Override
-            public StatusBean transform(final AnyTO input) {
-                final List<ConnObjectWrapper> connObjects =
-                        statusUtils.getConnectorObjects(input, Collections.singletonList(resource));
-
-                return statusUtils.getStatusBean(
-                        input,
-                        resource,
-                        connObjects.isEmpty() ? null : connObjects.iterator().next().getConnObjectTO(),
-                        input instanceof GroupTO);
-            }
-        }, new ArrayList<StatusBean>());
-
-        Collections.sort(res, comparator);
-        return res.iterator();
-    }
-
-    @Override
-    public long size() {
-        if (fiql == null) {
-            return 0;
-        }
-        return restClient.searchCount(realm, fiql, type);
-    }
-
-    @Override
-    public IModel<StatusBean> model(final StatusBean object) {
-        return new CompoundPropertyModel<>(object);
-    }
-}

http://git-wip-us.apache.org/repos/asf/syncope/blob/a660a26b/client/console/src/main/java/org/apache/syncope/client/console/commons/status/AbstractStatusBeanProvider.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/commons/status/AbstractStatusBeanProvider.java b/client/console/src/main/java/org/apache/syncope/client/console/commons/status/AbstractStatusBeanProvider.java
index 7d9a688..50619e5 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/commons/status/AbstractStatusBeanProvider.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/commons/status/AbstractStatusBeanProvider.java
@@ -18,7 +18,6 @@
  */
 package org.apache.syncope.client.console.commons.status;
 
-import java.util.Collections;
 import java.util.Iterator;
 import java.util.List;
 import org.apache.syncope.client.console.commons.DirectoryDataProvider;
@@ -31,7 +30,7 @@ public abstract class AbstractStatusBeanProvider extends DirectoryDataProvider<S
 
     private static final long serialVersionUID = 4287357360778016173L;
 
-    private final SortableDataProviderComparator<StatusBean> comparator;
+    protected final SortableDataProviderComparator<StatusBean> comparator;
 
     public AbstractStatusBeanProvider(final String sort) {
         super(10);
@@ -42,29 +41,27 @@ public abstract class AbstractStatusBeanProvider extends DirectoryDataProvider<S
 
     @Override
     public Iterator<StatusBean> iterator(final long first, final long count) {
-        List<StatusBean> list = getStatusBeans();
-        Collections.sort(list, comparator);
-        return list.subList((int) first, (int) first + (int) count).iterator();
+        return getStatusBeans(first, count).iterator();
     }
 
     @Override
     public long size() {
-        return getStatusBeans().size();
+        return getStatusBeans(-1, -1).size();
     }
 
     @Override
-    public IModel<StatusBean> model(final StatusBean resource) {
+    public IModel<StatusBean> model(final StatusBean statusBean) {
         return new AbstractReadOnlyModel<StatusBean>() {
 
             private static final long serialVersionUID = -7802635613997243712L;
 
             @Override
             public StatusBean getObject() {
-                return resource;
+                return statusBean;
             }
         };
     }
 
-    public abstract List<StatusBean> getStatusBeans();
+    protected abstract List<StatusBean> getStatusBeans(long first, long count);
 
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/a660a26b/client/console/src/main/java/org/apache/syncope/client/console/commons/status/ConnObjectWrapper.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/commons/status/ConnObjectWrapper.java b/client/console/src/main/java/org/apache/syncope/client/console/commons/status/ConnObjectWrapper.java
index 06ccac7..14dca77 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/commons/status/ConnObjectWrapper.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/commons/status/ConnObjectWrapper.java
@@ -28,13 +28,13 @@ public class ConnObjectWrapper implements Serializable {
 
     private final AnyTO any;
 
-    private final String resourceName;
+    private final String resource;
 
     private final ConnObjectTO connObjectTO;
 
-    public ConnObjectWrapper(final AnyTO any, final String resourceName, final ConnObjectTO connObjectTO) {
+    public ConnObjectWrapper(final AnyTO any, final String resource, final ConnObjectTO connObjectTO) {
         this.any = any;
-        this.resourceName = resourceName;
+        this.resource = resource;
         this.connObjectTO = connObjectTO;
     }
 
@@ -42,8 +42,8 @@ public class ConnObjectWrapper implements Serializable {
         return any;
     }
 
-    public String getResourceName() {
-        return resourceName;
+    public String getResource() {
+        return resource;
     }
 
     public ConnObjectTO getConnObjectTO() {

http://git-wip-us.apache.org/repos/asf/syncope/blob/a660a26b/client/console/src/main/java/org/apache/syncope/client/console/commons/status/StatusBean.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/commons/status/StatusBean.java b/client/console/src/main/java/org/apache/syncope/client/console/commons/status/StatusBean.java
index fe7ce9f..fc834b5 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/commons/status/StatusBean.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/commons/status/StatusBean.java
@@ -23,6 +23,7 @@ import org.apache.commons.lang3.builder.EqualsBuilder;
 import org.apache.commons.lang3.builder.HashCodeBuilder;
 import org.apache.commons.lang3.builder.ReflectionToStringBuilder;
 import org.apache.commons.lang3.builder.ToStringStyle;
+import org.apache.syncope.common.lib.to.AnyObjectTO;
 import org.apache.syncope.common.lib.to.AnyTO;
 import org.apache.syncope.common.lib.to.GroupTO;
 import org.apache.syncope.common.lib.to.RealmTO;
@@ -44,18 +45,20 @@ public class StatusBean implements Serializable {
 
     private boolean linked = true;
 
-    public StatusBean(final AnyTO any, final String resourceName) {
+    public StatusBean(final AnyTO any, final String resource) {
         this.key = any.getKey();
         this.name = any instanceof UserTO
                 ? ((UserTO) any).getUsername()
-                : any instanceof GroupTO ? ((GroupTO) any).getName() : String.valueOf(any.getKey());
-        this.resource = resourceName;
+                : any instanceof GroupTO
+                        ? ((GroupTO) any).getName()
+                        : ((AnyObjectTO) any).getName();
+        this.resource = resource;
     }
 
-    public StatusBean(final RealmTO realm, final String resourceName) {
+    public StatusBean(final RealmTO realm, final String resource) {
         this.key = realm.getKey();
         this.name = realm.getFullPath();
-        this.resource = resourceName;
+        this.resource = resource;
     }
 
     public String getConnObjectLink() {

http://git-wip-us.apache.org/repos/asf/syncope/blob/a660a26b/client/console/src/main/java/org/apache/syncope/client/console/commons/status/StatusUtils.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/commons/status/StatusUtils.java b/client/console/src/main/java/org/apache/syncope/client/console/commons/status/StatusUtils.java
index 9828b0c..9f4bd6c 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/commons/status/StatusUtils.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/commons/status/StatusUtils.java
@@ -22,17 +22,21 @@ import java.io.Serializable;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.collections4.PredicateUtils;
+import org.apache.commons.collections4.Transformer;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.syncope.client.console.commons.ConnIdSpecialName;
 import org.apache.syncope.client.console.commons.Constants;
 import org.apache.syncope.client.console.panels.LabelPanel;
-import org.apache.syncope.client.console.rest.ResourceRestClient;
+import org.apache.syncope.client.console.rest.ReconciliationRestClient;
 import org.apache.syncope.common.lib.patch.PasswordPatch;
 import org.apache.syncope.common.lib.patch.StatusPatch;
 import org.apache.syncope.common.lib.to.AnyTO;
 import org.apache.syncope.common.lib.to.AttrTO;
 import org.apache.syncope.common.lib.to.ConnObjectTO;
-import org.apache.syncope.common.lib.to.RealmTO;
+import org.apache.syncope.common.lib.to.ReconStatus;
+import org.apache.syncope.common.lib.types.AnyTypeKind;
 import org.apache.syncope.common.lib.types.PropagationTaskExecStatus;
 import org.apache.wicket.markup.ComponentTag;
 import org.apache.wicket.markup.html.basic.Label;
@@ -40,118 +44,72 @@ import org.apache.wicket.markup.html.panel.Panel;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-public class StatusUtils implements Serializable {
+public final class StatusUtils implements Serializable {
 
     private static final long serialVersionUID = 7238009174387184309L;
 
     private static final Logger LOG = LoggerFactory.getLogger(StatusUtils.class);
 
-    private final ResourceRestClient restClient = new ResourceRestClient();
+    private static final ReconciliationRestClient RECONCILIATION_REST_CLIENT = new ReconciliationRestClient();
 
-    public List<ConnObjectWrapper> getConnectorObjects(final AnyTO any) {
-        final List<ConnObjectWrapper> objects = new ArrayList<>();
-        objects.addAll(getConnectorObjects(any, any.getResources()));
-        return objects;
-    }
-
-    public List<ConnObjectWrapper> getConnectorObjects(
-            final Collection<AnyTO> anys, final Collection<String> resources) {
-
-        final List<ConnObjectWrapper> objects = new ArrayList<>();
-
-        for (AnyTO any : anys) {
-            objects.addAll(getConnectorObjects(any, resources));
-        }
-
-        return objects;
-    }
+    public static List<ReconStatus> getReconStatuses(
+            final AnyTypeKind anyTypeKind, final String anyKey, final Collection<String> resources) {
 
-    public List<ConnObjectWrapper> getConnectorObjects(
-            final AnyTO any, final Collection<String> resources) {
+        List<ReconStatus> result = CollectionUtils.collect(resources, new Transformer<String, ReconStatus>() {
 
-        final List<ConnObjectWrapper> objects = new ArrayList<>();
-
-        for (String resourceName : resources) {
-            ConnObjectTO objectTO = null;
-            try {
-                objectTO = restClient.readConnObject(resourceName, any.getType(), any.getKey());
-            } catch (Exception e) {
-                LOG.warn("ConnObject '{}' not found on resource '{}'", any.getKey(), resourceName);
+            @Override
+            public ReconStatus transform(final String resource) {
+                try {
+                    return RECONCILIATION_REST_CLIENT.status(anyTypeKind, anyKey, resource);
+                } catch (Exception e) {
+                    LOG.warn("Unexpected error for {} {} on {}", anyTypeKind, anyKey, resource, e);
+                    return null;
+                }
             }
+        }, new ArrayList<ReconStatus>());
+        CollectionUtils.filter(result, PredicateUtils.notNullPredicate());
 
-            objects.add(new ConnObjectWrapper(any, resourceName, objectTO));
-        }
-
-        return objects;
+        return result;
     }
 
-    public StatusBean getStatusBean(
+    public static StatusBean getStatusBean(
             final AnyTO anyTO,
-            final String resourceName,
-            final ConnObjectTO objectTO,
+            final String resource,
+            final ConnObjectTO connObjectTO,
             final boolean notUser) {
 
-        final StatusBean statusBean = new StatusBean(anyTO, resourceName);
+        StatusBean statusBean = new StatusBean(anyTO, resource);
 
-        if (objectTO != null) {
-            final Boolean enabled = isEnabled(objectTO);
-
-            final Status status = enabled == null
+        if (connObjectTO != null) {
+            Boolean enabled = isEnabled(connObjectTO);
+            statusBean.setStatus(enabled == null
                     ? (notUser ? Status.ACTIVE : Status.UNDEFINED)
                     : enabled
                             ? Status.ACTIVE
-                            : Status.SUSPENDED;
-
-            String connObjectLink = getConnObjectLink(objectTO);
+                            : Status.SUSPENDED);
 
-            statusBean.setStatus(status);
-            statusBean.setConnObjectLink(connObjectLink);
+            statusBean.setConnObjectLink(getConnObjectLink(connObjectTO));
         }
 
         return statusBean;
     }
 
-    public StatusBean getStatusBean(
-            final RealmTO anyTO,
-            final String resourceName,
-            final ConnObjectTO objectTO) {
-
-        final StatusBean statusBean = new StatusBean(anyTO, resourceName);
-
-        if (objectTO != null) {
-            final Boolean enabled = isEnabled(objectTO);
-
-            final Status status = enabled == null
-                    ? Status.ACTIVE
-                    : enabled
-                            ? Status.ACTIVE
-                            : Status.SUSPENDED;
-
-            String connObjectLink = getConnObjectLink(objectTO);
-
-            statusBean.setStatus(status);
-            statusBean.setConnObjectLink(connObjectLink);
-        }
-
-        return statusBean;
-    }
-
-    private Boolean isEnabled(final ConnObjectTO objectTO) {
-        final AttrTO status = objectTO.getAttr(ConnIdSpecialName.ENABLE);
+    private static Boolean isEnabled(final ConnObjectTO objectTO) {
+        AttrTO status = objectTO.getAttr(ConnIdSpecialName.ENABLE);
         return status != null && status.getValues() != null && !status.getValues().isEmpty()
                 ? Boolean.valueOf(status.getValues().get(0))
                 : Boolean.FALSE;
     }
 
-    private String getConnObjectLink(final ConnObjectTO objectTO) {
-        final AttrTO name = objectTO == null ? null : objectTO.getAttr(ConnIdSpecialName.NAME);
+    private static String getConnObjectLink(final ConnObjectTO objectTO) {
+        AttrTO name = objectTO == null ? null : objectTO.getAttr(ConnIdSpecialName.NAME);
         return name != null && name.getValues() != null && !name.getValues().isEmpty()
                 ? name.getValues().get(0)
                 : null;
     }
 
     public static PasswordPatch buildPasswordPatch(final String password, final Collection<StatusBean> statuses) {
-        final PasswordPatch.Builder builder = new PasswordPatch.Builder();
+        PasswordPatch.Builder builder = new PasswordPatch.Builder();
         builder.value(password);
 
         for (StatusBean status : statuses) {
@@ -294,4 +252,8 @@ public class StatusUtils implements Serializable {
             }
         };
     }
+
+    private StatusUtils() {
+        // private constructor for static utility class
+    }
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/a660a26b/client/console/src/main/java/org/apache/syncope/client/console/panels/AjaxDataTablePanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/panels/AjaxDataTablePanel.java b/client/console/src/main/java/org/apache/syncope/client/console/panels/AjaxDataTablePanel.java
index 9204aa1..eabf5aa 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/panels/AjaxDataTablePanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/AjaxDataTablePanel.java
@@ -256,15 +256,17 @@ public final class AjaxDataTablePanel<T extends Serializable, S> extends DataTab
                 }
 
                 if (builder.multiLevelPanel == null) {
-                    bulkModal.header(new ResourceModel("bulk.action", "Bulk action"));
+                    bulkModal.header(new ResourceModel("bulk.action"));
                     bulkModal.changeCloseButtonLabel(getString("cancel", null, "Cancel"), target);
 
                     target.add(bulkModal.setContent(new BulkActionModal<>(
                             bulkModal,
                             builder.pageRef,
                             new ArrayList<>(group.getModelObject()),
+                            builder.columns.size() == 1
+                            ? builder.columns
                             // serialization problem with sublist only
-                            new ArrayList<>(builder.columns.subList(1, builder.columns.size())),
+                            : new ArrayList<>(builder.columns.subList(1, builder.columns.size())),
                             builder.bulkActions,
                             builder.bulkActionExecutor,
                             builder.itemKeyField)));
@@ -276,8 +278,10 @@ public final class AjaxDataTablePanel<T extends Serializable, S> extends DataTab
                             new BulkContent<>(
                                     builder.baseModal,
                                     new ArrayList<>(group.getModelObject()),
+                                    builder.columns.size() == 1
+                                    ? builder.columns
                                     // serialization problem with sublist only
-                                    new ArrayList<>(builder.columns.subList(1, builder.columns.size() - 1)),
+                                    : new ArrayList<>(builder.columns.subList(1, builder.columns.size())),
                                     builder.bulkActions,
                                     builder.bulkActionExecutor,
                                     builder.itemKeyField),

http://git-wip-us.apache.org/repos/asf/syncope/blob/a660a26b/client/console/src/main/java/org/apache/syncope/client/console/panels/AnyDirectoryPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/panels/AnyDirectoryPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/panels/AnyDirectoryPanel.java
index 3b05c8b..c2b10fd 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/panels/AnyDirectoryPanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/AnyDirectoryPanel.java
@@ -27,7 +27,7 @@ import java.util.Collection;
 import java.util.Date;
 import java.util.List;
 import org.apache.commons.collections4.CollectionUtils;
-import org.apache.commons.lang3.tuple.Pair;
+import org.apache.commons.lang3.tuple.Triple;
 import org.apache.syncope.client.console.SyncopeConsoleSession;
 import org.apache.syncope.client.console.commons.AnyDataProvider;
 import org.apache.syncope.client.console.commons.Constants;
@@ -293,21 +293,22 @@ public abstract class AnyDirectoryPanel<A extends AnyTO, E extends AbstractAnyRe
                 new ListModel<>(new ArrayList<StatusBean>()),
                 CollectionUtils.collect(
                         ((ProvisioningResult<A>) result).getPropagationStatuses(),
-                        new SerializableTransformer<PropagationStatus, Pair<ConnObjectTO, ConnObjectWrapper>>() {
+                        new SerializableTransformer<
+                                PropagationStatus, Triple<ConnObjectTO, ConnObjectWrapper, String>>() {
 
                     private static final long serialVersionUID = -4931455531906427515L;
 
                     @Override
-                    public Pair<ConnObjectTO, ConnObjectWrapper> transform(final PropagationStatus input) {
-                        ConnObjectTO before = input.getBeforeObj();
+                    public Triple<ConnObjectTO, ConnObjectWrapper, String> transform(final PropagationStatus status) {
+                        ConnObjectTO before = status.getBeforeObj();
                         ConnObjectWrapper afterObjWrapper = new ConnObjectWrapper(
                                 ((ProvisioningResult<A>) result).getEntity(),
-                                input.getResource(),
-                                input.getAfterObj());
-                        return Pair.of(before, afterObjWrapper);
+                                status.getResource(),
+                                status.getAfterObj());
+                        return Triple.of(before, afterObjWrapper, status.getFailureReason());
                     }
 
-                }, new ArrayList<Pair<ConnObjectTO, ConnObjectWrapper>>()),
+                }, new ArrayList<Triple<ConnObjectTO, ConnObjectWrapper, String>>()),
                 pageRef);
     }
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/a660a26b/client/console/src/main/java/org/apache/syncope/client/console/panels/ConnObjectDetails.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/panels/ConnObjectDetails.java b/client/console/src/main/java/org/apache/syncope/client/console/panels/ConnObjectDetails.java
index 98a289e..4f348be 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/panels/ConnObjectDetails.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/ConnObjectDetails.java
@@ -21,6 +21,8 @@ package org.apache.syncope.client.console.panels;
 import org.apache.commons.lang3.tuple.Pair;
 import org.apache.syncope.client.console.wizards.any.ConnObjectPanel;
 import org.apache.syncope.common.lib.to.ConnObjectTO;
+import org.apache.wicket.model.IModel;
+import org.apache.wicket.model.Model;
 
 public class ConnObjectDetails extends MultilevelPanel.SecondLevel {
 
@@ -30,8 +32,11 @@ public class ConnObjectDetails extends MultilevelPanel.SecondLevel {
         super();
 
         MultilevelPanel mlp = new MultilevelPanel("details");
-        mlp.setFirstLevel(
-                new ConnObjectPanel(MultilevelPanel.FIRST_LEVEL_ID, Pair.of((ConnObjectTO) null, connObjectTO), true));
+        mlp.setFirstLevel(new ConnObjectPanel(
+                MultilevelPanel.FIRST_LEVEL_ID,
+                Pair.<IModel<?>, IModel<?>>of(Model.of(), Model.of()),
+                Pair.of((ConnObjectTO) null, connObjectTO),
+                true));
         add(mlp);
     }
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/a660a26b/client/console/src/main/java/org/apache/syncope/client/console/panels/ConnObjects.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/panels/ConnObjects.java b/client/console/src/main/java/org/apache/syncope/client/console/panels/ConnObjects.java
index d29ce1a..191460d 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/panels/ConnObjects.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/ConnObjects.java
@@ -81,7 +81,7 @@ public class ConnObjects extends Panel implements ModalPanel {
             private static final long serialVersionUID = 1473786800290434002L;
 
             @Override
-            protected void prev(final AjaxRequestTarget target) {
+            public void prev(final AjaxRequestTarget target) {
                 anyTypes.setEnabled(true);
                 target.add(anyTypes);
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/a660a26b/client/console/src/main/java/org/apache/syncope/client/console/panels/MultilevelPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/panels/MultilevelPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/panels/MultilevelPanel.java
index 4f0029c..6050d30 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/panels/MultilevelPanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/MultilevelPanel.java
@@ -34,12 +34,12 @@ public class MultilevelPanel extends Panel implements IHeaderContributor {
 
     protected static final Logger LOG = LoggerFactory.getLogger(MultilevelPanel.class);
 
-    private boolean isFirstLevel = true;
-
     public static final String FIRST_LEVEL_ID = "first";
 
     public static final String SECOND_LEVEL_ID = "second";
 
+    private boolean isFirstLevel = true;
+
     private final WebMarkupContainer firstLevelContainer;
 
     private final WebMarkupContainer secondLevelContainer;
@@ -85,7 +85,7 @@ public class MultilevelPanel extends Panel implements IHeaderContributor {
         }
     }
 
-    protected void prev(final AjaxRequestTarget target) {
+    public void prev(final AjaxRequestTarget target) {
         if (isFirstLevel) {
             LOG.warn("No further level available");
         } else {

http://git-wip-us.apache.org/repos/asf/syncope/blob/a660a26b/client/console/src/main/java/org/apache/syncope/client/console/panels/PropagationErrorPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/panels/PropagationErrorPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/panels/PropagationErrorPanel.java
new file mode 100644
index 0000000..c6d4da9
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/PropagationErrorPanel.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.panels;
+
+import org.apache.wicket.markup.html.basic.Label;
+
+public class PropagationErrorPanel extends MultilevelPanel.SecondLevel {
+
+    private static final long serialVersionUID = -6203280629851678781L;
+
+    public PropagationErrorPanel(final String failureReason) {
+        add(new Label("failureReason", failureReason).setOutputMarkupId(true));
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/a660a26b/client/console/src/main/java/org/apache/syncope/client/console/panels/Realm.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/panels/Realm.java b/client/console/src/main/java/org/apache/syncope/client/console/panels/Realm.java
index 7e6e998..6d845ad 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/panels/Realm.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/Realm.java
@@ -58,7 +58,9 @@ import org.apache.wicket.extensions.markup.html.tabs.ITab;
 import org.apache.wicket.markup.html.WebMarkupContainer;
 import org.apache.wicket.markup.html.basic.Label;
 import org.apache.wicket.markup.html.panel.Panel;
+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;
 
@@ -166,8 +168,8 @@ public abstract class Realm extends WizardMgtPanel<RealmTO> {
             }
         });
 
-        final Triple<UserFormLayoutInfo, GroupFormLayoutInfo, Map<String, AnyObjectFormLayoutInfo>> formLayoutInfo
-                = FormLayoutInfoUtils.fetch(CollectionUtils.collect(anyTypes, EntityTOUtils.keyTransformer()));
+        final Triple<UserFormLayoutInfo, GroupFormLayoutInfo, Map<String, AnyObjectFormLayoutInfo>> formLayoutInfo =
+                FormLayoutInfoUtils.fetch(CollectionUtils.collect(anyTypes, EntityTOUtils.keyTransformer()));
 
         for (final AnyTypeTO anyType : anyTypes) {
             tabs.add(new ITabComponent(
@@ -205,7 +207,7 @@ public abstract class Realm extends WizardMgtPanel<RealmTO> {
         syncope.setStatus(PropagationTaskExecStatus.SUCCESS);
         syncope.setResource(Constants.SYNCOPE);
 
-        ArrayList<PropagationStatus> propagations = new ArrayList<>();
+        List<PropagationStatus> propagations = new ArrayList<>();
         propagations.add(syncope);
         propagations.addAll(((ProvisioningResult) result).getPropagationStatuses());
 
@@ -253,11 +255,26 @@ public abstract class Realm extends WizardMgtPanel<RealmTO> {
             }
 
             @Override
-            public void onClick(final AjaxRequestTarget target, final PropagationStatus bean) {
-                mlp.next(bean.getResource(), new RemoteRealmPanel(bean), target);
+            public void onClick(final AjaxRequestTarget target, final PropagationStatus status) {
+                mlp.next(status.getResource(), new RemoteRealmPanel(status), target);
             }
         }, ActionLink.ActionType.VIEW, StandardEntitlement.RESOURCE_GET_CONNOBJECT);
 
+        builder.addAction(new ActionLink<PropagationStatus>() {
+
+            private static final long serialVersionUID = -3722207913631435501L;
+
+            @Override
+            protected boolean statusCondition(final PropagationStatus status) {
+                return StringUtils.isNotBlank(status.getFailureReason());
+            }
+
+            @Override
+            public void onClick(final AjaxRequestTarget target, final PropagationStatus status) {
+                mlp.next(status.getResource(), new PropagationErrorPanel(status.getFailureReason()), target);
+            }
+        }, ActionLink.ActionType.PROPAGATION_TASKS, StringUtils.EMPTY);
+
         mlp.setFirstLevel(builder.build(MultilevelPanel.FIRST_LEVEL_ID));
         return mlp;
     }
@@ -270,19 +287,23 @@ public abstract class Realm extends WizardMgtPanel<RealmTO> {
 
     protected abstract void onClickDelete(final AjaxRequestTarget target, final RealmTO realmTO);
 
-    public class RemoteRealmPanel extends RemoteObjectPanel {
+    class RemoteRealmPanel extends RemoteObjectPanel {
 
         private static final long serialVersionUID = 4303365227411467563L;
 
         private final PropagationStatus bean;
 
-        public RemoteRealmPanel(final PropagationStatus bean) {
+        RemoteRealmPanel(final PropagationStatus bean) {
             this.bean = bean;
-            add(new ConnObjectPanel(REMOTE_OBJECT_PANEL_ID, getConnObjectTO(), false));
+            add(new ConnObjectPanel(
+                    REMOTE_OBJECT_PANEL_ID,
+                    Pair.<IModel<?>, IModel<?>>of(new ResourceModel("before"), new ResourceModel("after")),
+                    getConnObjectTOs(),
+                    false));
         }
 
         @Override
-        protected final Pair<ConnObjectTO, ConnObjectTO> getConnObjectTO() {
+        protected final Pair<ConnObjectTO, ConnObjectTO> getConnObjectTOs() {
             return Pair.of(bean.getBeforeObj(), bean.getAfterObj());
         }
     }

http://git-wip-us.apache.org/repos/asf/syncope/blob/a660a26b/client/console/src/main/java/org/apache/syncope/client/console/panels/RealmWizardBuilder.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/panels/RealmWizardBuilder.java b/client/console/src/main/java/org/apache/syncope/client/console/panels/RealmWizardBuilder.java
index f491f2b..9edcded 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/panels/RealmWizardBuilder.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/RealmWizardBuilder.java
@@ -47,13 +47,13 @@ public class RealmWizardBuilder extends AjaxWizardBuilder<RealmTO> {
 
     @Override
     protected Serializable onApplyInternal(final RealmTO modelObject) {
-        final ProvisioningResult<RealmTO> res;
+        ProvisioningResult<RealmTO> result;
         if (modelObject.getKey() == null) {
-            res = realmRestClient.create(this.parentPath, modelObject);
+            result = realmRestClient.create(this.parentPath, modelObject);
         } else {
-            res = realmRestClient.update(modelObject);
+            result = realmRestClient.update(modelObject);
         }
-        return res;
+        return result;
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/syncope/blob/a660a26b/client/console/src/main/java/org/apache/syncope/client/console/panels/RemoteObjectPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/panels/RemoteObjectPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/panels/RemoteObjectPanel.java
index 5a6ab4e..6c4231d 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/panels/RemoteObjectPanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/RemoteObjectPanel.java
@@ -19,14 +19,13 @@
 package org.apache.syncope.client.console.panels;
 
 import org.apache.commons.lang3.tuple.Pair;
-import org.apache.syncope.client.console.panels.MultilevelPanel.SecondLevel;
 import org.apache.syncope.common.lib.to.ConnObjectTO;
 
-public abstract class RemoteObjectPanel extends SecondLevel {
+public abstract class RemoteObjectPanel extends MultilevelPanel.SecondLevel {
 
     private static final long serialVersionUID = 4303365227411467563L;
 
     protected static final String REMOTE_OBJECT_PANEL_ID = "remoteObject";
 
-    protected abstract Pair<ConnObjectTO, ConnObjectTO> getConnObjectTO();
+    protected abstract Pair<ConnObjectTO, ConnObjectTO> getConnObjectTOs();
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/a660a26b/client/console/src/main/java/org/apache/syncope/client/console/rest/AbstractAnyRestClient.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/rest/AbstractAnyRestClient.java b/client/console/src/main/java/org/apache/syncope/client/console/rest/AbstractAnyRestClient.java
index 4cfdddb..639a4eb 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/rest/AbstractAnyRestClient.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/rest/AbstractAnyRestClient.java
@@ -40,7 +40,7 @@ public abstract class AbstractAnyRestClient<TO extends AnyTO> extends BaseRestCl
 
     protected abstract Class<? extends AnyService<TO>> getAnyServiceClass();
 
-    public abstract int searchCount(String realm, String fiql, String type);
+    public abstract int count(String realm, String fiql, String type);
 
     public abstract List<TO> search(String realm, String fiql, int page, int size, SortParam<String> sort, String type);
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/a660a26b/client/console/src/main/java/org/apache/syncope/client/console/rest/AnyObjectRestClient.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/rest/AnyObjectRestClient.java b/client/console/src/main/java/org/apache/syncope/client/console/rest/AnyObjectRestClient.java
index a885764..86a9e29 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/rest/AnyObjectRestClient.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/rest/AnyObjectRestClient.java
@@ -59,7 +59,7 @@ public class AnyObjectRestClient extends AbstractAnyRestClient<AnyObjectTO> {
     }
 
     @Override
-    public int searchCount(final String realm, final String fiql, final String type) {
+    public int count(final String realm, final String fiql, final String type) {
         return getService(AnyObjectService.class).
                 search(new AnyQuery.Builder().realm(realm).fiql(fiql).page(1).size(1).build()).
                 getTotalCount();

http://git-wip-us.apache.org/repos/asf/syncope/blob/a660a26b/client/console/src/main/java/org/apache/syncope/client/console/rest/GroupRestClient.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/rest/GroupRestClient.java b/client/console/src/main/java/org/apache/syncope/client/console/rest/GroupRestClient.java
index c7ff004..9ecd9ca 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/rest/GroupRestClient.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/rest/GroupRestClient.java
@@ -62,7 +62,7 @@ public class GroupRestClient extends AbstractAnyRestClient<GroupTO> {
     }
 
     @Override
-    public int searchCount(final String realm, final String fiql, final String type) {
+    public int count(final String realm, final String fiql, final String type) {
         return getService(GroupService.class).
                 search(new AnyQuery.Builder().realm(realm).fiql(fiql).page(1).size(1).build()).
                 getTotalCount();

http://git-wip-us.apache.org/repos/asf/syncope/blob/a660a26b/client/console/src/main/java/org/apache/syncope/client/console/rest/ReconciliationRestClient.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/rest/ReconciliationRestClient.java b/client/console/src/main/java/org/apache/syncope/client/console/rest/ReconciliationRestClient.java
new file mode 100644
index 0000000..16960de
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/rest/ReconciliationRestClient.java
@@ -0,0 +1,52 @@
+/*
+ * 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.rest;
+
+import org.apache.syncope.common.lib.to.PullTaskTO;
+import org.apache.syncope.common.lib.to.PushTaskTO;
+import org.apache.syncope.common.lib.to.ReconStatus;
+import org.apache.syncope.common.lib.types.AnyTypeKind;
+import org.apache.syncope.common.rest.api.service.ReconciliationService;
+
+public class ReconciliationRestClient extends BaseRestClient {
+
+    private static final long serialVersionUID = -3161863874876938094L;
+
+    public ReconStatus status(final AnyTypeKind anyTypeKind, final String anyKey, final String resourceKey) {
+        return getService(ReconciliationService.class).status(anyTypeKind, anyKey, resourceKey);
+    }
+
+    public void push(
+            final AnyTypeKind anyTypeKind,
+            final String anyKey,
+            final String resourceKey,
+            final PushTaskTO pushTask) {
+
+        getService(ReconciliationService.class).push(anyTypeKind, anyKey, resourceKey, pushTask);
+    }
+
+    public void pull(
+            final AnyTypeKind anyTypeKind,
+            final String anyKey,
+            final String resourceKey,
+            final PullTaskTO pullTask) {
+
+        getService(ReconciliationService.class).pull(anyTypeKind, anyKey, resourceKey, pullTask);
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/a660a26b/client/console/src/main/java/org/apache/syncope/client/console/rest/UserRestClient.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/rest/UserRestClient.java b/client/console/src/main/java/org/apache/syncope/client/console/rest/UserRestClient.java
index b64ff9b..514d970 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/rest/UserRestClient.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/rest/UserRestClient.java
@@ -22,7 +22,6 @@ import java.util.List;
 import java.util.Map;
 import javax.ws.rs.core.GenericType;
 import javax.ws.rs.core.Response;
-import org.apache.commons.lang3.StringUtils;
 import org.apache.syncope.client.console.commons.Constants;
 import org.apache.syncope.client.console.commons.status.StatusBean;
 import org.apache.syncope.client.console.commons.status.StatusUtils;
@@ -69,7 +68,7 @@ public class UserRestClient extends AbstractAnyRestClient<UserTO> {
     }
 
     @Override
-    public int searchCount(final String realm, final String fiql, final String type) {
+    public int count(final String realm, final String fiql, final String type) {
         return getService(UserService.class).
                 search(new AnyQuery.Builder().realm(realm).fiql(fiql).page(1).size(1).build()).
                 getTotalCount();
@@ -97,29 +96,29 @@ public class UserRestClient extends AbstractAnyRestClient<UserTO> {
         statusPatch.setKey(userKey);
         statusPatch.setType(StatusPatchType.SUSPEND);
 
-        BulkActionResult result;
+        BulkActionResult bulkActionResult;
         synchronized (this) {
-            result = new BulkActionResult();
-            Map<String, BulkActionResult.Status> res = result.getResults();
+            bulkActionResult = new BulkActionResult();
+            Map<String, BulkActionResult.Status> results = bulkActionResult.getResults();
             UserService service = getService(etag, UserService.class);
 
-            @SuppressWarnings("unchecked")
-            ProvisioningResult<UserTO> provisions = (ProvisioningResult<UserTO>) service.status(statusPatch).
-                    readEntity(ProvisioningResult.class);
+            ProvisioningResult<UserTO> provisioningResult = service.status(statusPatch).readEntity(
+                    new GenericType<ProvisioningResult<UserTO>>() {
+            });
 
             if (statusPatch.isOnSyncope()) {
-                res.put(StringUtils.capitalize(Constants.SYNCOPE),
-                        "suspended".equalsIgnoreCase(provisions.getEntity().getStatus())
+                results.put(Constants.SYNCOPE,
+                        "suspended".equalsIgnoreCase(provisioningResult.getEntity().getStatus())
                         ? BulkActionResult.Status.SUCCESS
                         : BulkActionResult.Status.FAILURE);
             }
 
-            for (PropagationStatus status : provisions.getPropagationStatuses()) {
-                res.put(status.getResource(), BulkActionResult.Status.valueOf(status.getStatus().name()));
+            for (PropagationStatus status : provisioningResult.getPropagationStatuses()) {
+                results.put(status.getResource(), BulkActionResult.Status.valueOf(status.getStatus().name()));
             }
             resetClient(UserService.class);
         }
-        return result;
+        return bulkActionResult;
     }
 
     public BulkActionResult reactivate(final String etag, final String userKey, final List<StatusBean> statuses) {
@@ -127,28 +126,28 @@ public class UserRestClient extends AbstractAnyRestClient<UserTO> {
         statusPatch.setKey(userKey);
         statusPatch.setType(StatusPatchType.REACTIVATE);
 
-        BulkActionResult result;
+        BulkActionResult bulkActionResult;
         synchronized (this) {
-            result = new BulkActionResult();
-            Map<String, BulkActionResult.Status> res = result.getResults();
+            bulkActionResult = new BulkActionResult();
+            Map<String, BulkActionResult.Status> results = bulkActionResult.getResults();
             UserService service = getService(etag, UserService.class);
 
-            @SuppressWarnings("unchecked")
-            ProvisioningResult<UserTO> provisions = (ProvisioningResult<UserTO>) service.status(statusPatch).
-                    readEntity(ProvisioningResult.class);
+            ProvisioningResult<UserTO> provisioningResult = service.status(statusPatch).readEntity(
+                    new GenericType<ProvisioningResult<UserTO>>() {
+            });
 
             if (statusPatch.isOnSyncope()) {
-                res.put(StringUtils.capitalize(Constants.SYNCOPE),
-                        "active".equalsIgnoreCase(provisions.getEntity().getStatus())
+                results.put(Constants.SYNCOPE,
+                        "active".equalsIgnoreCase(provisioningResult.getEntity().getStatus())
                         ? BulkActionResult.Status.SUCCESS
                         : BulkActionResult.Status.FAILURE);
             }
 
-            for (PropagationStatus status : provisions.getPropagationStatuses()) {
-                res.put(status.getResource(), BulkActionResult.Status.valueOf(status.getStatus().name()));
+            for (PropagationStatus status : provisioningResult.getPropagationStatuses()) {
+                results.put(status.getResource(), BulkActionResult.Status.valueOf(status.getStatus().name()));
             }
             resetClient(UserService.class);
         }
-        return result;
+        return bulkActionResult;
     }
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/a660a26b/client/console/src/main/java/org/apache/syncope/client/console/status/AnyStatusDirectoryPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/status/AnyStatusDirectoryPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/status/AnyStatusDirectoryPanel.java
index 6a4c3ad..f50bbed 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/status/AnyStatusDirectoryPanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/status/AnyStatusDirectoryPanel.java
@@ -19,19 +19,22 @@
 package org.apache.syncope.client.console.status;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.List;
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.collections4.PredicateUtils;
+import org.apache.commons.collections4.Transformer;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.syncope.client.console.commons.Constants;
 import org.apache.syncope.client.console.commons.DirectoryDataProvider;
 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.Status;
 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.DirectoryPanel;
 import org.apache.syncope.client.console.panels.AjaxDataTablePanel;
-import org.apache.syncope.client.console.panels.ConnObjectDetails;
 import org.apache.syncope.client.console.panels.ModalPanel;
 import org.apache.syncope.client.console.panels.MultilevelPanel;
 import org.apache.syncope.client.console.rest.AbstractAnyRestClient;
@@ -42,10 +45,15 @@ import org.apache.syncope.client.console.rest.UserRestClient;
 import org.apache.syncope.client.console.wicket.markup.html.bootstrap.dialog.BaseModal;
 import org.apache.syncope.client.console.wicket.markup.html.form.ActionLink;
 import org.apache.syncope.client.console.wicket.markup.html.form.ActionsPanel;
+import org.apache.syncope.common.lib.to.AnyObjectTO;
 import org.apache.syncope.common.lib.to.AnyTO;
 import org.apache.syncope.common.lib.to.ResourceTO;
 import org.apache.syncope.common.lib.to.GroupTO;
+import org.apache.syncope.common.lib.to.PullTaskTO;
+import org.apache.syncope.common.lib.to.PushTaskTO;
+import org.apache.syncope.common.lib.to.ReconStatus;
 import org.apache.syncope.common.lib.to.UserTO;
+import org.apache.syncope.common.lib.types.AnyTypeKind;
 import org.apache.syncope.common.lib.types.StandardEntitlement;
 import org.apache.wicket.PageReference;
 import org.apache.wicket.ajax.AjaxRequestTarget;
@@ -71,9 +79,11 @@ public class AnyStatusDirectoryPanel
 
     private final AnyTO anyTO;
 
+    private final AnyTypeKind anyTypeKind;
+
     private final boolean statusOnly;
 
-    private final ResourceRestClient resourceRestClient = new ResourceRestClient();
+    private final List<String> resources;
 
     public AnyStatusDirectoryPanel(
             final BaseModal<?> baseModal,
@@ -92,12 +102,25 @@ public class AnyStatusDirectoryPanel
 
         if (anyTO instanceof UserTO) {
             this.restClient = new UserRestClient();
+            anyTypeKind = AnyTypeKind.USER;
         } else if (anyTO instanceof GroupTO) {
             this.restClient = new GroupRestClient();
+            anyTypeKind = AnyTypeKind.GROUP;
         } else {
             this.restClient = new AnyObjectRestClient();
+            anyTypeKind = AnyTypeKind.ANY_OBJECT;
         }
 
+        resources = CollectionUtils.collect(new ResourceRestClient().list(),
+                new Transformer<ResourceTO, String>() {
+
+            @Override
+            public String transform(final ResourceTO resource) {
+                return resource.getProvision(anyTO.getType()) == null ? null : resource.getKey();
+            }
+        }, new ArrayList<String>());
+        CollectionUtils.filter(resources, PredicateUtils.notNullPredicate());
+
         initResultTable();
     }
 
@@ -127,7 +150,9 @@ public class AnyStatusDirectoryPanel
 
                     @Override
                     protected void onComponentTag(final ComponentTag tag) {
-                        if (model.getObject().isLinked()) {
+                        if (anyTO.getResources().contains(model.getObject().getResource())
+                                || Constants.SYNCOPE.equalsIgnoreCase(model.getObject().getResource())) {
+
                             super.onComponentTag(tag);
                         } else {
                             tag.put("style", "font-style: italic");
@@ -137,26 +162,29 @@ public class AnyStatusDirectoryPanel
             }
         });
 
-        columns.add(new PropertyColumn<StatusBean, String>(
-                new StringResourceModel("connObjectLink", this), "connObjectLink", "connObjectLink"));
+        if (statusOnly) {
+            columns.add(new PropertyColumn<StatusBean, String>(
+                    new StringResourceModel("connObjectLink", this), "connObjectLink", "connObjectLink"));
 
-        columns.add(new AbstractColumn<StatusBean, String>(new StringResourceModel("status", this)) {
+            columns.add(new AbstractColumn<StatusBean, String>(new StringResourceModel("status", this)) {
 
-            private static final long serialVersionUID = -3503023501954863131L;
+                private static final long serialVersionUID = -3503023501954863131L;
 
-            @Override
-            public void populateItem(
-                    final Item<ICellPopulator<StatusBean>> cellItem,
-                    final String componentId,
-                    final IModel<StatusBean> model) {
+                @Override
+                public void populateItem(
+                        final Item<ICellPopulator<StatusBean>> cellItem,
+                        final String componentId,
+                        final IModel<StatusBean> model) {
 
-                if (model.getObject().isLinked()) {
-                    cellItem.add(StatusUtils.getStatusImage(componentId, model.getObject().getStatus()));
-                } else {
-                    cellItem.add(new Label(componentId, ""));
+                    if (model.getObject().isLinked()) {
+                        cellItem.add(StatusUtils.getStatusImage(componentId, model.getObject().getStatus()));
+                    } else {
+                        cellItem.add(new Label(componentId, ""));
+                    }
                 }
-            }
-        });
+            });
+        }
+
         return columns;
     }
 
@@ -164,32 +192,70 @@ public class AnyStatusDirectoryPanel
     public ActionsPanel<StatusBean> getActions(final IModel<StatusBean> model) {
         final ActionsPanel<StatusBean> panel = super.getActions(model);
 
-        panel.add(new ActionLink<StatusBean>() {
+        if (!Constants.SYNCOPE.equalsIgnoreCase(model.getObject().getResource())) {
+            panel.add(new ActionLink<StatusBean>() {
 
-            private static final long serialVersionUID = -7978723352517770645L;
+                private static final long serialVersionUID = -7978723352517770645L;
 
-            @Override
-            protected boolean statusCondition(final StatusBean bean) {
-                return bean != null && bean.getConnObjectLink() != null
-                        && !bean.getResource().equalsIgnoreCase(Constants.SYNCOPE);
-            }
+                @Override
+                public void onClick(final AjaxRequestTarget target, final StatusBean bean) {
+                    multiLevelPanelRef.next(bean.getResource(),
+                            new ReconStatusPanel(bean.getResource(), anyTypeKind, anyTO.getKey()),
+                            target);
+                    target.add(multiLevelPanelRef);
+                    AnyStatusDirectoryPanel.this.getTogglePanel().close(target);
+                }
+            }, ActionLink.ActionType.VIEW, StandardEntitlement.RESOURCE_GET_CONNOBJECT);
+        }
 
-            @Override
-            public void onClick(final AjaxRequestTarget target, final StatusBean bean) {
-                multiLevelPanelRef.next(bean.getResource(),
-                        new ConnObjectDetails(resourceRestClient.readConnObject(
-                                bean.getResource(), anyTO.getType(), anyTO.getKey())), target);
-                target.add(multiLevelPanelRef);
-                AnyStatusDirectoryPanel.this.getTogglePanel().close(target);
-            }
-        }, ActionLink.ActionType.VIEW, StandardEntitlement.RESOURCE_GET_CONNOBJECT);
+        if (!statusOnly) {
+            panel.add(new ActionLink<StatusBean>() {
+
+                private static final long serialVersionUID = -7978723352517770645L;
+
+                @Override
+                public void onClick(final AjaxRequestTarget target, final StatusBean bean) {
+                    multiLevelPanelRef.next("PUSH " + bean.getResource(),
+                            new ReconTaskPanel(
+                                    bean.getResource(),
+                                    new PushTaskTO(),
+                                    anyTypeKind,
+                                    anyTO.getKey(),
+                                    multiLevelPanelRef,
+                                    pageRef),
+                            target);
+                    target.add(multiLevelPanelRef);
+                    AnyStatusDirectoryPanel.this.getTogglePanel().close(target);
+                }
+            }, ActionLink.ActionType.RECONCILIATION_PUSH, StandardEntitlement.TASK_EXECUTE);
+
+            panel.add(new ActionLink<StatusBean>() {
+
+                private static final long serialVersionUID = -7978723352517770645L;
+
+                @Override
+                public void onClick(final AjaxRequestTarget target, final StatusBean bean) {
+                    multiLevelPanelRef.next("PULL " + bean.getResource(),
+                            new ReconTaskPanel(
+                                    bean.getResource(),
+                                    new PullTaskTO(),
+                                    anyTypeKind,
+                                    anyTO.getKey(),
+                                    multiLevelPanelRef,
+                                    pageRef),
+                            target);
+                    target.add(multiLevelPanelRef);
+                    AnyStatusDirectoryPanel.this.getTogglePanel().close(target);
+                }
+            }, ActionLink.ActionType.RECONCILIATION_PULL, StandardEntitlement.TASK_EXECUTE);
+        }
 
         return panel;
     }
 
     @Override
     protected Collection<ActionLink.ActionType> getBulkActions() {
-        final List<ActionLink.ActionType> bulkActions = new ArrayList<>();
+        List<ActionLink.ActionType> bulkActions = new ArrayList<>();
         if (statusOnly) {
             bulkActions.add(ActionLink.ActionType.SUSPEND);
             bulkActions.add(ActionLink.ActionType.REACTIVATE);
@@ -200,14 +266,13 @@ public class AnyStatusDirectoryPanel
             bulkActions.add(ActionLink.ActionType.PROVISION);
             bulkActions.add(ActionLink.ActionType.ASSIGN);
             bulkActions.add(ActionLink.ActionType.UNASSIGN);
-
         }
         return bulkActions;
     }
 
     @Override
-    protected AttributableStatusProvider dataProvider() {
-        return new AttributableStatusProvider();
+    protected AnyStatusProvider dataProvider() {
+        return new AnyStatusProvider();
     }
 
     @Override
@@ -215,71 +280,88 @@ public class AnyStatusDirectoryPanel
         return StringUtils.EMPTY;
     }
 
-    public class AttributableStatusProvider extends AbstractStatusBeanProvider {
+    protected class AnyStatusProvider extends AbstractStatusBeanProvider {
 
         private static final long serialVersionUID = 4586969457669796621L;
 
-        private final StatusUtils statusUtils;
-
-        AttributableStatusProvider() {
-            super(statusOnly ? "resource" : "connObjectLink");
-            statusUtils = new StatusUtils();
+        AnyStatusProvider() {
+            super("resource");
         }
 
-        @SuppressWarnings("unchecked")
         @Override
-        public List<StatusBean> getStatusBeans() {
+        protected List<StatusBean> getStatusBeans(final long first, final long count) {
             // this is required to retrieve updated data by reloading table
             final AnyTO actual = restClient.read(anyTO.getKey());
 
-            final List<String> resources = new ArrayList<>();
-            for (ResourceTO resourceTO : new ResourceRestClient().list()) {
-                resources.add(resourceTO.getKey());
-            }
+            List<StatusBean> statusBeans = CollectionUtils.collect(actual.getResources(),
+                    new Transformer<String, StatusBean>() {
 
-            final List<ConnObjectWrapper> connObjects = statusUtils.getConnectorObjects(actual);
+                @Override
+                public StatusBean transform(final String resource) {
+                    List<ReconStatus> statuses = Collections.emptyList();
+                    if (statusOnly) {
+                        statuses = StatusUtils.getReconStatuses(anyTypeKind, anyTO.getKey(), Arrays.asList(resource));
+                    }
 
-            final List<StatusBean> statusBeans = new ArrayList<>(connObjects.size() + 1);
+                    return StatusUtils.getStatusBean(
+                            actual,
+                            resource,
+                            statuses.isEmpty() ? null : statuses.get(0).getOnResource(),
+                            actual instanceof GroupTO);
+                }
+            }, new ArrayList<StatusBean>());
 
-            for (ConnObjectWrapper entry : connObjects) {
-                final StatusBean statusBean = statusUtils.getStatusBean(actual,
-                        entry.getResourceName(),
-                        entry.getConnObjectTO(),
-                        actual instanceof GroupTO);
+            if (statusOnly) {
+                StatusBean syncope = new StatusBean(actual, Constants.SYNCOPE);
+                switch (anyTypeKind) {
+                    case USER:
+                        syncope.setConnObjectLink(((UserTO) actual).getUsername());
+                        break;
 
-                statusBeans.add(statusBean);
-                resources.remove(entry.getResourceName());
-            }
+                    case GROUP:
+                        syncope.setConnObjectLink(((GroupTO) actual).getName());
+                        break;
 
-            if (statusOnly) {
-                final StatusBean syncope = new StatusBean(actual, "Syncope");
+                    case ANY_OBJECT:
+                        syncope.setConnObjectLink(((AnyObjectTO) actual).getName());
+                        break;
 
-                syncope.setConnObjectLink(((UserTO) actual).getUsername());
+                    default:
+                }
 
                 Status syncopeStatus = Status.UNDEFINED;
-                if (((UserTO) actual).getStatus() != null) {
+                if (actual.getStatus() != null) {
                     try {
-                        syncopeStatus = Status.valueOf(((UserTO) actual).getStatus().toUpperCase());
+                        syncopeStatus = Status.valueOf(actual.getStatus().toUpperCase());
                     } catch (IllegalArgumentException e) {
-                        LOG.warn("Unexpected status found: {}", ((UserTO) actual).getStatus(), e);
+                        LOG.warn("Unexpected status found: {}", actual.getStatus(), e);
                     }
                 }
                 syncope.setStatus(syncopeStatus);
 
-                statusBeans.add(syncope);
+                Collections.sort(statusBeans, comparator);
+                statusBeans.add(0, syncope);
             } else {
-                for (String resource : resources) {
-                    final StatusBean statusBean = statusUtils.getStatusBean(actual,
-                            resource,
-                            null,
-                            actual instanceof GroupTO);
+                statusBeans.addAll(CollectionUtils.collect(CollectionUtils.subtract(resources, anyTO.getResources()),
+                        new Transformer<String, StatusBean>() {
 
-                    statusBean.setLinked(false);
-                    statusBeans.add(statusBean);
-                }
+                    @Override
+                    public StatusBean transform(final String resource) {
+                        StatusBean statusBean = StatusUtils.getStatusBean(
+                                actual,
+                                resource,
+                                null,
+                                actual instanceof GroupTO);
+                        statusBean.setLinked(false);
+                        return statusBean;
+                    }
+                }, new ArrayList<StatusBean>()));
+                Collections.sort(statusBeans, comparator);
             }
 
-            return statusBeans;
+            return first == -1 && count == -1
+                    ? statusBeans
+                    : statusBeans.subList((int) first, (int) first + (int) count);
         }
     }
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/a660a26b/client/console/src/main/java/org/apache/syncope/client/console/status/ReconStatusPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/status/ReconStatusPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/status/ReconStatusPanel.java
new file mode 100644
index 0000000..91dc9ac
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/status/ReconStatusPanel.java
@@ -0,0 +1,68 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.client.console.status;
+
+import java.util.Arrays;
+import java.util.List;
+import org.apache.commons.lang3.tuple.Pair;
+import org.apache.syncope.client.console.commons.Constants;
+import org.apache.syncope.client.console.commons.status.StatusUtils;
+import org.apache.syncope.client.console.panels.RemoteObjectPanel;
+import org.apache.syncope.client.console.wizards.any.ConnObjectPanel;
+import org.apache.syncope.common.lib.to.ConnObjectTO;
+import org.apache.syncope.common.lib.to.ReconStatus;
+import org.apache.syncope.common.lib.types.AnyTypeKind;
+import org.apache.wicket.model.IModel;
+import org.apache.wicket.model.Model;
+import org.apache.wicket.model.ResourceModel;
+
+public class ReconStatusPanel extends RemoteObjectPanel {
+
+    private static final long serialVersionUID = 8000309881812037770L;
+
+    private final String resource;
+
+    private final AnyTypeKind anyTypeKind;
+
+    private final String anyKey;
+
+    public ReconStatusPanel(
+            final String resource,
+            final AnyTypeKind anyTypeKind,
+            final String anyKey) {
+
+        this.resource = resource;
+        this.anyTypeKind = anyTypeKind;
+        this.anyKey = anyKey;
+
+        add(new ConnObjectPanel(
+                REMOTE_OBJECT_PANEL_ID,
+                Pair.<IModel<?>, IModel<?>>of(Model.of(Constants.SYNCOPE), new ResourceModel("resource")),
+                getConnObjectTOs(),
+                false));
+    }
+
+    @Override
+    protected Pair<ConnObjectTO, ConnObjectTO> getConnObjectTOs() {
+        List<ReconStatus> statuses =
+                StatusUtils.getReconStatuses(anyTypeKind, anyKey, Arrays.asList(resource));
+
+        return statuses.isEmpty() ? null : Pair.of(statuses.get(0).getOnSyncope(), statuses.get(0).getOnResource());
+    }
+}