[SYNCOPE-1299] Console features implemented
authorFrancesco Chicchiriccò <ilgrosso@apache.org>
Tue, 17 Apr 2018 14:01:13 +0000 (16:01 +0200)
committerFrancesco Chicchiriccò <ilgrosso@apache.org>
Tue, 17 Apr 2018 15:09:23 +0000 (17:09 +0200)
102 files changed:
client/console/src/main/java/org/apache/syncope/client/console/approvals/ApprovalDirectoryPanel.java
client/console/src/main/java/org/apache/syncope/client/console/bulk/BulkContent.java
client/console/src/main/java/org/apache/syncope/client/console/commons/AnyDataProvider.java
client/console/src/main/java/org/apache/syncope/client/console/commons/ResourceStatusDataProvider.java [deleted file]
client/console/src/main/java/org/apache/syncope/client/console/commons/status/AbstractStatusBeanProvider.java
client/console/src/main/java/org/apache/syncope/client/console/commons/status/ConnObjectWrapper.java
client/console/src/main/java/org/apache/syncope/client/console/commons/status/StatusBean.java
client/console/src/main/java/org/apache/syncope/client/console/commons/status/StatusUtils.java
client/console/src/main/java/org/apache/syncope/client/console/panels/AjaxDataTablePanel.java
client/console/src/main/java/org/apache/syncope/client/console/panels/AnyDirectoryPanel.java
client/console/src/main/java/org/apache/syncope/client/console/panels/ConnObjectDetails.java
client/console/src/main/java/org/apache/syncope/client/console/panels/ConnObjects.java
client/console/src/main/java/org/apache/syncope/client/console/panels/MultilevelPanel.java
client/console/src/main/java/org/apache/syncope/client/console/panels/PropagationErrorPanel.java [new file with mode: 0644]
client/console/src/main/java/org/apache/syncope/client/console/panels/Realm.java
client/console/src/main/java/org/apache/syncope/client/console/panels/RealmWizardBuilder.java
client/console/src/main/java/org/apache/syncope/client/console/panels/RemoteObjectPanel.java
client/console/src/main/java/org/apache/syncope/client/console/panels/search/SearchClausePanel.java
client/console/src/main/java/org/apache/syncope/client/console/rest/AbstractAnyRestClient.java
client/console/src/main/java/org/apache/syncope/client/console/rest/AnyObjectRestClient.java
client/console/src/main/java/org/apache/syncope/client/console/rest/GroupRestClient.java
client/console/src/main/java/org/apache/syncope/client/console/rest/ReconciliationRestClient.java [new file with mode: 0644]
client/console/src/main/java/org/apache/syncope/client/console/rest/UserRestClient.java
client/console/src/main/java/org/apache/syncope/client/console/status/AnyStatusDirectoryPanel.java
client/console/src/main/java/org/apache/syncope/client/console/status/ReconStatusPanel.java [new file with mode: 0644]
client/console/src/main/java/org/apache/syncope/client/console/status/ReconTaskPanel.java [new file with mode: 0644]
client/console/src/main/java/org/apache/syncope/client/console/status/ResourceStatusDirectoryPanel.java
client/console/src/main/java/org/apache/syncope/client/console/status/StatusModal.java
client/console/src/main/java/org/apache/syncope/client/console/topology/TopologyTogglePanel.java
client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/ActionLink.java
client/console/src/main/java/org/apache/syncope/client/console/widgets/ReconDetailsModalPanel.java [moved from client/console/src/main/java/org/apache/syncope/client/console/widgets/ReconciliationDetailsModalPanel.java with 97% similarity]
client/console/src/main/java/org/apache/syncope/client/console/widgets/ReconciliationWidget.java
client/console/src/main/java/org/apache/syncope/client/console/wizards/any/AnyObjectWizardBuilder.java
client/console/src/main/java/org/apache/syncope/client/console/wizards/any/ConnObjectPanel.java
client/console/src/main/java/org/apache/syncope/client/console/wizards/any/GroupWizardBuilder.java
client/console/src/main/java/org/apache/syncope/client/console/wizards/any/StatusPanel.java
client/console/src/main/java/org/apache/syncope/client/console/wizards/any/UserWizardBuilder.java
client/console/src/main/resources/org/apache/syncope/client/console/SyncopeConsoleApplication.properties
client/console/src/main/resources/org/apache/syncope/client/console/SyncopeConsoleApplication_it.properties
client/console/src/main/resources/org/apache/syncope/client/console/SyncopeConsoleApplication_ja.properties
client/console/src/main/resources/org/apache/syncope/client/console/SyncopeConsoleApplication_pt_BR.properties
client/console/src/main/resources/org/apache/syncope/client/console/SyncopeConsoleApplication_ru.properties
client/console/src/main/resources/org/apache/syncope/client/console/bulk/BulkActionModal.html
client/console/src/main/resources/org/apache/syncope/client/console/bulk/BulkContent.html
client/console/src/main/resources/org/apache/syncope/client/console/notifications/NotificationTasks.html
client/console/src/main/resources/org/apache/syncope/client/console/notifications/NotificationWizardBuilder$Abouts.html
client/console/src/main/resources/org/apache/syncope/client/console/notifications/NotificationWizardBuilder$Details.html
client/console/src/main/resources/org/apache/syncope/client/console/notifications/NotificationWizardBuilder$Events.html
client/console/src/main/resources/org/apache/syncope/client/console/notifications/NotificationWizardBuilder$Recipients.html
client/console/src/main/resources/org/apache/syncope/client/console/panels/MultilevelPanel.html
client/console/src/main/resources/org/apache/syncope/client/console/panels/PropagationErrorPanel.html [new file with mode: 0644]
client/console/src/main/resources/org/apache/syncope/client/console/panels/RemoteObjectPanel.html
client/console/src/main/resources/org/apache/syncope/client/console/panels/search/SearchClausePanel.html
client/console/src/main/resources/org/apache/syncope/client/console/reports/ReportWizardBuilder$Schedule.html
client/console/src/main/resources/org/apache/syncope/client/console/status/AnyStatusModal.html
client/console/src/main/resources/org/apache/syncope/client/console/status/ReconTaskPanel.html [new file with mode: 0644]
client/console/src/main/resources/org/apache/syncope/client/console/topology/TopologyTogglePanel.html
client/console/src/main/resources/org/apache/syncope/client/console/topology/TopologyTogglePanel.properties
client/console/src/main/resources/org/apache/syncope/client/console/topology/TopologyTogglePanel_it.properties
client/console/src/main/resources/org/apache/syncope/client/console/topology/TopologyTogglePanel_ja.properties
client/console/src/main/resources/org/apache/syncope/client/console/topology/TopologyTogglePanel_pt_BR.properties
client/console/src/main/resources/org/apache/syncope/client/console/topology/TopologyTogglePanel_ru.properties
client/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/ActionPanel.properties
client/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/ActionPanel_it.properties
client/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/ActionPanel_ja.properties
client/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/ActionPanel_pt_BR.properties
client/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/ActionPanel_ru.properties
client/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/ActionsPanel.properties
client/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/ActionsPanel_it.properties
client/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/ActionsPanel_ja.properties
client/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/ActionsPanel_pt_BR.properties
client/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/ActionsPanel_ru.properties
client/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/preview/AbstractBinaryPreviewer.html
client/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/preview/BinaryImagePreviewer.html
client/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/preview/BinaryPDFPreviewer.html
client/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/preview/DefaultPreviewer.html
client/console/src/main/resources/org/apache/syncope/client/console/widgets/ReconDetailsModalPanel.html [moved from client/console/src/main/resources/org/apache/syncope/client/console/widgets/ReconciliationDetailsModalPanel.html with 100% similarity]
client/console/src/main/resources/org/apache/syncope/client/console/wizards/AbstractMappingPanel.html
client/console/src/main/resources/org/apache/syncope/client/console/wizards/any/AnnotatedBeanPanel.html
client/console/src/main/resources/org/apache/syncope/client/console/wizards/any/ConnObjectPanel.html
client/console/src/main/resources/org/apache/syncope/client/console/wizards/any/Details.html
client/console/src/main/resources/org/apache/syncope/client/console/wizards/any/DynamicMemberships.html
client/console/src/main/resources/org/apache/syncope/client/console/wizards/any/Ownership.html
client/console/src/main/resources/org/apache/syncope/client/console/wizards/any/Relationships$Specification.html
client/console/src/main/resources/org/apache/syncope/client/console/wizards/any/Relationships.html
client/console/src/main/resources/org/apache/syncope/client/console/wizards/any/Resources.html
client/console/src/main/resources/org/apache/syncope/client/console/wizards/any/ResultPage.html
client/console/src/main/resources/org/apache/syncope/client/console/wizards/any/Roles.html
client/console/src/main/resources/org/apache/syncope/client/console/wizards/any/StatusPanel.html
client/console/src/main/resources/org/apache/syncope/client/console/wizards/any/UserInformationPanel.html
common/lib/src/main/java/org/apache/syncope/common/lib/to/ReconStatus.java [moved from common/lib/src/main/java/org/apache/syncope/common/lib/to/ReconciliationStatus.java with 85% similarity]
common/lib/src/main/java/org/apache/syncope/common/lib/types/AnyTypeKind.java
common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/ReconciliationService.java
core/logic/src/main/java/org/apache/syncope/core/logic/ReconciliationLogic.java
core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPARoleDAO.java
core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/SinglePullJobDelegate.java
core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/SinglePushJobDelegate.java
core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/ReconciliationServiceImpl.java
fit/core-reference/src/test/java/org/apache/syncope/fit/console/BulkActionITCase.java
fit/core-reference/src/test/java/org/apache/syncope/fit/console/RealmsITCase.java
fit/core-reference/src/test/java/org/apache/syncope/fit/console/TopologyITCase.java
fit/core-reference/src/test/java/org/apache/syncope/fit/core/ReconciliationITCase.java

index 60077ba..10e4fa5 100644 (file)
@@ -325,13 +325,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);
 
@@ -344,11 +344,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());
                     }
@@ -356,7 +356,7 @@ public class ApprovalDirectoryPanel
 
             }
 
-            return actual;
+            return result;
         }
     }
 
index faf7255..4287521 100644 (file)
@@ -203,37 +203,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;
                                 }
                             }
                         }
index ff4161c..0eca373 100644 (file)
@@ -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);
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 (file)
index 3ce39ea..0000000
+++ /dev/null
@@ -1,137 +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.Collections;
-import java.util.Iterator;
-import java.util.List;
-import java.util.stream.Collectors;
-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> statuses = result.stream().map(any -> {
-            List<ConnObjectWrapper> connObjects =
-                    statusUtils.getConnectorObjects(any, Collections.singletonList(resource));
-
-            return statusUtils.getStatusBean(
-                    any,
-                    resource,
-                    connObjects.isEmpty() ? null : connObjects.iterator().next().getConnObjectTO(),
-                    any instanceof GroupTO);
-        }).collect(Collectors.toList());
-
-        Collections.sort(statuses, comparator);
-        return statuses.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);
-    }
-}
index 7d9a688..50619e5 100644 (file)
@@ -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);
 
 }
index 06ccac7..14dca77 100644 (file)
@@ -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() {
index fe7ce9f..fc834b5 100644 (file)
@@ -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() {
index 608dee1..7ba310e 100644 (file)
 package org.apache.syncope.client.console.commons.status;
 
 import java.io.Serializable;
-import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
+import java.util.Objects;
 import java.util.Optional;
+import java.util.stream.Collectors;
 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;
@@ -41,78 +44,50 @@ 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) {
-
-        final List<ConnObjectWrapper> objects = new ArrayList<>();
-
-        for (String resourceName : resources) {
-            ConnObjectTO objectTO = null;
+        return resources.stream().map(resource -> {
             try {
-                objectTO = restClient.readConnObject(resourceName, any.getType(), any.getKey());
+                return RECONCILIATION_REST_CLIENT.status(anyTypeKind, anyKey, resource);
             } catch (Exception e) {
-                LOG.warn("ConnObject '{}' not found on resource '{}'", any.getKey(), resourceName);
+                LOG.warn("Unexpected error for {} {} on {}", anyTypeKind, anyKey, resource, e);
+                return null;
             }
-
-            objects.add(new ConnObjectWrapper(any, resourceName, objectTO));
-        }
-
-        return objects;
+        }).filter(Objects::nonNull).collect(Collectors.toList());
     }
 
-    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(
+    public static StatusBean getStatusBean(
             final RealmTO anyTO,
             final String resourceName,
             final ConnObjectTO objectTO) {
@@ -137,31 +112,31 @@ public class StatusUtils implements Serializable {
         return statusBean;
     }
 
-    private Boolean isEnabled(final ConnObjectTO objectTO) {
+    private static Boolean isEnabled(final ConnObjectTO objectTO) {
         Optional<AttrTO> status = objectTO.getAttr(ConnIdSpecialName.ENABLE);
         return status.isPresent() && status.get().getValues() != null && !status.get().getValues().isEmpty()
                 ? Boolean.valueOf(status.get().getValues().get(0))
                 : Boolean.FALSE;
     }
 
-    private String getConnObjectLink(final ConnObjectTO objectTO) {
+    private static String getConnObjectLink(final ConnObjectTO objectTO) {
         Optional<AttrTO> name = objectTO == null ? null : objectTO.getAttr(ConnIdSpecialName.NAME);
-        return name.isPresent() && name.get().getValues() != null && !name.get().getValues().isEmpty()
+        return name != null && name.isPresent() && name.get().getValues() != null && !name.get().getValues().isEmpty()
                 ? name.get().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) {
+        statuses.forEach((status) -> {
             if (Constants.SYNCOPE.equalsIgnoreCase(status.getResource())) {
                 builder.onSyncope(true);
             } else {
                 builder.resource(status.getResource());
             }
-        }
+        });
         return builder.build();
     }
 
@@ -172,13 +147,13 @@ public class StatusUtils implements Serializable {
     public static StatusPatch buildStatusPatch(final Collection<StatusBean> statuses, final Boolean enable) {
         StatusPatch.Builder builder = new StatusPatch.Builder();
         builder.onSyncope(false);
-        for (StatusBean status : statuses) {
+        statuses.forEach((status) -> {
             if ("syncope".equalsIgnoreCase(status.getResource())) {
                 builder.onSyncope(true);
             } else {
                 builder.resource(status.getResource());
             }
-        }
+        });
 
         return builder.build();
     }
@@ -295,4 +270,8 @@ public class StatusUtils implements Serializable {
             }
         };
     }
+
+    private StatusUtils() {
+        // private constructor for static utility class
+    }
 }
index 001de67..aa7b19f 100644 (file)
@@ -249,15 +249,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)));
@@ -269,8 +271,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),
index 427953b..bea77ae 100644 (file)
@@ -27,7 +27,7 @@ import java.util.Collection;
 import java.util.Date;
 import java.util.List;
 import java.util.stream.Collectors;
-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;
@@ -285,15 +285,14 @@ public abstract class AnyDirectoryPanel<A extends AnyTO, E extends AbstractAnyRe
                 panelId,
                 ((ProvisioningResult<A>) result).getEntity(),
                 new ListModel<>(new ArrayList<>()),
-                ((ProvisioningResult<A>) result).getPropagationStatuses().stream().
-                        map(input -> {
-                            ConnObjectTO before = input.getBeforeObj();
-                            ConnObjectWrapper afterObjWrapper = new ConnObjectWrapper(
-                                    ((ProvisioningResult<A>) result).getEntity(),
-                                    input.getResource(),
-                                    input.getAfterObj());
-                            return Pair.of(before, afterObjWrapper);
-                        }).collect(Collectors.toList()),
+                ((ProvisioningResult<A>) result).getPropagationStatuses().stream().map(status -> {
+                    ConnObjectTO before = status.getBeforeObj();
+                    ConnObjectWrapper afterObjWrapper = new ConnObjectWrapper(
+                            ((ProvisioningResult<A>) result).getEntity(),
+                            status.getResource(),
+                            status.getAfterObj());
+                    return Triple.of(before, afterObjWrapper, status.getFailureReason());
+                }).collect(Collectors.toList()),
                 pageRef);
     }
 }
index 98a289e..4f348be 100644 (file)
@@ -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);
     }
 
index 303cbf1..881ae74 100644 (file)
@@ -73,7 +73,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);
 
index 4f0029c..6050d30 100644 (file)
@@ -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 {
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 (file)
index 0000000..c6d4da9
--- /dev/null
@@ -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));
+    }
+}
index e3f121c..95331ee 100644 (file)
@@ -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;
 
@@ -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());
         }
     }
index f491f2b..9edcded 100644 (file)
@@ -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
index 5a6ab4e..6c4231d 100644 (file)
 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();
 }
index 0dc3196..47e3545 100644 (file)
@@ -23,13 +23,10 @@ import de.agilecoders.wicket.extensions.markup.html.bootstrap.form.checkbox.boot
 import java.io.Serializable;
 import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
 import java.util.Map;
 import java.util.stream.Collectors;
-import org.apache.commons.collections4.CollectionUtils;
-import org.apache.commons.collections4.Transformer;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.commons.lang3.tuple.Pair;
 import org.apache.syncope.client.console.commons.Constants;
@@ -378,7 +375,7 @@ public class SearchClausePanel extends FieldPanel<SearchClause> {
         final AjaxTextFieldPanel property = new AjaxTextFieldPanel(
                 "property",
                 "property",
-                new PropertyModel<String>(searchClause, "property"),
+                new PropertyModel<>(searchClause, "property"),
                 false);
         property.hideLabel().setOutputMarkupId(true).setEnabled(true);
         property.setChoices(properties.getObject());
@@ -424,16 +421,8 @@ public class SearchClausePanel extends FieldPanel<SearchClause> {
                                     AnyObjectSearchPanel.MAX_GROUP_LIST_CARDINALITY,
                                     new SortParam<>("name", true),
                                     null);
-                            Collection<String> newList = CollectionUtils.collect(filteredGroups,
-                                    new Transformer<GroupTO, String>() {
-
-                                @Override
-                                public String transform(final GroupTO input) {
-                                    return input.getName();
-                                }
-                            });
-
-                            final List<String> names = new ArrayList<>(newList);
+                            List<String> names = filteredGroups.stream().
+                                    map(GroupTO::getName).collect(Collectors.toList());
                             Collections.sort(names);
                             property.setChoices(names);
                         }
@@ -614,7 +603,7 @@ public class SearchClausePanel extends FieldPanel<SearchClause> {
                     properties.detach();
                     property.setChoices(properties.getObject());
                     break;
-                    
+
                 case GROUP_MEMBERSHIP:
                     value.setEnabled(false);
                     value.setModelObject(StringUtils.EMPTY);
index 4cfdddb..639a4eb 100644 (file)
@@ -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);
 
index a885764..86a9e29 100644 (file)
@@ -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();
index c7ff004..9ecd9ca 100644 (file)
@@ -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();
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 (file)
index 0000000..16960de
--- /dev/null
@@ -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);
+    }
+}
index b64ff9b..514d970 100644 (file)
@@ -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;
     }
 }
index 087bdf8..f39e823 100644 (file)
 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 java.util.stream.Collectors;
 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,9 +43,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.EntityTO;
 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;
@@ -70,9 +77,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,
@@ -91,12 +100,19 @@ 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 = new ResourceRestClient().list().stream().
+                filter(resource -> resource.getProvision(anyTO.getType()).isPresent()).
+                map(EntityTO::getKey).collect(Collectors.toList());
+
         initResultTable();
     }
 
@@ -126,7 +142,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");
@@ -136,26 +154,29 @@ public class AnyStatusDirectoryPanel
             }
         });
 
-        columns.add(new PropertyColumn<>(
-                new StringResourceModel("connObjectLink", this), "connObjectLink", "connObjectLink"));
+        if (statusOnly) {
+            columns.add(new PropertyColumn<>(
+                    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;
     }
 
@@ -163,32 +184,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);
@@ -199,14 +258,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
@@ -214,74 +272,82 @@ 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<>();
-            new ResourceRestClient().list().forEach(resourceTO -> {
-                resources.add(resourceTO.getKey());
-            });
-
-            final List<ConnObjectWrapper> connObjects = statusUtils.getConnectorObjects(actual);
-
-            final List<StatusBean> statusBeans = new ArrayList<>(connObjects.size() + 1);
+            List<StatusBean> statusBeans = actual.getResources().stream().map(resource -> {
+                List<ReconStatus> statuses = Collections.emptyList();
+                if (statusOnly) {
+                    statuses = StatusUtils.
+                            getReconStatuses(anyTypeKind, anyTO.getKey(), Arrays.asList(resource));
+                }
 
-            connObjects.forEach(entry -> {
-                final StatusBean statusBean = statusUtils.getStatusBean(actual,
-                        entry.getResourceName(),
-                        entry.getConnObjectTO(),
+                return StatusUtils.getStatusBean(
+                        actual,
+                        resource,
+                        statuses.isEmpty() ? null : statuses.get(0).getOnResource(),
                         actual instanceof GroupTO);
-
-                statusBeans.add(statusBean);
-                resources.remove(entry.getResourceName());
-            });
+            }).collect(Collectors.toList());
 
             if (statusOnly) {
-                final StatusBean syncope = new StatusBean(actual, "Syncope");
+                StatusBean syncope = new StatusBean(actual, Constants.SYNCOPE);
+                switch (anyTypeKind) {
+                    case USER:
+                        syncope.setConnObjectLink(((UserTO) actual).getUsername());
+                        break;
+
+                    case GROUP:
+                        syncope.setConnObjectLink(((GroupTO) actual).getName());
+                        break;
 
-                syncope.setConnObjectLink(((UserTO) actual).getUsername());
+                    case ANY_OBJECT:
+                        syncope.setConnObjectLink(((AnyObjectTO) actual).getName());
+                        break;
+
+                    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 {
-                resources.stream().
-                        map(resource -> statusUtils.getStatusBean(actual,
-                        resource,
-                        null,
-                        actual instanceof GroupTO)).
-                        map(statusBean -> {
+                statusBeans.addAll(resources.stream().
+                        filter(resource -> !anyTO.getResources().contains(resource)).
+                        map(resource -> {
+                            StatusBean statusBean = StatusUtils.getStatusBean(
+                                    actual,
+                                    resource,
+                                    null,
+                                    actual instanceof GroupTO);
                             statusBean.setLinked(false);
                             return statusBean;
-                        }).
-                        forEachOrdered(statusBean -> {
-                            statusBeans.add(statusBean);
-                        });
+                        }).collect(Collectors.toList()));
+
+                Collections.sort(statusBeans, comparator);
             }
 
-            return statusBeans;
+            return first == -1 && count == -1
+                    ? statusBeans
+                    : statusBeans.subList((int) first, (int) first + (int) count);
         }
     }
 }
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 (file)
index 0000000..91dc9ac
--- /dev/null
@@ -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());
+    }
+}
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/status/ReconTaskPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/status/ReconTaskPanel.java
new file mode 100644 (file)
index 0000000..3dadb56
--- /dev/null
@@ -0,0 +1,162 @@
+/*
+ * 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 java.util.stream.Collectors;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.syncope.client.console.SyncopeConsoleSession;
+import org.apache.syncope.client.console.commons.Constants;
+import org.apache.syncope.client.console.pages.BasePage;
+import org.apache.syncope.client.console.panels.MultilevelPanel;
+import org.apache.syncope.client.console.rest.ImplementationRestClient;
+import org.apache.syncope.client.console.rest.ReconciliationRestClient;
+import org.apache.syncope.client.console.wicket.markup.html.form.AjaxCheckBoxPanel;
+import org.apache.syncope.client.console.wicket.markup.html.form.AjaxDropDownChoicePanel;
+import org.apache.syncope.client.console.wicket.markup.html.form.AjaxPalettePanel;
+import org.apache.syncope.common.lib.to.EntityTO;
+import org.apache.syncope.common.lib.to.ProvisioningTaskTO;
+import org.apache.syncope.common.lib.to.PullTaskTO;
+import org.apache.syncope.common.lib.to.PushTaskTO;
+import org.apache.syncope.common.lib.types.AnyTypeKind;
+import org.apache.syncope.common.lib.types.ImplementationType;
+import org.apache.syncope.common.lib.types.MatchingRule;
+import org.apache.syncope.common.lib.types.UnmatchingRule;
+import org.apache.wicket.PageReference;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.ajax.markup.html.form.AjaxSubmitLink;
+import org.apache.wicket.markup.html.form.Form;
+import org.apache.wicket.model.CompoundPropertyModel;
+import org.apache.wicket.model.IModel;
+import org.apache.wicket.model.LoadableDetachableModel;
+import org.apache.wicket.model.PropertyModel;
+import org.apache.wicket.model.util.ListModel;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ReconTaskPanel extends MultilevelPanel.SecondLevel {
+
+    private static final long serialVersionUID = 5870444905957760434L;
+
+    protected static final Logger LOG = LoggerFactory.getLogger(ReconTaskPanel.class);
+
+    private final ReconciliationRestClient restClient = new ReconciliationRestClient();
+
+    private final ImplementationRestClient implRestClient = new ImplementationRestClient();
+
+    private final IModel<List<String>> pullActions = new LoadableDetachableModel<List<String>>() {
+
+        private static final long serialVersionUID = 5275935387613157437L;
+
+        @Override
+        protected List<String> load() {
+            return implRestClient.list(ImplementationType.PULL_ACTIONS).stream().
+                    map(EntityTO::getKey).sorted().collect(Collectors.toList());
+        }
+    };
+
+    private final IModel<List<String>> pushActions = new LoadableDetachableModel<List<String>>() {
+
+        private static final long serialVersionUID = 5275935387613157437L;
+
+        @Override
+        protected List<String> load() {
+            return implRestClient.list(ImplementationType.PUSH_ACTIONS).stream().
+                    map(EntityTO::getKey).sorted().collect(Collectors.toList());
+        }
+    };
+
+    public ReconTaskPanel(
+            final String resource,
+            final ProvisioningTaskTO taskTO,
+            final AnyTypeKind anyTypeKind,
+            final String anyKey,
+            final MultilevelPanel multiLevelPanelRef,
+            final PageReference pageRef) {
+
+        Form<ProvisioningTaskTO> form = new Form<>("form", new CompoundPropertyModel<>(taskTO));
+        add(form);
+
+        AjaxPalettePanel<String> actions = new AjaxPalettePanel.Builder<String>().
+                setAllowMoveAll(true).setAllowOrder(true).
+                build("actions",
+                        new PropertyModel<List<String>>(taskTO, "actions"),
+                        new ListModel<>(taskTO instanceof PushTaskTO
+                                ? pushActions.getObject() : pullActions.getObject()));
+        actions.setOutputMarkupId(true);
+        form.add(actions);
+
+        AjaxDropDownChoicePanel<MatchingRule> matchingRule = new AjaxDropDownChoicePanel<>(
+                "matchingRule", "matchingRule", new PropertyModel<MatchingRule>(taskTO, "matchingRule"), false);
+        matchingRule.setChoices(Arrays.asList(MatchingRule.values()));
+        form.add(matchingRule);
+
+        AjaxDropDownChoicePanel<UnmatchingRule> unmatchingRule = new AjaxDropDownChoicePanel<>(
+                "unmatchingRule", "unmatchingRule", new PropertyModel<UnmatchingRule>(taskTO, "unmatchingRule"),
+                false);
+        unmatchingRule.setChoices(Arrays.asList(UnmatchingRule.values()));
+        form.add(unmatchingRule);
+
+        taskTO.setPerformCreate(true);
+        AjaxCheckBoxPanel performCreate = new AjaxCheckBoxPanel(
+                "performCreate", "performCreate", new PropertyModel<Boolean>(taskTO, "performCreate"), false);
+        form.add(performCreate);
+
+        taskTO.setPerformUpdate(true);
+        AjaxCheckBoxPanel performUpdate = new AjaxCheckBoxPanel(
+                "performUpdate", "performUpdate", new PropertyModel<Boolean>(taskTO, "performUpdate"), false);
+        form.add(performUpdate);
+
+        taskTO.setPerformDelete(true);
+        AjaxCheckBoxPanel performDelete = new AjaxCheckBoxPanel(
+                "performDelete", "performDelete", new PropertyModel<Boolean>(taskTO, "performDelete"), false);
+        form.add(performDelete);
+
+        taskTO.setSyncStatus(true);
+        AjaxCheckBoxPanel syncStatus = new AjaxCheckBoxPanel(
+                "syncStatus", "syncStatus", new PropertyModel<Boolean>(taskTO, "syncStatus"), false);
+        form.add(syncStatus);
+
+        form.add(new AjaxSubmitLink("reconcile") {
+
+            private static final long serialVersionUID = -817438685948164787L;
+
+            @Override
+            protected void onSubmit(final AjaxRequestTarget target, final Form<?> form) {
+                try {
+                    if (taskTO instanceof PushTaskTO) {
+                        restClient.push(anyTypeKind, anyKey, resource, (PushTaskTO) form.getModelObject());
+                    } else {
+                        restClient.pull(anyTypeKind, anyKey, resource, (PullTaskTO) form.getModelObject());
+                    }
+
+                    SyncopeConsoleSession.get().info(getString(Constants.OPERATION_SUCCEEDED));
+                } catch (Exception e) {
+                    LOG.error("While attempting reconciliation on {} {} {} {}",
+                            anyTypeKind, anyKey, resource, form.getModelObject(), e);
+                    SyncopeConsoleSession.get().error(resource + ": "
+                            + (StringUtils.isBlank(e.getMessage()) ? e.getClass().getName() : e.getMessage()));
+                }
+                multiLevelPanelRef.prev(target);
+                ((BasePage) pageRef.getPage()).getNotificationPanel().refresh(target);
+            }
+        });
+    }
+}
index a37ab4a..c75dce3 100644 (file)
@@ -21,9 +21,10 @@ package org.apache.syncope.client.console.status;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
+import java.util.stream.Collectors;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.syncope.client.console.commons.DirectoryDataProvider;
-import org.apache.syncope.client.console.commons.ResourceStatusDataProvider;
+import org.apache.syncope.client.console.commons.status.AbstractStatusBeanProvider;
 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;
@@ -36,16 +37,21 @@ import org.apache.syncope.client.console.rest.GroupRestClient;
 import org.apache.syncope.client.console.rest.UserRestClient;
 import org.apache.syncope.client.console.wicket.markup.html.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.client.lib.SyncopeClient;
 import org.apache.syncope.common.lib.SyncopeConstants;
+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.syncope.common.lib.to.PullTaskTO;
+import org.apache.syncope.common.lib.to.PushTaskTO;
 import org.apache.syncope.common.lib.to.ResourceTO;
+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;
-import org.apache.wicket.extensions.markup.html.repeater.data.grid.ICellPopulator;
-import org.apache.wicket.extensions.markup.html.repeater.data.table.AbstractColumn;
 import org.apache.wicket.extensions.markup.html.repeater.data.table.IColumn;
 import org.apache.wicket.extensions.markup.html.repeater.data.table.PropertyColumn;
-import org.apache.wicket.markup.html.basic.Label;
-import org.apache.wicket.markup.repeater.Item;
 import org.apache.wicket.model.IModel;
 import org.apache.wicket.model.StringResourceModel;
 
@@ -61,21 +67,21 @@ public class ResourceStatusDirectoryPanel
 
     private String type;
 
-    private final ResourceTO resourceTO;
+    private final ResourceTO resource;
 
     public ResourceStatusDirectoryPanel(
             final BaseModal<?> baseModal,
             final MultilevelPanel multiLevelPanelRef,
             final PageReference pageRef,
             final String type,
-            final ResourceTO resourceTO) {
+            final ResourceTO resource) {
 
         super(MultilevelPanel.FIRST_LEVEL_ID, pageRef);
         this.baseModal = baseModal;
         this.multiLevelPanelRef = multiLevelPanelRef;
         this.type = type;
-        this.resourceTO = resourceTO;
-        this.itemKeyFieldName = "key";
+        this.resource = resource;
+        this.itemKeyFieldName = "name";
 
         initResultTable();
     }
@@ -89,44 +95,117 @@ public class ResourceStatusDirectoryPanel
     protected List<IColumn<StatusBean, String>> getColumns() {
         final List<IColumn<StatusBean, String>> columns = new ArrayList<>();
 
-        columns.add(new PropertyColumn<>(
-                new StringResourceModel("key", this), "key", "key"));
+        columns.add(new PropertyColumn<>(new StringResourceModel("name", this), "name", "name"));
 
-        columns.add(new PropertyColumn<>(
-                new StringResourceModel("connObjectLink", this), "connObjectLink", "connObjectLink"));
+        return columns;
+    }
+
+    private AnyTypeKind getAnyTypeKind() {
+        if (StringUtils.isBlank(type)) {
+            return null;
+        }
+
+        switch (type) {
+            case "USER":
+                return AnyTypeKind.USER;
+
+            case "GROUP":
+                return AnyTypeKind.GROUP;
+
+            default:
+                return AnyTypeKind.ANY_OBJECT;
+        }
+    }
+
+    @Override
+    public ActionsPanel<StatusBean> getActions(final IModel<StatusBean> model) {
+        final ActionsPanel<StatusBean> panel = super.getActions(model);
 
-        columns.add(new AbstractColumn<StatusBean, String>(new StringResourceModel("status", this)) {
+        panel.add(new ActionLink<StatusBean>() {
 
-            private static final long serialVersionUID = -3503023501954863131L;
+            private static final long serialVersionUID = -7978723352517770645L;
 
             @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, ""));
-                }
+            protected boolean statusCondition(final StatusBean bean) {
+                return getAnyTypeKind() != null;
             }
-        });
 
-        return columns;
+            @Override
+            public void onClick(final AjaxRequestTarget target, final StatusBean bean) {
+                multiLevelPanelRef.next(bean.getResource(),
+                        new ReconStatusPanel(bean.getResource(), getAnyTypeKind(), bean.getKey()),
+                        target);
+                target.add(multiLevelPanelRef);
+                getTogglePanel().close(target);
+            }
+        }, ActionLink.ActionType.VIEW, StandardEntitlement.RESOURCE_GET_CONNOBJECT);
+
+        panel.add(new ActionLink<StatusBean>() {
+
+            private static final long serialVersionUID = -7978723352517770645L;
+
+            @Override
+            protected boolean statusCondition(final StatusBean bean) {
+                return getAnyTypeKind() != null;
+            }
+
+            @Override
+            public void onClick(final AjaxRequestTarget target, final StatusBean bean) {
+                multiLevelPanelRef.next("PUSH " + bean.getResource(),
+                        new ReconTaskPanel(
+                                bean.getResource(),
+                                new PushTaskTO(),
+                                getAnyTypeKind(),
+                                bean.getKey(),
+                                multiLevelPanelRef,
+                                pageRef),
+                        target);
+                target.add(multiLevelPanelRef);
+                getTogglePanel().close(target);
+            }
+        }, ActionLink.ActionType.RECONCILIATION_PUSH, StandardEntitlement.TASK_EXECUTE);
+
+        panel.add(new ActionLink<StatusBean>() {
+
+            private static final long serialVersionUID = -7978723352517770645L;
+
+            @Override
+            protected boolean statusCondition(final StatusBean bean) {
+                return getAnyTypeKind() != null;
+            }
+
+            @Override
+            public void onClick(final AjaxRequestTarget target, final StatusBean bean) {
+                multiLevelPanelRef.next("PULL " + bean.getResource(),
+                        new ReconTaskPanel(
+                                bean.getResource(),
+                                new PullTaskTO(),
+                                getAnyTypeKind(),
+                                bean.getKey(),
+                                multiLevelPanelRef,
+                                pageRef),
+                        target);
+                target.add(multiLevelPanelRef);
+                getTogglePanel().close(target);
+            }
+        }, ActionLink.ActionType.RECONCILIATION_PULL, StandardEntitlement.TASK_EXECUTE);
+
+        return panel;
     }
 
     public void updateResultTable(final String type, final AjaxRequestTarget target) {
         this.type = type;
 
-        if (StringUtils.isNoneEmpty(type)) {
+        if (StringUtils.isNotBlank(type)) {
             switch (type) {
                 case "USER":
                     this.restClient = new UserRestClient();
                     break;
+
                 case "GROUP":
                     this.restClient = new GroupRestClient();
                     break;
+
                 default:
                     this.restClient = new AnyObjectRestClient();
             }
@@ -137,20 +216,85 @@ public class ResourceStatusDirectoryPanel
 
     @Override
     protected Collection<ActionLink.ActionType> getBulkActions() {
-        final List<ActionLink.ActionType> bulkActions = new ArrayList<>();
+        List<ActionLink.ActionType> bulkActions = new ArrayList<>();
         bulkActions.add(ActionLink.ActionType.UNLINK);
+        bulkActions.add(ActionLink.ActionType.LINK);
         bulkActions.add(ActionLink.ActionType.DEPROVISION);
+        bulkActions.add(ActionLink.ActionType.PROVISION);
+        bulkActions.add(ActionLink.ActionType.ASSIGN);
         bulkActions.add(ActionLink.ActionType.UNASSIGN);
         return bulkActions;
     }
 
     @Override
     protected ResourceStatusDataProvider dataProvider() {
-        return new ResourceStatusDataProvider(type, resourceTO.getKey(), rows, SyncopeConstants.ROOT_REALM);
+        return new ResourceStatusDataProvider();
     }
 
     @Override
     protected String paginatorRowsKey() {
         return StringUtils.EMPTY;
     }
+
+    protected class ResourceStatusDataProvider extends AbstractStatusBeanProvider {
+
+        private static final long serialVersionUID = 4586969457669796621L;
+
+        private final String fiql;
+
+        private final AbstractAnyRestClient<? extends AnyTO> restClient;
+
+        public ResourceStatusDataProvider() {
+            super(AnyTypeKind.USER.name().equals(type) ? "username" : "name");
+
+            if (StringUtils.isEmpty(type)) {
+                fiql = null;
+                restClient = null;
+            } else {
+                AbstractFiqlSearchConditionBuilder bld;
+                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();
+                }
+                fiql = bld.isNotNull("key").query();
+            }
+        }
+
+        @Override
+        protected List<StatusBean> getStatusBeans(final long first, final long count) {
+            List<StatusBean> statusBeans = new ArrayList<>();
+
+            if (fiql != null && restClient != null) {
+                int page = (int) first / paginatorRows;
+                List<? extends AnyTO> result = restClient.search(
+                        SyncopeConstants.ROOT_REALM, fiql, (page < 0 ? 0 : page) + 1, paginatorRows, getSort(), type);
+
+                statusBeans.addAll(result.stream().map(any -> StatusUtils.getStatusBean(
+                        any,
+                        resource.getKey(),
+                        null,
+                        any instanceof GroupTO)).collect(Collectors.toList()));
+            }
+
+            return statusBeans;
+        }
+
+        @Override
+        public long size() {
+            return fiql == null
+                    ? 0
+                    : restClient.count(SyncopeConstants.ROOT_REALM, fiql, type);
+        }
+    }
 }
index baba5a5..d1387e0 100644 (file)
@@ -18,7 +18,6 @@
  */
 package org.apache.syncope.client.console.status;
 
-import java.io.Serializable;
 import org.apache.syncope.client.console.commons.DirectoryDataProvider;
 import org.apache.syncope.client.console.commons.status.StatusBean;
 import org.apache.syncope.client.console.panels.DirectoryPanel;
@@ -26,10 +25,11 @@ import org.apache.syncope.client.console.panels.ModalPanel;
 import org.apache.syncope.client.console.panels.MultilevelPanel;
 import org.apache.syncope.client.console.rest.AbstractAnyRestClient;
 import org.apache.syncope.client.console.wicket.markup.html.bootstrap.dialog.BaseModal;
+import org.apache.syncope.common.lib.AbstractBaseBean;
 import org.apache.wicket.PageReference;
 import org.apache.wicket.markup.html.panel.Panel;
 
-public abstract class StatusModal<T extends Serializable> extends Panel implements ModalPanel {
+public abstract class StatusModal<T extends AbstractBaseBean> extends Panel implements ModalPanel {
 
     private static final long serialVersionUID = 1066124171682570080L;
 
index 5f33ed5..310aa13 100644 (file)
@@ -18,7 +18,6 @@
  */
 package org.apache.syncope.client.console.topology;
 
-
 import de.agilecoders.wicket.core.markup.html.bootstrap.dialog.Modal;
 import java.io.Serializable;
 import java.text.MessageFormat;
@@ -417,7 +416,7 @@ public class TopologyTogglePanel extends TogglePanel<Serializable> {
         MetaDataRoleAuthorizationStrategy.authorize(edit, RENDER, StandardEntitlement.RESOURCE_READ);
         fragment.add(edit);
 
-        AjaxLink<String> status = new IndicatingAjaxLink<String>("status") {
+        AjaxLink<String> status = new IndicatingAjaxLink<String>("reconciliation") {
 
             private static final long serialVersionUID = 3776750333491622263L;
 
@@ -426,8 +425,8 @@ public class TopologyTogglePanel extends TogglePanel<Serializable> {
                 ResourceTO modelObject = resourceRestClient.read(node.getKey());
                 target.add(propTaskModal.setContent(
                         new ResourceStatusModal(propTaskModal, pageRef, modelObject)));
-                propTaskModal.header(new Model<>(MessageFormat.format(getString("resource.provisioning.status"),
-                        node.getKey())));
+                propTaskModal.header(
+                        new Model<>(MessageFormat.format(getString("resource.reconciliation"), node.getKey())));
                 propTaskModal.show(true);
             }
 
index 5b67fa1..d8e8f77 100644 (file)
@@ -89,6 +89,8 @@ public abstract class ActionLink<T extends Serializable> implements Serializable
         PROVISION("update"),
         DEPROVISION_MEMBERS("update"),
         PROVISION_MEMBERS("update"),
+        RECONCILIATION_PUSH("update"),
+        RECONCILIATION_PULL("update"),
         MANAGE_RESOURCES("update"),
         MANAGE_USERS("update"),
         MANAGE_GROUPS("update"),
@@ -24,6 +24,7 @@ import java.util.Collections;
 import java.util.Iterator;
 import java.util.List;
 import org.apache.commons.lang3.StringUtils;
+import org.apache.syncope.client.console.commons.Constants;
 import org.apache.syncope.client.console.commons.DirectoryDataProvider;
 import org.apache.syncope.client.console.commons.SortableDataProviderComparator;
 import org.apache.syncope.client.console.panels.AbstractModalPanel;
@@ -48,7 +49,7 @@ import org.apache.wicket.model.IModel;
 import org.apache.wicket.model.Model;
 import org.apache.wicket.model.ResourceModel;
 
-public class ReconciliationDetailsModalPanel extends AbstractModalPanel<Any> {
+public class ReconDetailsModalPanel extends AbstractModalPanel<Any> {
 
     private static final long serialVersionUID = 1469396040405535283L;
 
@@ -58,7 +59,7 @@ public class ReconciliationDetailsModalPanel extends AbstractModalPanel<Any> {
 
     private final List<Misaligned> misaligned;
 
-    public ReconciliationDetailsModalPanel(
+    public ReconDetailsModalPanel(
             final BaseModal<Any> modal,
             final String resource,
             final List<Misaligned> misaligned,
@@ -112,7 +113,7 @@ public class ReconciliationDetailsModalPanel extends AbstractModalPanel<Any> {
 
             columns.add(new PropertyColumn<>(new ResourceModel("key"), "name", "name"));
 
-            columns.add(new AbstractColumn<Misaligned, String>(Model.of("Syncope")) {
+            columns.add(new AbstractColumn<Misaligned, String>(Model.of(Constants.SYNCOPE)) {
 
                 private static final long serialVersionUID = 2054811145491901166L;
 
index 86aefed..475f6e9 100644 (file)
@@ -414,7 +414,7 @@ public class ReconciliationWidget extends BaseWidget {
                                                 rowModel.getObject().getType()
                                                 + " " + rowModel.getObject().getKey()
                                                 + " " + rowModel.getObject().getName()));
-                                        modal.setContent(new ReconciliationDetailsModalPanel(
+                                        modal.setContent(new ReconDetailsModalPanel(
                                                 modal,
                                                 resource,
                                                 misaligned,
index d52a2f7..184de10 100644 (file)
@@ -68,22 +68,22 @@ public class AnyObjectWizardBuilder extends AnyWizardBuilder<AnyObjectTO> implem
     protected Serializable onApplyInternal(final AnyWrapper<AnyObjectTO> modelObject) {
         final AnyObjectTO inner = modelObject.getInnerObject();
 
-        ProvisioningResult<AnyObjectTO> actual;
+        ProvisioningResult<AnyObjectTO> result;
         if (inner.getKey() == null) {
-            actual = anyObjectRestClient.create(inner);
+            result = anyObjectRestClient.create(inner);
         } else {
             AnyObjectPatch patch = AnyOperations.diff(inner, getOriginalItem().getInnerObject(), false);
 
             // update just if it is changed
             if (patch.isEmpty()) {
-                actual = new ProvisioningResult<>();
-                actual.setEntity(inner);
+                result = new ProvisioningResult<>();
+                result.setEntity(inner);
             } else {
-                actual = anyObjectRestClient.update(getOriginalItem().getInnerObject().getETagValue(), patch);
+                result = anyObjectRestClient.update(getOriginalItem().getInnerObject().getETagValue(), patch);
             }
         }
 
-        return actual;
+        return result;
     }
 
     @Override
index 4ebd393..ada36d3 100644 (file)
@@ -35,6 +35,7 @@ import org.apache.syncope.common.lib.EntityTOUtils;
 import org.apache.wicket.Component;
 import org.apache.wicket.behavior.Behavior;
 import org.apache.wicket.markup.ComponentTag;
+import org.apache.wicket.markup.html.basic.Label;
 import org.apache.wicket.markup.html.list.ListItem;
 import org.apache.wicket.markup.html.list.ListView;
 import org.apache.wicket.markup.html.panel.Fragment;
@@ -48,7 +49,12 @@ public class ConnObjectPanel extends Panel {
 
     private static final long serialVersionUID = -6469290753080058487L;
 
-    public ConnObjectPanel(final String id, final Pair<ConnObjectTO, ConnObjectTO> connObjectTOs, final boolean view) {
+    public ConnObjectPanel(
+            final String id,
+            final Pair<IModel<?>, IModel<?>> titles,
+            final Pair<ConnObjectTO, ConnObjectTO> connObjectTOs,
+            final boolean hideLeft) {
+
         super(id);
 
         final IModel<List<String>> formProps = new LoadableDetachableModel<List<String>>() {
@@ -60,29 +66,28 @@ public class ConnObjectPanel extends Panel {
                 List<AttrTO> right = new ArrayList<>(connObjectTOs == null || connObjectTOs.getRight() == null
                         ? Collections.<AttrTO>emptyList()
                         : connObjectTOs.getRight().getAttrs());
-
                 List<AttrTO> left = new ArrayList<>(connObjectTOs == null || connObjectTOs.getLeft() == null
                         ? Collections.<AttrTO>emptyList()
                         : connObjectTOs.getLeft().getAttrs());
 
-                final List<String> schemas = ListUtils.sum(
+                List<String> schemas = ListUtils.sum(
                         right.stream().map(AttrTO::getSchema).collect(Collectors.toList()),
                         left.stream().map(AttrTO::getSchema).collect(Collectors.toList()));
-
                 Collections.sort(schemas);
-
                 return schemas;
             }
         };
 
-        final Map<String, AttrTO> beforeProfile = connObjectTOs == null || connObjectTOs.getLeft() == null
+        add(new Label("leftTitle", titles.getLeft()).setOutputMarkupPlaceholderTag(true).setVisible(!hideLeft));
+        add(new Label("rightTitle", titles.getRight()));
+
+        final Map<String, AttrTO> leftProfile = connObjectTOs == null || connObjectTOs.getLeft() == null
                 ? null
                 : EntityTOUtils.buildAttrMap(connObjectTOs.getLeft().getAttrs());
-        final Map<String, AttrTO> afterProfile = connObjectTOs == null || connObjectTOs.getRight() == null
+        final Map<String, AttrTO> rightProfile = connObjectTOs == null || connObjectTOs.getRight() == null
                 ? null
                 : EntityTOUtils.buildAttrMap(connObjectTOs.getRight().getAttrs());
-
-        final ListView<String> propView = new ListView<String>("propView", formProps) {
+        ListView<String> propView = new ListView<String>("propView", formProps) {
 
             private static final long serialVersionUID = 3109256773218160485L;
 
@@ -91,29 +96,25 @@ public class ConnObjectPanel extends Panel {
                 final String prop = item.getModelObject();
 
                 final Fragment valueFragment;
-                final AttrTO before = beforeProfile == null ? null : beforeProfile.get(prop);
-                final AttrTO after = afterProfile == null ? null : afterProfile.get(prop);
+                final AttrTO left = leftProfile == null ? null : leftProfile.get(prop);
+                final AttrTO right = rightProfile == null ? null : rightProfile.get(prop);
 
                 valueFragment = new Fragment("value", "doubleValue", ConnObjectPanel.this);
-
-                Panel oldAttribute = getValuePanel("oldAttribute", prop, before);
-                oldAttribute.setOutputMarkupPlaceholderTag(true);
-                oldAttribute.setVisible(!view);
-                valueFragment.add(oldAttribute);
-
-                valueFragment.add(getValuePanel("newAttribute", prop, after));
-
-                if (before == null || after == null
-                        || (CollectionUtils.isNotEmpty(after.getValues())
-                        && CollectionUtils.isEmpty(before.getValues()))
-                        || (CollectionUtils.isEmpty(after.getValues())
-                        && CollectionUtils.isNotEmpty(before.getValues()))
-                        || (CollectionUtils.isNotEmpty(after.getValues())
-                        && CollectionUtils.isNotEmpty(before.getValues())
-                        && after.getValues().size() != before.getValues().size())
-                        || (CollectionUtils.isNotEmpty(after.getValues())
-                        && CollectionUtils.isNotEmpty(before.getValues())
-                        && !after.getValues().equals(before.getValues()))) {
+                valueFragment.add(getValuePanel("leftAttribute", prop, left).
+                        setOutputMarkupPlaceholderTag(true).setVisible(!hideLeft));
+                valueFragment.add(getValuePanel("rightAttribute", prop, right));
+
+                if (left == null || right == null
+                        || (CollectionUtils.isNotEmpty(right.getValues())
+                        && CollectionUtils.isEmpty(left.getValues()))
+                        || (CollectionUtils.isEmpty(right.getValues())
+                        && CollectionUtils.isNotEmpty(left.getValues()))
+                        || (CollectionUtils.isNotEmpty(right.getValues())
+                        && CollectionUtils.isNotEmpty(left.getValues())
+                        && right.getValues().size() != left.getValues().size())
+                        || (CollectionUtils.isNotEmpty(right.getValues())
+                        && CollectionUtils.isNotEmpty(left.getValues())
+                        && !right.getValues().equals(left.getValues()))) {
 
                     valueFragment.add(new Behavior() {
 
@@ -158,5 +159,4 @@ public class ConnObjectPanel extends Panel {
         field.setEnabled(false);
         return field;
     }
-
 }
index 4282fae..2e0d47f 100644 (file)
@@ -87,9 +87,9 @@ public class GroupWizardBuilder extends AnyWizardBuilder<GroupTO> implements Gro
                 ? GroupWrapper.class.cast(modelObject).fillDynamicConditions()
                 : modelObject.getInnerObject();
 
-        ProvisioningResult<GroupTO> actual;
+        ProvisioningResult<GroupTO> result;
         if (inner.getKey() == null) {
-            actual = groupRestClient.create(inner);
+            result = groupRestClient.create(inner);
         } else {
             GroupPatch patch = AnyOperations.diff(inner, getOriginalItem().getInnerObject(), false);
             GroupTO originaObj = getOriginalItem().getInnerObject();
@@ -107,14 +107,14 @@ public class GroupWizardBuilder extends AnyWizardBuilder<GroupTO> implements Gro
 
             // update just if it is changed
             if (patch.isEmpty() && !othersNotEqualsOrBlanks) {
-                actual = new ProvisioningResult<>();
-                actual.setEntity(inner);
+                result = new ProvisioningResult<>();
+                result.setEntity(inner);
             } else {
-                actual = groupRestClient.update(getOriginalItem().getInnerObject().getETagValue(), patch);
+                result = groupRestClient.update(getOriginalItem().getInnerObject().getETagValue(), patch);
             }
         }
 
-        return actual;
+        return result;
     }
 
     @Override
index cac7b38..93a338a 100644 (file)
 package org.apache.syncope.client.console.wizards.any;
 
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.stream.Collectors;
-import org.apache.commons.lang3.tuple.ImmutablePair;
+import org.apache.commons.lang3.StringUtils;
 import org.apache.commons.lang3.tuple.Pair;
+import org.apache.commons.lang3.tuple.Triple;
 import org.apache.syncope.client.console.commons.Constants;
 import org.apache.syncope.client.console.commons.status.ConnObjectWrapper;
 import org.apache.syncope.client.console.commons.status.Status;
@@ -32,18 +34,21 @@ 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.ListViewPanel;
 import org.apache.syncope.client.console.panels.MultilevelPanel;
+import org.apache.syncope.client.console.panels.PropagationErrorPanel;
 import org.apache.syncope.client.console.panels.RemoteObjectPanel;
 import org.apache.syncope.client.console.wicket.markup.html.form.ActionLink;
 import org.apache.syncope.common.lib.to.AnyTO;
 import org.apache.syncope.common.lib.to.ConnObjectTO;
 import org.apache.syncope.common.lib.to.GroupTO;
 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.Component;
 import org.apache.wicket.PageReference;
 import org.apache.wicket.ajax.AjaxRequestTarget;
 import org.apache.wicket.markup.html.panel.Panel;
 import org.apache.wicket.model.IModel;
+import org.apache.wicket.model.ResourceModel;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -55,8 +60,6 @@ public class StatusPanel extends Panel {
 
     private Map<String, StatusBean> initialStatusBeanMap;
 
-    private final StatusUtils statusUtils;
-
     private ListViewPanel<?> listViewPanel;
 
     public <T extends AnyTO> StatusPanel(
@@ -66,9 +69,12 @@ public class StatusPanel extends Panel {
             final PageReference pageRef) {
 
         super(id);
-        statusUtils = new StatusUtils();
-        init(any, model, statusUtils.getConnectorObjects(any).stream().
-                map(input -> new ImmutablePair<ConnObjectTO, ConnObjectWrapper>(null, input)).
+        init(any, model, StatusUtils.getReconStatuses(
+                AnyTypeKind.fromTOClass(any.getClass()), any.getKey(), any.getResources()).stream().
+                map(status -> Triple.<ConnObjectTO, ConnObjectWrapper, String>of(
+                status.getOnSyncope(),
+                new ConnObjectWrapper(any, status.getResource(), status.getOnResource()),
+                null)).
                 collect(Collectors.toList()), pageRef, false);
     }
 
@@ -76,17 +82,17 @@ public class StatusPanel extends Panel {
             final String id,
             final T any,
             final IModel<List<StatusBean>> model,
-            final List<Pair<ConnObjectTO, ConnObjectWrapper>> connObjects,
+            final List<Triple<ConnObjectTO, ConnObjectWrapper, String>> connObjects,
             final PageReference pageRef) {
+
         super(id);
-        statusUtils = new StatusUtils();
         init(any, model, connObjects, pageRef, true);
     }
 
     private void init(
             final AnyTO any,
             final IModel<List<StatusBean>> model,
-            final List<Pair<ConnObjectTO, ConnObjectWrapper>> connObjects,
+            final List<Triple<ConnObjectTO, ConnObjectWrapper, String>> connObjects,
             final PageReference pageRef,
             final boolean enableConnObjectLink) {
 
@@ -115,15 +121,20 @@ public class StatusPanel extends Panel {
         statusBeans.add(syncope);
         initialStatusBeanMap.put(syncope.getResource(), syncope);
 
-        connObjects.forEach(pair -> {
-            ConnObjectWrapper entry = pair.getRight();
-            final StatusBean statusBean = statusUtils.getStatusBean(entry.getAny(),
-                    entry.getResourceName(),
-                    entry.getConnObjectTO(),
+        Map<String, String> failureReasons = new HashMap<>();
+        connObjects.forEach(triple -> {
+            ConnObjectWrapper connObjectWrapper = triple.getMiddle();
+            StatusBean statusBean = StatusUtils.getStatusBean(connObjectWrapper.getAny(),
+                    connObjectWrapper.getResource(),
+                    connObjectWrapper.getConnObjectTO(),
                     any instanceof GroupTO);
 
-            initialStatusBeanMap.put(entry.getResourceName(), statusBean);
+            initialStatusBeanMap.put(connObjectWrapper.getResource(), statusBean);
             statusBeans.add(statusBean);
+
+            if (StringUtils.isNotBlank(triple.getRight())) {
+                failureReasons.put(connObjectWrapper.getResource(), triple.getRight());
+            }
         });
 
         final MultilevelPanel mlp = new MultilevelPanel("resources");
@@ -142,22 +153,20 @@ public class StatusPanel extends Panel {
                 }
             }
         };
-
         builder.setModel(model);
         builder.setItems(statusBeans);
         builder.includes("resource", "connObjectLink", "status");
         builder.withChecks(ListViewPanel.CheckAvailability.NONE);
         builder.setReuseItem(false);
 
-        final ActionLink<StatusBean> connObjectLink = new ActionLink<StatusBean>() {
+        ActionLink<StatusBean> connObjectLink = new ActionLink<StatusBean>() {
 
             private static final long serialVersionUID = -3722207913631435501L;
 
             @Override
             protected boolean statusCondition(final StatusBean bean) {
-                final Pair<ConnObjectTO, ConnObjectTO> pair =
-                        getConnObjectTO(bean.getKey(), bean.getResource(), connObjects);
-
+                Pair<ConnObjectTO, ConnObjectTO> pair =
+                        getConnObjectTOs(bean.getKey(), bean.getResource(), connObjects);
                 return pair != null && pair.getRight() != null;
             }
 
@@ -166,13 +175,26 @@ public class StatusPanel extends Panel {
                 mlp.next(bean.getResource(), new RemoteAnyPanel(bean, connObjects), target);
             }
         };
-
         if (!enableConnObjectLink) {
             connObjectLink.disable();
         }
-
         builder.addAction(connObjectLink, ActionLink.ActionType.VIEW, StandardEntitlement.RESOURCE_GET_CONNOBJECT);
 
+        builder.addAction(new ActionLink<StatusBean>() {
+
+            private static final long serialVersionUID = -3722207913631435501L;
+
+            @Override
+            protected boolean statusCondition(final StatusBean bean) {
+                return failureReasons.containsKey(bean.getResource());
+            }
+
+            @Override
+            public void onClick(final AjaxRequestTarget target, final StatusBean bean) {
+                mlp.next(bean.getResource(), new PropagationErrorPanel(failureReasons.get(bean.getResource())), target);
+            }
+        }, ActionLink.ActionType.PROPAGATION_TASKS, StringUtils.EMPTY);
+
         listViewPanel = ListViewPanel.class.cast(builder.build(MultilevelPanel.FIRST_LEVEL_ID));
         mlp.setFirstLevel(listViewPanel);
     }
@@ -185,39 +207,44 @@ public class StatusPanel extends Panel {
         return initialStatusBeanMap;
     }
 
-    protected Pair<ConnObjectTO, ConnObjectTO> getConnObjectTO(
-            final String anyKey, final String resourceName,
-            final List<Pair<ConnObjectTO, ConnObjectWrapper>> objects) {
+    protected Pair<ConnObjectTO, ConnObjectTO> getConnObjectTOs(
+            final String anyKey,
+            final String resource,
+            final List<Triple<ConnObjectTO, ConnObjectWrapper, String>> objects) {
 
-        for (Pair<ConnObjectTO, ConnObjectWrapper> object : objects) {
-            if (anyKey.equals(object.getRight().getAny().getKey())
-                    && resourceName.equalsIgnoreCase(object.getRight().getResourceName())) {
+        for (Triple<ConnObjectTO, ConnObjectWrapper, String> object : objects) {
+            if (anyKey.equals(object.getMiddle().getAny().getKey())
+                    && resource.equalsIgnoreCase(object.getMiddle().getResource())) {
 
-                return Pair.of(object.getLeft(), object.getRight().getConnObjectTO());
+                return Pair.of(object.getLeft(), object.getMiddle().getConnObjectTO());
             }
         }
 
         return null;
     }
 
-    public class RemoteAnyPanel extends RemoteObjectPanel {
+    class RemoteAnyPanel extends RemoteObjectPanel {
 
         private static final long serialVersionUID = 4303365227411467563L;
 
         private final StatusBean bean;
 
-        private final List<Pair<ConnObjectTO, ConnObjectWrapper>> connObjects;
+        private final List<Triple<ConnObjectTO, ConnObjectWrapper, String>> connObjects;
 
-        public RemoteAnyPanel(final StatusBean bean, final List<Pair<ConnObjectTO, ConnObjectWrapper>> connObjects) {
+        RemoteAnyPanel(final StatusBean bean, final List<Triple<ConnObjectTO, ConnObjectWrapper, String>> connObjects) {
             this.bean = bean;
             this.connObjects = connObjects;
 
-            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() {
-            return StatusPanel.this.getConnObjectTO(bean.getKey(), bean.getResource(), connObjects);
+        protected final Pair<ConnObjectTO, ConnObjectTO> getConnObjectTOs() {
+            return StatusPanel.this.getConnObjectTOs(bean.getKey(), bean.getResource(), connObjects);
         }
     }
 }
index 4db79bf..2a932af 100644 (file)
@@ -76,9 +76,9 @@ public class UserWizardBuilder extends AnyWizardBuilder<UserTO> implements UserF
     protected Serializable onApplyInternal(final AnyWrapper<UserTO> modelObject) {
         UserTO inner = modelObject.getInnerObject();
 
-        ProvisioningResult<UserTO> actual;
+        ProvisioningResult<UserTO> result;
         if (inner.getKey() == null) {
-            actual = userRestClient.create(inner, modelObject instanceof UserWrapper
+            result = userRestClient.create(inner, modelObject instanceof UserWrapper
                     ? UserWrapper.class.cast(modelObject).isStorePasswordInSyncope()
                     : StringUtils.isNotBlank(inner.getPassword()));
         } else {
@@ -92,14 +92,14 @@ public class UserWizardBuilder extends AnyWizardBuilder<UserTO> implements UserF
 
             // 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);
+                result = userRestClient.update(getOriginalItem().getInnerObject().getETagValue(), patch);
             }
         }
 
-        return actual;
+        return result;
     }
 
     @Override
index 1d093bc..41b2c46 100644 (file)
@@ -73,3 +73,5 @@ implementations=Implementations
 
 timeout=Operation is taking to long: it will be executed in background. Please check later for the result (errors won't be triggered).
 security=Security
+before=Before
+after=After
index a4514ff..bb0b3af 100644 (file)
@@ -73,3 +73,5 @@ implementations=Implementazioni
 
 timeout=L'operazione sta durando troppo: sar\u00e0 eseguita in background. Verifica il risultato pi\u00f9 tardi (gli errori non saranno notificati).
 security=Sicurezza
+before=Prima
+after=Dopo
index c512754..dda9afc 100644 (file)
@@ -71,3 +71,5 @@ confirmGlobalLogout=\u30b0\u30ed\u30fc\u30d0\u30eb\u30ed\u30b0\u30a2\u30a6\u30c8
 implementations=\u5c0e\u5165
 timeout=\u64cd\u4f5c\u306b\u9577\u6642\u9593\u304b\u304b\u3063\u3066\u3044\u307e\u3059\: \u30d0\u30c3\u30af\u30b0\u30e9\u30a6\u30f3\u30c9\u3067\u5b9f\u884c\u3055\u308c\u307e\u3059\u3002 \u7d50\u679c\u3092\u5f8c\u3067\u78ba\u8a8d\u3057\u3066\u304f\u3060\u3055\u3044 (\u30a8\u30e9\u30fc\u306f\u5f15\u304d\u8d77\u3053\u3057\u307e\u305b\u3093)\u3002
 security=Security
+before=Before
+after=After
index 0e0ecbf..c603b39 100644 (file)
@@ -72,3 +72,5 @@ implementations=\u0420\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438
 
 timeout=Operation is taking to long: it will be executed in background. Please check later for the result (errors won't be triggered).
 security=Security
+before=Before
+after=After
index a9cd88e..dda032e 100644 (file)
@@ -17,10 +17,7 @@ specific language governing permissions and limitations
 under the License.
 -->
 <html xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org">
-  <head><title></title></head>
-  <body>
-    <wicket:extend>
-      <span wicket:id="content"/>
-    </wicket:extend>
-  </body>
+  <wicket:extend>
+    <span wicket:id="content"/>
+  </wicket:extend>
 </html>
index 4adf9d7..5cebcb5 100644 (file)
@@ -17,21 +17,18 @@ specific language governing permissions and limitations
 under the License.
 -->
 <html xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org">
-  <head><title></title></head>
-  <body>
-    <wicket:head>
-      <link rel="stylesheet" type="text/css" href="css/bulk.css" media="all"/>
-    </wicket:head>
-    <wicket:panel>
-      <div wicket:id="container" id="selectedObjects" class="table-responsive dataTable">
-        <table class="ui-widget ui-widget-content table-hover pageRowElement" wicket:id="selectedObjects">[DataTable]</table>
+  <wicket:head>
+    <link rel="stylesheet" type="text/css" href="css/bulk.css" media="all"/>
+  </wicket:head>
+  <wicket:panel>
+    <div wicket:id="container" id="selectedObjects" class="table-responsive dataTable">
+      <table class="ui-widget ui-widget-content table-hover pageRowElement" wicket:id="selectedObjects">[DataTable]</table>
 
-        <div class="circular-actions">
-          <div id="inline-actions">
-            <span wicket:id="actions">[Actions]</span>
-          </div>
+      <div class="circular-actions">
+        <div id="inline-actions">
+          <span wicket:id="actions">[Actions]</span>
         </div>
       </div>
-    </wicket:panel>
-  </body>
+    </div>
+  </wicket:panel>
 </html>
index ac755e8..f74731a 100644 (file)
@@ -17,7 +17,6 @@ specific language governing permissions and limitations
 under the License.
 -->
 <html xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org">
-  <head><title></title></head>
   <wicket:panel>
     <span wicket:id="tasks">[TASKS]</span>
   </wicket:panel>
index c1cbc27..4b5ef37 100644 (file)
@@ -17,12 +17,9 @@ specific language governing permissions and limitations
 under the License.
 -->
 <html xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org">
-  <head><title></title></head>
-  <body>
-    <wicket:panel>
-      <div wicket:id="about" class="form-group">
-        <span wicket:id="abouts">[abouts]</span>
-      </div>
-    </wicket:panel>
-  </body>
+  <wicket:panel>
+    <div wicket:id="about" class="form-group">
+      <span wicket:id="abouts">[abouts]</span>
+    </div>
+  </wicket:panel>
 </html>
index d9844ab..1cbab58 100644 (file)
@@ -17,24 +17,21 @@ specific language governing permissions and limitations
 under the License.
 -->
 <html xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org">
-  <head><title></title></head>
-  <body>
-    <wicket:panel>
-      <div class="form-group">
-        <span wicket:id="isActive">[isActive]</span>
-      </div>
-      <div class="form-group">
-        <span wicket:id="sender">[sender]</span>
-      </div>
-      <div class="form-group">
-        <span wicket:id="subject">[subject]</span>
-      </div>
-      <div class="form-group">
-        <span wicket:id="template">[template]</span>
-      </div>
-      <div class="form-group">
-        <span wicket:id="traceLevel">[traceLevel]</span>
-      </div>
-    </wicket:panel>
-  </body>
+  <wicket:panel>
+    <div class="form-group">
+      <span wicket:id="isActive">[isActive]</span>
+    </div>
+    <div class="form-group">
+      <span wicket:id="sender">[sender]</span>
+    </div>
+    <div class="form-group">
+      <span wicket:id="subject">[subject]</span>
+    </div>
+    <div class="form-group">
+      <span wicket:id="template">[template]</span>
+    </div>
+    <div class="form-group">
+      <span wicket:id="traceLevel">[traceLevel]</span>
+    </div>
+  </wicket:panel>
 </html>
index c697099..0001cfd 100644 (file)
@@ -17,11 +17,8 @@ specific language governing permissions and limitations
 under the License.
 -->
 <html xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org">
-  <head><title></title></head>
-  <body>
-    <wicket:panel>
-      <span wicket:id="eventSelection"/>
-    </wicket:panel>
-  </body>
+  <wicket:panel>
+    <span wicket:id="eventSelection"/>
+  </wicket:panel>
 </html>
 
index 6c75dfb..f91de30 100644 (file)
@@ -17,7 +17,6 @@ specific language governing permissions and limitations
 under the License.
 -->
 <html xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org">
-  <head><title></title></head>
   <wicket:panel>
     <div wicket:id="firstLevelContainer">
       <span wicket:id="first">[FIRST]</span>
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/panels/PropagationErrorPanel.html b/client/console/src/main/resources/org/apache/syncope/client/console/panels/PropagationErrorPanel.html
new file mode 100644 (file)
index 0000000..777986d
--- /dev/null
@@ -0,0 +1,24 @@
+<!--
+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.
+-->
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org">
+  <wicket:panel>
+    <pre wicket:id="failureReason">
+    </pre>
+  </wicket:panel>
+</html>
index d0e5167..46fb7fd 100644 (file)
@@ -17,8 +17,7 @@ specific language governing permissions and limitations
 under the License.
 -->
 <html xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org">
-  <head><title></title></head>
   <wicket:panel>
-    <span wicket:id="remoteObject">[REMOTE OBJCET]</span>
+    <span wicket:id="remoteObject">[REMOTE OBJECT]</span>
   </wicket:panel>
 </html>
index 683fef7..0929615 100644 (file)
@@ -17,28 +17,25 @@ specific language governing permissions and limitations
 under the License.
 -->
 <html xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org">
-  <head><title></title></head>
-  <body>
-    <wicket:extend>
-      <wicket:enclosure child="field-label">
-        <label wicket:id="field-label">[LABEL]</label><span wicket:id="required"/>
-        <span wicket:id="externalAction"/>
-      </wicket:enclosure>
-      <span wicket:id="container"  class="clause">
-        <div wicket:id="operatorContainer" class="field operator"><span wicket:id="operator"/></div>
-        <span wicket:id="type" class="field type"/>
-        <span wicket:id="property" class="field property"/>
-        <span wicket:id="comparator" class="field comparator"/>
-        <span wicket:id="value" class="field value"/>
-      </span>
+  <wicket:extend>
+    <wicket:enclosure child="field-label">
+      <label wicket:id="field-label">[LABEL]</label><span wicket:id="required"/>
+      <span wicket:id="externalAction"/>
+    </wicket:enclosure>
+    <span wicket:id="container"  class="clause">
+      <div wicket:id="operatorContainer" class="field operator"><span wicket:id="operator"/></div>
+      <span wicket:id="type" class="field type"/>
+      <span wicket:id="property" class="field property"/>
+      <span wicket:id="comparator" class="field comparator"/>
+      <span wicket:id="value" class="field value"/>
+    </span>
 
-      <wicket:fragment wicket:id="searchButtonFragment">
-        <a href="#" wicket:id="search"><li class="glyphicon glyphicon-search"></li></a>
-      </wicket:fragment>
+    <wicket:fragment wicket:id="searchButtonFragment">
+      <a href="#" wicket:id="search"><li class="glyphicon glyphicon-search"></li></a>
+    </wicket:fragment>
 
-      <wicket:fragment wicket:id="operatorFragment">
-        <span wicket:id="operator"/>
-      </wicket:fragment>
-    </wicket:extend>
-  </body>
+    <wicket:fragment wicket:id="operatorFragment">
+      <span wicket:id="operator"/>
+    </wicket:fragment>
+  </wicket:extend>
 </html>
index 99e853e..dad9871 100644 (file)
@@ -17,10 +17,7 @@ specific language governing permissions and limitations
 under the License.
 -->
 <html xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org">
-  <head><title></title></head>
-  <body>
-    <wicket:panel>
-      <span wicket:id="schedule"/>
-    </wicket:panel>
-  </body>
+  <wicket:panel>
+    <span wicket:id="schedule"/>
+  </wicket:panel>
 </html>
index 7f18503..303ef4a 100644 (file)
@@ -16,8 +16,7 @@ KIND, either express or implied.  See the License for the
 specific language governing permissions and limitations
 under the License.
 -->
-<html xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org">
-  <head><title></title></head>
+<html xmlns="http://www.w3.org/1999/xhtml" >
   <wicket:extend>
   </wicket:extend>
 </html>
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/status/ReconTaskPanel.html b/client/console/src/main/resources/org/apache/syncope/client/console/status/ReconTaskPanel.html
new file mode 100644 (file)
index 0000000..c0c4891
--- /dev/null
@@ -0,0 +1,37 @@
+<!--
+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.
+-->
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org">
+  <wicket:panel>
+    <form wicket:id="form">
+      <div class="form-group form-palette">
+        <span wicket:id="actions">[actions]</span>
+      </div>
+      <div class="form-group"><span wicket:id="matchingRule">[matchingRule]</span></div>
+      <div class="form-group"><span wicket:id="unmatchingRule">[unmatchingRule]</span></div>
+      <div class="form-group"><span wicket:id="performCreate">[performCreate]</span></div>
+      <div class="form-group"><span wicket:id="performUpdate">[performUpdate]</span></div>
+      <div class="form-group"><span wicket:id="performDelete">[performDelete]</span></div>
+      <div class="form-group"><span wicket:id="syncStatus">[syncStatus]</span></div>
+
+      <div style="float: right;">
+        <a href="#" wicket:id="reconcile" class="btn btn-primary btn-circle btn-lg"><i class="fa fa-recycle" alt="reconcile" title="Reconcile"></i></a>
+      </div>
+    </form>
+  </wicket:panel>
+</html>
index 892ec31..839fce0 100644 (file)
@@ -66,8 +66,8 @@ under the License.
         <wicket:enclosure child="push">
           <li><a href="#" wicket:id="push"><i class="fa fa-chevron-circle-right"></i><wicket:message key="resource.menu.push.list"/></a></li>
         </wicket:enclosure>
-        <wicket:enclosure child="status">
-          <li><a href="#" wicket:id="status"><i class="fa fa-list-ul"></i><wicket:message key="resource.menu.provisioning.status"/></a></li>
+        <wicket:enclosure child="reconciliation">
+          <li><a href="#" wicket:id="reconciliation"><i class="fa fa-recycle"></i><wicket:message key="resource.menu.reconciliation"/></a></li>
         </wicket:enclosure>
         <wicket:enclosure child="history">
           <li><a href="#" wicket:id="history"><i class="fa fa-history"></i><wicket:message key="resource.menu.history"/></a></li>
index 60e4c18..a20f7cb 100644 (file)
@@ -37,8 +37,8 @@ task.pull.list=Pull tasks {0}
 task.push.list=Push tasks {0}
 resource.explore.list=Explore ${key}
 connectors.reload=Reload all connectors
-resource.provisioning.status=Provisioning Status {0}
-resource.menu.provisioning.status=Provisioning status
+resource.reconciliation=Reconciliation {0}
+resource.menu.reconciliation=Reconciliation
 resource.menu.push.list=Push tasks
 resource.menu.pull.list=Pull tasks
 resource.menu.propagation.list=Propagation tasks
index dd16d75..7a67919 100644 (file)
@@ -37,8 +37,8 @@ task.pull.list=Pull task {0}
 task.push.list=Push task {0}
 resource.explore.list=Esplora ${key}
 connectors.reload=Ricarica tutti i connettori
-resource.provisioning.status=Stato provisioning {0}
-resource.menu.provisioning.status=Stato provisioning
+resource.reconciliation=Riconciliazione {0}
+resource.menu.reconciliation=Riconciliazione
 resource.menu.push.list=Push tasks
 resource.menu.pull.list=Pull tasks
 resource.menu.propagation.list=Task di propagazione
index aef451c..9bff0a5 100644 (file)
@@ -37,8 +37,8 @@ task.pull.list=\u30d7\u30eb\u30bf\u30b9\u30af {0}
 task.push.list=\u30d7\u30c3\u30b7\u30e5\u30bf\u30b9\u30af {0}
 resource.explore.list=${key} \u3092\u63a2\u7d22
 connectors.reload=\u3059\u3079\u3066\u306e\u30b3\u30cd\u30af\u30bf\u30fc\u3092\u518d\u8aad\u307f\u8fbc\u307f
-resource.provisioning.status=\u30d7\u30ed\u30d3\u30b8\u30e7\u30cb\u30f3\u30b0\u30b9\u30c6\u30fc\u30bf\u30b9 {0}
-resource.menu.provisioning.status=\u30d7\u30ed\u30d3\u30b8\u30e7\u30cb\u30f3\u30b0\u30b9\u30c6\u30fc\u30bf\u30b9
+resource.reconciliation=Reconciliation {0}
+resource.menu.reconciliation=Reconciliation
 resource.menu.push.list=\u30d7\u30c3\u30b7\u30e5\u30bf\u30b9\u30af
 resource.menu.pull.list=\u30d7\u30eb\u30bf\u30b9\u30af
 resource.menu.propagation.list=\u4f1d\u64ad\u30bf\u30b9\u30af
index ce3fa05..47d851f 100644 (file)
@@ -37,8 +37,8 @@ task.pull.list=Pull tasks {0}
 task.push.list=Push tasks {0}
 resource.explore.list=Explorar ${key}
 connectors.reload=Reload all connectors
-resource.provisioning.status=Provisioning status {0}
-resource.menu.provisioning.status=Provisioning status
+resource.reconciliation=Reconciliation {0}
+resource.menu.reconciliation=Reconciliation
 resource.menu.push.list=Push tasks
 resource.menu.pull.list=Pull tasks
 resource.menu.propagation.list=Propagation tasks
index 07b3b09..5879fe2 100644 (file)
@@ -38,8 +38,8 @@ task.pull.list=\u0417\u0430\u0434\u0430\u0447\u0438 \u043f\u043e\u043b\u0443\u04
 task.push.list=\u0417\u0430\u0434\u0430\u0447\u0438 \u043f\u0435\u0440\u0435\u0434\u0430\u0447\u0438 \u0434\u0430\u043d\u043d\u044b\u0445 {0}
 resource.explore.list=\u041f\u0440\u043e\u0441\u043c\u043e\u0442\u0440 ${key}
 connectors.reload=\u041f\u0435\u0440\u0435\u0437\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044c \u0432\u0441\u0435 \u043a\u043e\u043d\u043d\u0435\u043a\u0442\u043e\u0440\u044b
-resource.provisioning.status=\u0421\u0442\u0430\u0442\u0443\u0441 \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u044f {0}
-resource.menu.provisioning.status=\u0421\u0442\u0430\u0442\u0443\u0441 \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u044f
+resource.reconciliation=Reconciliation {0}
+resource.menu.reconciliation=Reconciliation
 resource.menu.push.list=\u0417\u0430\u0434\u0430\u0447\u0438 \u043f\u0435\u0440\u0435\u0434\u0430\u0447\u0438 \u0434\u0430\u043d\u043d\u044b\u0445
 resource.menu.pull.list=\u0417\u0430\u0434\u0430\u0447\u0438 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445
 resource.menu.propagation.list=\u0417\u0430\u0434\u0430\u0447\u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0439
index a0fe773..1086b88 100644 (file)
@@ -91,7 +91,7 @@ reset.title=reset
 reset.alt=reset icon
 
 enable.class=fa fa-toggle-on
-enable.title=enable
+enable.title=manage status
 enable.alt=enable icon
 
 not_found.class=fa fa-eye-slash
@@ -226,6 +226,14 @@ provision_members.class=glyphicon glyphicon-fast-forward
 provision_members.title=provision members
 provision_members.alt=provision members icon
 
+reconciliation_push.class=fa fa-chevron-circle-right
+reconciliation_push.title=push
+reconciliation_push.alt=reconciliation push icon
+
+reconciliation_pull.class=fa fa-chevron-circle-left
+reconciliation_pull.title=pull
+reconciliation_pull.alt=reconciliation pull icon
+
 manage_resources.class=fa fa-sitemap
 manage_resources.title=manage resources
 manage_resources.alt=manage resources icon
index e3903e1..5538d75 100644 (file)
@@ -91,7 +91,7 @@ reset.title=reset
 reset.alt=reset icon
 
 enable.class=fa fa-toggle-on
-enable.title=enable
+enable.title=manage status
 enable.alt=enable icon
 
 not_found.class=fa fa-eye-slash
@@ -256,3 +256,9 @@ zoom_out.alt=zoom-out icon
 workflow_modeler.class=fa fa-picture-o
 workflow_modeler.title=workflow modeler
 workflow_modeler.alt=workflow modeler icon
+reconciliation_push.class=fa fa-chevron-circle-right
+reconciliation_push.title=push
+reconciliation_push.alt=reconciliation push icon
+reconciliation_pull.class=fa fa-chevron-circle-left
+reconciliation_pull.title=pull
+reconciliation_pull.alt=reconciliation pull icon
index 2ef2c19..6789a9b 100644 (file)
@@ -91,7 +91,7 @@ reset.title=\u30ea\u30bb\u30c3\u30c8
 reset.alt=\u30ea\u30bb\u30c3\u30c8
 
 enable.class=fa fa-toggle-on
-enable.title=\u6709\u52b9
+enable.title=manage status
 enable.alt=\u6709\u52b9
 
 not_found.class=fa fa-eye-slash
@@ -257,3 +257,9 @@ zoom_out.alt=\u30ba\u30fc\u30e0\u30a2\u30a6\u30c8
 workflow_modeler.class=fa fa-picture-o
 workflow_modeler.title=\u30ef\u30fc\u30af\u30d5\u30ed\u30fc\u30e2\u30c7\u30e9\u2015
 workflow_modeler.alt=\u30ef\u30fc\u30af\u30d5\u30ed\u30fc\u30e2\u30c7\u30e9\u2015
+reconciliation_push.class=fa fa-chevron-circle-right
+reconciliation_push.title=push
+reconciliation_push.alt=reconciliation push icon
+reconciliation_pull.class=fa fa-chevron-circle-left
+reconciliation_pull.title=pull
+reconciliation_pull.alt=reconciliation pull icon
index 07acbc3..c996263 100644 (file)
@@ -91,7 +91,7 @@ reset.title=reset
 reset.alt=reset icon
 
 enable.class=fa fa-toggle-on
-enable.title=enable
+enable.title=manage status
 enable.alt=enable icon
 
 not_found.class=fa fa-eye-slash
@@ -256,3 +256,9 @@ zoom_out.alt=zoom-out icon
 workflow_modeler.class=fa fa-picture-o
 workflow_modeler.title=workflow modeler
 workflow_modeler.alt=workflow modeler icon
+reconciliation_push.class=fa fa-chevron-circle-right
+reconciliation_push.title=push
+reconciliation_push.alt=reconciliation push icon
+reconciliation_pull.class=fa fa-chevron-circle-left
+reconciliation_pull.title=pull
+reconciliation_pull.alt=reconciliation pull icon
index db15243..d697f25 100644 (file)
@@ -91,7 +91,7 @@ reset.title=reset
 reset.alt=reset icon
 
 enable.class=fa fa-toggle-on
-enable.title=abilita
+enable.title=gestisci stato
 enable.alt=enable icon
 
 not_found.class=fa fa-eye-slash
@@ -256,3 +256,9 @@ zoom_out.alt=zoom-out icon
 workflow_modeler.class=fa fa-picture-o
 workflow_modeler.title=workflow modeler
 workflow_modeler.alt=workflow modeler icon
+reconciliation_push.class=fa fa-chevron-circle-right
+reconciliation_push.title=push
+reconciliation_push.alt=reconciliation push icon
+reconciliation_pull.class=fa fa-chevron-circle-left
+reconciliation_pull.title=pull
+reconciliation_pull.alt=reconciliation pull icon
index ad327c2..e5affd7 100644 (file)
@@ -75,7 +75,7 @@ reset.title=reset
 reset.alt=reset icon
 
 enable.class=fa fa-toggle-on
-enable.title=enable
+enable.title=manage status
 enable.alt=enable icon
 
 not_found.class=fa fa-eye-slash
@@ -198,6 +198,14 @@ provision_members.class=glyphicon glyphicon-fast-forward
 provision_members.title=provision members
 provision_members.alt=provision members icon
 
+reconciliation_push.class=fa fa-chevron-circle-right
+reconciliation_push.title=push
+reconciliation_push.alt=reconciliation push icon
+
+reconciliation_pull.class=fa fa-chevron-circle-left
+reconciliation_pull.title=pull
+reconciliation_pull.alt=reconciliation pull icon
+
 manage_resources.class=fa fa-sitemap
 manage_resources.title=manage resources
 manage_resources.alt=manage resources icon
index 5cf18df..d0dbb16 100644 (file)
@@ -75,7 +75,7 @@ reset.title=reset
 reset.alt=reset icon
 
 enable.class=fa fa-toggle-on
-enable.title=abilita
+enable.title=gestisci stato
 enable.alt=enable icon
 
 not_found.class=fa fa-eye-slash
@@ -225,3 +225,9 @@ zoom_in.alt=zoom-in icon
 zoom_out.class=fa fa-search-minus
 zoom_out.title=rimpicciolisci
 zoom_out.alt=zoom-out icon
+reconciliation_push.class=fa fa-chevron-circle-right
+reconciliation_push.title=push
+reconciliation_push.alt=reconciliation push icon
+reconciliation_pull.class=fa-chevron-circle-left
+reconciliation_pull.title=pull
+reconciliation_pull.alt=reconciliation pull icon
index db63cdb..599edfa 100644 (file)
@@ -75,7 +75,7 @@ reset.title=\u30ea\u30bb\u30c3\u30c8
 reset.alt=\u30ea\u30bb\u30c3\u30c8
 
 enable.class=fa fa-toggle-on
-enable.title=\u6709\u52b9
+enable.title=manage status
 enable.alt=\u6709\u52b9
 
 not_found.class=fa fa-eye-slash
@@ -225,3 +225,9 @@ zoom_in.alt=\u30ba\u30fc\u30e0\u30a4\u30f3
 zoom_out.class=fa fa-search-minus
 zoom_out.title=\u30ba\u30fc\u30e0\u30a2\u30a6\u30c8
 zoom_out.alt=\u30ba\u30fc\u30e0\u30a2\u30a6\u30c8
+reconciliation_push.class=fa fa-chevron-circle-right
+reconciliation_push.title=push
+reconciliation_push.alt=reconciliation push icon
+reconciliation_pull.class=fa-chevron-circle-left
+reconciliation_pull.title=pull
+reconciliation_pull.alt=reconciliation pull icon
index b8afd75..4aedf76 100644 (file)
@@ -75,7 +75,7 @@ reset.title=reset
 reset.alt=reset icon
 
 enable.class=fa fa-toggle-on
-enable.title=enable
+enable.title=manage status
 enable.alt=enable icon
 
 not_found.class=fa fa-eye-slash
@@ -225,3 +225,9 @@ zoom_in.alt=zoom-in icon
 zoom_out.class=fa fa-search-minus
 zoom_out.title=zoom-out
 zoom_out.alt=zoom-out icon
+reconciliation_push.class=fa fa-chevron-circle-right
+reconciliation_push.title=push
+reconciliation_push.alt=reconciliation push icon
+reconciliation_pull.class=fa-chevron-circle-left
+reconciliation_pull.title=pull
+reconciliation_pull.alt=reconciliation pull icon
index ad327c2..e7fc2d3 100644 (file)
@@ -75,7 +75,7 @@ reset.title=reset
 reset.alt=reset icon
 
 enable.class=fa fa-toggle-on
-enable.title=enable
+enable.title=manage status
 enable.alt=enable icon
 
 not_found.class=fa fa-eye-slash
@@ -225,3 +225,9 @@ zoom_in.alt=zoom-in icon
 zoom_out.class=fa fa-search-minus
 zoom_out.title=zoom-out
 zoom_out.alt=zoom-out icon
+reconciliation_push.class=fa fa-chevron-circle-right
+reconciliation_push.title=push
+reconciliation_push.alt=reconciliation push icon
+reconciliation_pull.class=fa-chevron-circle-left
+reconciliation_pull.title=pull
+reconciliation_pull.alt=reconciliation pull icon
index 0767e59..249ac51 100644 (file)
@@ -16,11 +16,8 @@ KIND, either express or implied.  See the License for the
 specific language governing permissions and limitations
 under the License.
 -->
-<html xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org">
-  <head><title></title></head>
-  <body>
-    <wicket:panel>
-      <wicket:child />
-    </wicket:panel>
-  </body>
+<html xmlns="http://www.w3.org/1999/xhtml" >
+  <wicket:panel>
+    <wicket:child/>
+  </wicket:panel>
 </html>
index 51f5a3e..3b891b0 100644 (file)
@@ -17,10 +17,7 @@ specific language governing permissions and limitations
 under the License.
 -->
 <html xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org">
-  <head><title></title></head>
-  <body>
-    <wicket:extend>
-      <div><img wicket:id = "previewImage"/></div>
-    </wicket:extend>
-  </body>
+  <wicket:extend>
+    <div><img wicket:id = "previewImage"/></div>
+  </wicket:extend>
 </html>
index 6b4cee1..b9a1f19 100644 (file)
@@ -17,21 +17,17 @@ specific language governing permissions and limitations
 under the License.
 -->
 <html xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org">
-  <head><title></title></head>
-  <body>
-    <wicket:extend>
-      <div wicket:id="previewContainer">
-        <span wicket:id="preview"/>
-      </div>
+  <wicket:extend>
+    <div wicket:id="previewContainer">
+      <span wicket:id="preview"/>
+    </div>
 
-      <wicket:fragment wicket:id="previewFragment">
-        <div><img wicket:id = "previewImage"/></div>
-      </wicket:fragment>
-      <wicket:fragment wicket:id="noPreviewFragment">
-        <div style="padding: 8px 0px 1px 10px">
-          <i class=" glyphicon glyphicon-paperclip fa-2x" title="Preview not available" alt="Default preview icon"></i>
-        </div>
-      </wicket:fragment>
-    </wicket:extend>
-  </body>
+    <wicket:fragment wicket:id="previewFragment">
+      <div><img wicket:id = "previewImage"/></div>
+    </wicket:fragment>
+    <wicket:fragment wicket:id="noPreviewFragment">
+      <div style="padding: 8px 0px 1px 10px">
+        <i class=" glyphicon glyphicon-paperclip fa-2x" title="Preview not available" alt="Default preview icon"></i>
+      </div>
+    </wicket:fragment>
 </html>
index c96fd4b..7471fed 100644 (file)
@@ -16,13 +16,10 @@ KIND, either express or implied.  See the License for the
 specific language governing permissions and limitations
 under the License.
 -->
-<html xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org">
-  <head><title></title></head>
-  <body>
-    <wicket:extend>
-      <div style="padding: 8px 0px 1px 10px">
-        <i class=" glyphicon glyphicon-paperclip fa-2x" title="Preview not available" alt="Default preview icon"></i>
-      </div>
-    </wicket:extend>
-  </body>
+<html xmlns="http://www.w3.org/1999/xhtml" >
+  <wicket:extend>
+    <div style="padding: 8px 0px 1px 10px">
+      <i class=" glyphicon glyphicon-paperclip fa-2x" title="Preview not available" alt="Default preview icon"></i>
+    </div>
+  </wicket:extend>
 </html>
index 57339dd..6df2828 100644 (file)
@@ -17,80 +17,77 @@ specific language governing permissions and limitations
 under the License.
 -->
 <html xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org">
-  <head><title></title></head>
-  <body>
-    <wicket:panel>
-      <div class="table-responsive no-padding">
-        <table id="mappings"
-               class="table table-hover"
-               style="font-size: 1em;margin-top:2px;"
-               wicket:id="mappingContainer">
-          <tbody>
-            <tr>
-              <th>
-                <wicket:message key="intAttrName"/>
-                <span id="intAttrNameInfo" wicket:id="intAttrNameInfo" class="glyphicon glyphicon-info-sign"></span>
-              </th>
-              <th><wicket:message key="extAttrName"/></th>
-              <th><i class="fa fa-repeat"></i></th>
-              <th><i class="fa fa-magic"></i></th>
-              <th>
-                <wicket:message key="mandatoryCondition"/>
-                <span id="jexlInfo" wicket:id="jexlInfo" class="glyphicon glyphicon-info-sign"></span>
-              </th>
-              <th><wicket:message key="connObjectKey"/></th>
-              <th><label wicket:id="passwordLabel"/></th>
-              <th><label wicket:id="purposeLabel"/></th>
-              <th></th>
-            </tr>
-            <tr wicket:id="mappings">
-              <td>
-                <span wicket:id="intAttrName">[intAttrNames]</span>
-              </td>
-              <td>
-                <span wicket:id="extAttrName">[extAttrName]</span>
-              </td>
-              <td>
-                <div class="alert-widget dropdown tasks-menu">
-                  <span wicket:id="jexlTransformers">[JEXL Transformers]</span>
-                </div>
-              </td>
-              <td>
-                <div class="alert-widget dropdown tasks-menu">
-                  <span wicket:id="itemTransformers">[Mapping Item Transformers]</span>
-                </div>
-              </td>
-              <td>
-                <span wicket:id="mandatoryCondition">[mandatoryCondition]</span>
-              </td>
-              <td>
-                <span wicket:id="connObjectKey">[connObjectKey]</span>
-              </td>
-              <td>
-                <span wicket:id="password">[password]</span>
-              </td>
-              <td>
-                <div wicket:id="purpose" style="margin: 10px 0px 10px 0px">
-                  <span wicket:id="purposeActions">[purpose]</span>
-                </div>
-              </td>
-              <td>
-                <div id="inline-actions">
-                  <span  wicket:id="toRemove"/>
-                </div>
-              </td>
-            </tr>
-          </tbody>
+  <wicket:panel>
+    <div class="table-responsive no-padding">
+      <table id="mappings"
+             class="table table-hover"
+             style="font-size: 1em;margin-top:2px;"
+             wicket:id="mappingContainer">
+        <tbody>
+          <tr>
+            <th>
+              <wicket:message key="intAttrName"/>
+              <span id="intAttrNameInfo" wicket:id="intAttrNameInfo" class="glyphicon glyphicon-info-sign"></span>
+            </th>
+            <th><wicket:message key="extAttrName"/></th>
+            <th><i class="fa fa-repeat"></i></th>
+            <th><i class="fa fa-magic"></i></th>
+            <th>
+              <wicket:message key="mandatoryCondition"/>
+              <span id="jexlInfo" wicket:id="jexlInfo" class="glyphicon glyphicon-info-sign"></span>
+            </th>
+            <th><wicket:message key="connObjectKey"/></th>
+            <th><label wicket:id="passwordLabel"/></th>
+            <th><label wicket:id="purposeLabel"/></th>
+            <th></th>
+          </tr>
+          <tr wicket:id="mappings">
+            <td>
+              <span wicket:id="intAttrName">[intAttrNames]</span>
+            </td>
+            <td>
+              <span wicket:id="extAttrName">[extAttrName]</span>
+            </td>
+            <td>
+              <div class="alert-widget dropdown tasks-menu">
+                <span wicket:id="jexlTransformers">[JEXL Transformers]</span>
+              </div>
+            </td>
+            <td>
+              <div class="alert-widget dropdown tasks-menu">
+                <span wicket:id="itemTransformers">[Mapping Item Transformers]</span>
+              </div>
+            </td>
+            <td>
+              <span wicket:id="mandatoryCondition">[mandatoryCondition]</span>
+            </td>
+            <td>
+              <span wicket:id="connObjectKey">[connObjectKey]</span>
+            </td>
+            <td>
+              <span wicket:id="password">[password]</span>
+            </td>
+            <td>
+              <div wicket:id="purpose" style="margin: 10px 0px 10px 0px">
+                <span wicket:id="purposeActions">[purpose]</span>
+              </div>
+            </td>
+            <td>
+              <div id="inline-actions">
+                <span  wicket:id="toRemove"/>
+              </div>
+            </td>
+          </tr>
+        </tbody>
 
-          <tfoot>
-            <tr>
-              <td colspan="10" style="padding: 5px; text-align: right">
-                <input type="submit" class="btn btn-primary" wicket:id="addMappingBtn" />
-              </td>
-            </tr>
-          </tfoot>
-        </table>
-      </div>
-    </wicket:panel>
-  </body>
+        <tfoot>
+          <tr>
+            <td colspan="10" style="padding: 5px; text-align: right">
+              <input type="submit" class="btn btn-primary" wicket:id="addMappingBtn" />
+            </td>
+          </tr>
+        </tfoot>
+      </table>
+    </div>
+  </wicket:panel>
 </html>
index 02bbeb7..c2ae2b8 100644 (file)
@@ -17,48 +17,45 @@ specific language governing permissions and limitations
 under the License.
 -->
 <html xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org">
-  <head><title></title></head>
-  <body>
-    <wicket:panel>
-      <div class="information">
-        <div class="infoleft">
-          <div class="infolabel"> 
-            <wicket:message key="creationDate"/>:
-          </div>
-          <div>
-            <span wicket:id="creationDate" />
-          </div>
+  <wicket:panel>
+    <div class="information">
+      <div class="infoleft">
+        <div class="infolabel"> 
+          <wicket:message key="creationDate"/>:
         </div>
-
-        <div class="inforight">
-          <div class="infolabel">
-            <wicket:message key="lastChangeDate"/>:
-          </div>
-          <div>
-            <span wicket:id="lastChangeDate" />
-          </div>
+        <div>
+          <span wicket:id="creationDate" />
         </div>
+      </div>
 
-        <div class="infoleft">
-          <div class="infolabel">
-            <wicket:message key="creator"/>:
-          </div>
-          <div>
-            <span wicket:id="creator" />
-          </div>
+      <div class="inforight">
+        <div class="infolabel">
+          <wicket:message key="lastChangeDate"/>:
+        </div>
+        <div>
+          <span wicket:id="lastChangeDate" />
         </div>
+      </div>
 
-        <div class="inforight">
-          <div class="infolabel">
-            <wicket:message key="lastModifier"/>:
-          </div>
-          <div>
-            <span wicket:id="lastModifier" />
-          </div>
+      <div class="infoleft">
+        <div class="infolabel">
+          <wicket:message key="creator"/>:
+        </div>
+        <div>
+          <span wicket:id="creator" />
         </div>
+      </div>
 
-        <wicket:child />
+      <div class="inforight">
+        <div class="infolabel">
+          <wicket:message key="lastModifier"/>:
+        </div>
+        <div>
+          <span wicket:id="lastModifier" />
+        </div>
       </div>
-    </wicket:panel>
-  </body>
+
+      <wicket:child />
+    </div>
+  </wicket:panel>
 </html>
index 18a4448..3b15ad7 100644 (file)
@@ -18,15 +18,17 @@ under the License.
 -->
 <html xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org">
   <wicket:panel>
-    <div class="form-group" wicket:id="propView">
-      <span wicket:id="value">[ATTIRIBUTE]</span>
+    <h4 class="left page-header" wicket:id="leftTitle">[TITLE]</h4>
+    <h4 class="right page-header" wicket:id="rightTitle">[TITLE]</h4>
+    <div class="form-group" wicket:id="propView" style="clear: both;">
+      <span wicket:id="value">[ATTRIBUTE]</span>
     </div>
     <wicket:fragment wicket:id="doubleValue">
       <div class="left attribute">
-        <span wicket:id="oldAttribute">[ATTIRIBUTE]</span>
+        <span wicket:id="leftAttribute">[ATTRIBUTE]</span>
       </div>
       <div class="right attribute">
-        <span wicket:id="newAttribute">[ATTIRIBUTE]</span>
+        <span wicket:id="rightAttribute">[ATTRIBUTE]</span>
       </div>
     </wicket:fragment>
   </wicket:panel>
index f9b03c8..a6773aa 100644 (file)
@@ -17,18 +17,15 @@ specific language governing permissions and limitations
 under the License.
 -->
 <html xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org">
-  <head><title></title></head>
-  <body>
-    <wicket:panel>
-      <div class="details">
-        <div class="form-group">
-          <span wicket:id="destinationRealm">[DESTINATION REALM]</span>
-        </div>
-        <wicket:child/>
+  <wicket:panel>
+    <div class="details">
+      <div class="form-group">
+        <span wicket:id="destinationRealm">[DESTINATION REALM]</span>
       </div>
-      <div class="details-footer">
-        <span wicket:id="generalStatusInformation">[GENERAL STATUS INFORMATION]</span>
-      </div>
-    </wicket:panel>
-  </body>
+      <wicket:child/>
+    </div>
+    <div class="details-footer">
+      <span wicket:id="generalStatusInformation">[GENERAL STATUS INFORMATION]</span>
+    </div>
+  </wicket:panel>
 </html>
index 12540fa..9e6f5f9 100644 (file)
@@ -17,13 +17,10 @@ specific language governing permissions and limitations
 under the License.
 -->
 <html xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org">
-  <head><title></title></head>
-  <body>
-    <wicket:panel>
-      <div wicket:id="uDynMembershipCond" />
-      <span wicket:id="aDynMembershipCond">
-        <div wicket:id="aDynMembershipCond"/>
-      </span>
-    </wicket:panel>
-  </body>
+  <wicket:panel>
+    <div wicket:id="uDynMembershipCond" />
+    <span wicket:id="aDynMembershipCond">
+      <div wicket:id="aDynMembershipCond"/>
+    </span>
+  </wicket:panel>
 </html>
index 1e1629b..11509f6 100644 (file)
@@ -17,38 +17,35 @@ specific language governing permissions and limitations
 under the License.
 -->
 <html xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org">
-  <head><title></title></head>
-  <body>
-    <wicket:panel>
-      <div id="ownership">
-        <span wicket:id="ownership">[OWNERSHIP]</span>
-      </div>
+  <wicket:panel>
+    <div id="ownership">
+      <span wicket:id="ownership">[OWNERSHIP]</span>
+    </div>
 
-      <div wicket:id="ownerContainer">
-        <span wicket:id="search">[SEARCH]</span>
-      </div>
+    <div wicket:id="ownerContainer">
+      <span wicket:id="search">[SEARCH]</span>
+    </div>
 
-      <wicket:fragment wicket:id="userSearchFragment">
-        <div class="form-group input-group">
-          <span wicket:id="userOwner"/>
-          <a href="#" wicket:id="userOwnerReset" class="input-group-addon"><i class="glyphicon glyphicon-remove-circle" alt="reset user owner" title="Reset"></i></a>
-        </div>
-        <span wicket:id="usersearch">[USER SEARCH]</span>
-        <div class="searchResult">
-          <span wicket:id="searchResult">[USER SEARCH RESULT]</span>
-        </div>
-      </wicket:fragment>
+    <wicket:fragment wicket:id="userSearchFragment">
+      <div class="form-group input-group">
+        <span wicket:id="userOwner"/>
+        <a href="#" wicket:id="userOwnerReset" class="input-group-addon"><i class="glyphicon glyphicon-remove-circle" alt="reset user owner" title="Reset"></i></a>
+      </div>
+      <span wicket:id="usersearch">[USER SEARCH]</span>
+      <div class="searchResult">
+        <span wicket:id="searchResult">[USER SEARCH RESULT]</span>
+      </div>
+    </wicket:fragment>
 
-      <wicket:fragment wicket:id="groupSearchFragment">
-        <div class="form-group input-group">
-          <span wicket:id="groupOwner"/>
-          <a href="#" wicket:id="groupOwnerReset" class="input-group-addon"><i class="glyphicon glyphicon-remove-circle" alt="reset group owner" title="Reset"></i></a>
-        </div>
-        <span wicket:id="groupsearch">[GROUP SEARCH]</span>
-        <div class="searchResult">
-          <span wicket:id="searchResult">[GROUP SEARCH RESULT]</span>
-        </div>
-      </wicket:fragment>
-    </wicket:panel>
-  </body>
+    <wicket:fragment wicket:id="groupSearchFragment">
+      <div class="form-group input-group">
+        <span wicket:id="groupOwner"/>
+        <a href="#" wicket:id="groupOwnerReset" class="input-group-addon"><i class="glyphicon glyphicon-remove-circle" alt="reset group owner" title="Reset"></i></a>
+      </div>
+      <span wicket:id="groupsearch">[GROUP SEARCH]</span>
+      <div class="searchResult">
+        <span wicket:id="searchResult">[GROUP SEARCH RESULT]</span>
+      </div>
+    </wicket:fragment>
+  </wicket:panel>
 </html>
index 83ab31d..c58eb6f 100644 (file)
@@ -17,28 +17,25 @@ specific language governing permissions and limitations
 under the License.
 -->
 <html xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org">
-  <head><title></title></head>
-  <body>
-    <wicket:panel>
-      <div class="form-group">
-        <span wicket:id="type" />
-      </div>
+  <wicket:panel>
+    <div class="form-group">
+      <span wicket:id="type" />
+    </div>
 
-      <div class="form-group">
-        <span wicket:id="otherType"/>
-      </div>
+    <div class="form-group">
+      <span wicket:id="otherType"/>
+    </div>
 
-      <div wicket:id="searchPanelContainer">
-        <span wicket:id="searchPanel"/>
-      </div>
+    <div wicket:id="searchPanelContainer">
+      <span wicket:id="searchPanel"/>
+    </div>
 
-      <wicket:fragment wicket:id="emptyFragment"/>
-      <wicket:fragment wicket:id="searchFragment">
-        <span wicket:id="searchPanel"/>
-        <div class="searchResult">
-          <span wicket:id="searchResultPanel"/>
-        </div>
-      </wicket:fragment>
-    </wicket:panel>
-  </body>
+    <wicket:fragment wicket:id="emptyFragment"/>
+    <wicket:fragment wicket:id="searchFragment">
+      <span wicket:id="searchPanel"/>
+      <div class="searchResult">
+        <span wicket:id="searchResultPanel"/>
+      </div>
+    </wicket:fragment>
+  </wicket:panel>
 </html>
index bfa6f45..992c3af 100644 (file)
@@ -17,25 +17,22 @@ specific language governing permissions and limitations
 under the License.
 -->
 <html xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org">
-  <head><title></title></head>
-  <body>
-    <wicket:panel>
-      <div class="wizard-step-title">
-        <div><span wicket:id="title">[RELATIONSHIPS]</span></div><span wicket:id="changed"></span>
-      </div>
+  <wicket:panel>
+    <div class="wizard-step-title">
+      <div><span wicket:id="title">[RELATIONSHIPS]</span></div><span wicket:id="changed"></span>
+    </div>
 
-      <div id="emptyPlaceholder"/>
-      <span wicket:id="relationships"/>
+    <div id="emptyPlaceholder"/>
+    <span wicket:id="relationships"/>
 
-      <wicket:fragment wicket:id="viewFragment">
-        <div wicket:id="relationships"/>
-        <div id="inline-actions" class="modal-footer">
-          <span wicket:id="actions" class="circular-actions">[ACTIONS]</span>
-        </div>
-      </wicket:fragment>
-      <wicket:fragment wicket:id="addFragment">
-        <span wicket:id="specification" />
-      </wicket:fragment>
-    </wicket:panel>
-  </body>
+    <wicket:fragment wicket:id="viewFragment">
+      <div wicket:id="relationships"/>
+      <div id="inline-actions" class="modal-footer">
+        <span wicket:id="actions" class="circular-actions">[ACTIONS]</span>
+      </div>
+    </wicket:fragment>
+    <wicket:fragment wicket:id="addFragment">
+      <span wicket:id="specification" />
+    </wicket:fragment>
+  </wicket:panel>
 </html>
index 54219d1..10f17f7 100644 (file)
@@ -17,22 +17,19 @@ specific language governing permissions and limitations
 under the License.
 -->
 <html xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org">
-  <head><title></title></head>
-  <body>
-    <wicket:panel>
-      <div class="col-xs-12">
-        <div class="box">
-          <div class="box-header">
-            <h3 class="box-title">
-              <wicket:message key="resources.palette">[ROLES]</wicket:message>
-            </h3>
-            <span wicket:id="changed"></span>
-          </div>
-          <div class="box-body">
-            <span wicket:id="resources">[RESOURCES]</span>
-          </div>
+  <wicket:panel>
+    <div class="col-xs-12">
+      <div class="box">
+        <div class="box-header">
+          <h3 class="box-title">
+            <wicket:message key="resources.palette">[ROLES]</wicket:message>
+          </h3>
+          <span wicket:id="changed"></span>
+        </div>
+        <div class="box-body">
+          <span wicket:id="resources">[RESOURCES]</span>
         </div>
       </div>
-    </wicket:panel>
-  </body>
+    </div>
+  </wicket:panel>
 </html>
\ No newline at end of file
index cf43602..bca1667 100644 (file)
@@ -17,13 +17,10 @@ specific language governing permissions and limitations
 under the License.
 -->
 <html xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org">
-  <head><title></title></head>
-  <body>
-    <wicket:panel>
-      <span wicket:id="customResultBody"/>
-      <div id="inline-actions" class="modal-footer circular-actions">
-        <span wicket:id="action"/>
-      </div>
-    </wicket:panel>
-  </body>
+  <wicket:panel>
+    <span wicket:id="customResultBody"/>
+    <div id="inline-actions" class="modal-footer circular-actions">
+      <span wicket:id="action"/>
+    </div>
+  </wicket:panel>
 </html>
index f7eded7..5243059 100644 (file)
@@ -17,35 +17,32 @@ specific language governing permissions and limitations
 under the License.
 -->
 <html xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org">
-  <head><title></title></head>
-  <body>
-    <wicket:panel>
-      <div class="col-xs-12">
-        <div class="box">
-          <div class="box-header">
-            <h3 class="box-title">
-              <wicket:message key="roles.palette">[ROLES]</wicket:message>
-            </h3>
-            <span wicket:id="changed"></span>
-          </div>
-          <div class="box-body">
-            <span wicket:id="roles">[ROLES]</span>
-          </div>
+  <wicket:panel>
+    <div class="col-xs-12">
+      <div class="box">
+        <div class="box-header">
+          <h3 class="box-title">
+            <wicket:message key="roles.palette">[ROLES]</wicket:message>
+          </h3>
+          <span wicket:id="changed"></span>
+        </div>
+        <div class="box-body">
+          <span wicket:id="roles">[ROLES]</span>
         </div>
       </div>
+    </div>
 
-      <div class="col-xs-12">
-        <div class="box">
-          <div class="box-header">
-            <h3 class="box-title">
-              <wicket:message key="dynroles.palette">[ROLES]</wicket:message>
-            </h3>
-          </div>
-          <div class="box-body">
-            <span wicket:id="dynroles">[ROLES]</span>
-          </div>
+    <div class="col-xs-12">
+      <div class="box">
+        <div class="box-header">
+          <h3 class="box-title">
+            <wicket:message key="dynroles.palette">[ROLES]</wicket:message>
+          </h3>
+        </div>
+        <div class="box-body">
+          <span wicket:id="dynroles">[ROLES]</span>
         </div>
       </div>
-    </wicket:panel>
-  </body>
+    </div>
+  </wicket:panel>
 </html>
\ No newline at end of file
index a411f3f..de9b10d 100644 (file)
@@ -17,7 +17,6 @@ specific language governing permissions and limitations
 under the License.
 -->
 <html xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org">
-  <head><title></title></head>
   <wicket:panel>
     <span wicket:id="resources">[RESOURCES]</span>
   </wicket:panel>
index 0b10b23..aa47866 100644 (file)
@@ -17,53 +17,50 @@ specific language governing permissions and limitations
 under the License.
 -->
 <html xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org">
-  <head><title></title></head>
-  <body>
-    <wicket:extend>
-      <div class="infoleft">
-        <div class="infolabel">
-          <wicket:message key="lastLoginDate"/>:
-        </div>
-        <div>
-          <span wicket:id="lastLoginDate"/>
-        </div>
+  <wicket:extend>
+    <div class="infoleft">
+      <div class="infolabel">
+        <wicket:message key="lastLoginDate"/>:
       </div>
+      <div>
+        <span wicket:id="lastLoginDate"/>
+      </div>
+    </div>
 
-      <div class="inforight">
-        <div class="infolabel">
-          <wicket:message key="failedLogins"/>:
-        </div>
-        <div>
-          <span wicket:id="failedLogins"/>
-        </div>
+    <div class="inforight">
+      <div class="infolabel">
+        <wicket:message key="failedLogins"/>:
+      </div>
+      <div>
+        <span wicket:id="failedLogins"/>
       </div>
+    </div>
 
-      <div class="infoleft">
-        <div class="infolabel">
-          <wicket:message key="changePwdDate"/>:
-        </div>
-        <div>
-          <span wicket:id="changePwdDate"/>
-        </div>
+    <div class="infoleft">
+      <div class="infolabel">
+        <wicket:message key="changePwdDate"/>:
+      </div>
+      <div>
+        <span wicket:id="changePwdDate"/>
       </div>
+    </div>
 
-      <div class="inforight">
-        <div class="infolabel">
-          <wicket:message key="tokenExpireTime"/>
-        </div>
-        <div>
-          <span wicket:id="tokenExpireTime"/>
-        </div>
+    <div class="inforight">
+      <div class="infolabel">
+        <wicket:message key="tokenExpireTime"/>
       </div>
+      <div>
+        <span wicket:id="tokenExpireTime"/>
+      </div>
+    </div>
 
-      <div class="inforow">
-        <div class="infolabel">
-          <wicket:message key="token"/>:
-        </div>
-        <div class="wrap">
-          <span wicket:id="token"/>
-        </div>
+    <div class="inforow">
+      <div class="infolabel">
+        <wicket:message key="token"/>:
+      </div>
+      <div class="wrap">
+        <span wicket:id="token"/>
       </div>
-    </wicket:extend>
-  </body>
+    </div>
+  </wicket:extend>
 </html>
@@ -28,15 +28,26 @@ import javax.xml.bind.annotation.XmlType;
  */
 @XmlRootElement(name = "reconciliationStatus")
 @XmlType
-public class ReconciliationStatus extends AbstractBaseBean {
+public class ReconStatus extends AbstractBaseBean {
 
     private static final long serialVersionUID = -8516345256596521490L;
 
+    private String resource;
+
     private ConnObjectTO onSyncope;
 
     private ConnObjectTO onResource;
 
     @Schema(accessMode = Schema.AccessMode.READ_ONLY)
+    public String getResource() {
+        return resource;
+    }
+
+    public void setResource(final String resource) {
+        this.resource = resource;
+    }
+
+    @Schema(accessMode = Schema.AccessMode.READ_ONLY)
     public ConnObjectTO getOnSyncope() {
         return onSyncope;
     }
index 6cd6c98..ec82e1b 100644 (file)
@@ -52,4 +52,11 @@ public enum AnyTypeKind {
         return patchClass;
     }
 
+    public static AnyTypeKind fromTOClass(final Class<? extends AnyTO> clazz) {
+        return UserTO.class.isAssignableFrom(clazz)
+                ? AnyTypeKind.USER
+                : GroupTO.class.isAssignableFrom(clazz)
+                ? AnyTypeKind.GROUP
+                : AnyTypeKind.ANY_OBJECT;
+    }
 }
index 068f840..b971a3e 100644 (file)
@@ -34,7 +34,7 @@ import javax.ws.rs.core.MediaType;
 import org.apache.syncope.common.lib.SyncopeConstants;
 import org.apache.syncope.common.lib.to.PullTaskTO;
 import org.apache.syncope.common.lib.to.PushTaskTO;
-import org.apache.syncope.common.lib.to.ReconciliationStatus;
+import org.apache.syncope.common.lib.to.ReconStatus;
 import org.apache.syncope.common.lib.types.AnyTypeKind;
 
 /**
@@ -59,7 +59,7 @@ public interface ReconciliationService extends JAXRSService {
      */
     @GET
     @Produces({ MediaType.APPLICATION_JSON, SyncopeConstants.APPLICATION_YAML, MediaType.APPLICATION_XML })
-    ReconciliationStatus status(
+    ReconStatus status(
             @NotNull @QueryParam("anyTypeKind") AnyTypeKind anyTypeKind,
             @NotNull @QueryParam("anyKey") String anyKey,
             @NotNull @QueryParam("resourceKey") String resourceKey);
index a686215..d2315c5 100644 (file)
@@ -31,7 +31,7 @@ import org.apache.syncope.common.lib.to.AttrTO;
 import org.apache.syncope.common.lib.to.ConnObjectTO;
 import org.apache.syncope.common.lib.to.PullTaskTO;
 import org.apache.syncope.common.lib.to.PushTaskTO;
-import org.apache.syncope.common.lib.to.ReconciliationStatus;
+import org.apache.syncope.common.lib.to.ReconStatus;
 import org.apache.syncope.common.lib.types.AnyTypeKind;
 import org.apache.syncope.common.lib.types.ClientExceptionType;
 import org.apache.syncope.common.lib.types.StandardEntitlement;
@@ -131,9 +131,10 @@ public class ReconciliationLogic extends AbstractTransactionalLogic<AbstractBase
         MappingItem connObjectKeyItem = MappingUtils.getConnObjectKeyItem(provision).orElseThrow(()
                 -> new NotFoundException("ConnObjectKey for " + any.getType()
                         + " on resource '" + provision.getResource().getKey() + "'"));
-        String connObjectKeyValue = mappingManager.getConnObjectKeyValue(any, provision).orElseThrow(()
-                -> new NotFoundException("Value for ConnObjectKey for " + any.getType()
-                        + " on resource '" + provision.getResource().getKey() + "'"));
+        String connObjectKeyValue = mappingManager.getConnObjectKeyValue(any, provision).orElse(null);
+        if (connObjectKeyValue == null) {
+            return null;
+        }
 
         // 2. determine attributes to query
         Set<MappingItem> linkinMappingItems = virSchemaDAO.findByProvision(provision).stream().
@@ -166,10 +167,11 @@ public class ReconciliationLogic extends AbstractTransactionalLogic<AbstractBase
     }
 
     @PreAuthorize("hasRole('" + StandardEntitlement.RESOURCE_GET_CONNOBJECT + "')")
-    public ReconciliationStatus status(final AnyTypeKind anyTypeKind, final String anyKey, final String resourceKey) {
+    public ReconStatus status(final AnyTypeKind anyTypeKind, final String anyKey, final String resourceKey) {
         Pair<Any<?>, Provision> init = init(anyTypeKind, anyKey, resourceKey);
 
-        ReconciliationStatus status = new ReconciliationStatus();
+        ReconStatus status = new ReconStatus();
+        status.setResource(resourceKey);
         status.setOnSyncope(getOnSyncope(init.getLeft(), init.getRight(), resourceKey));
         status.setOnResource(getOnResource(init.getLeft(), init.getRight()));
 
index dda23b2..e65704a 100644 (file)
@@ -101,12 +101,11 @@ public class JPARoleDAO extends AbstractDAO<Role> implements RoleDAO {
         Role merged = entityManager().merge(role);
 
         // refresh dynamic memberships
+        clearDynMembers(merged);
         if (merged.getDynMembership() != null) {
             List<User> matching = searchDAO().search(
                     SearchCondConverter.convert(merged.getDynMembership().getFIQLCond()), AnyTypeKind.USER);
 
-            clearDynMembers(merged);
-
             matching.forEach((user) -> {
                 Query insert = entityManager().createNativeQuery("INSERT INTO " + DYNMEMB_TABLE + " VALUES(?, ?)");
                 insert.setParameter(1, user.getKey());
index bb410f9..65151dc 100644 (file)
@@ -110,6 +110,7 @@ public class SinglePullJobDelegate extends PullJobDelegate implements SyncopeSin
             pullTask.setPerformCreate(pullTaskTO.isPerformCreate());
             pullTask.setPerformUpdate(pullTaskTO.isPerformUpdate());
             pullTask.setPerformDelete(pullTaskTO.isPerformDelete());
+            pullTask.setSyncStatus(pullTaskTO.isSyncStatus());
             pullTask.setDestinationRealm(realm);
             pullTask.setRemediation(pullTaskTO.isRemediation());
             // validate JEXL expressions from templates and proceed if fine
index 90b8f08..8f8a3d1 100644 (file)
@@ -80,6 +80,7 @@ public class SinglePushJobDelegate extends PushJobDelegate implements SyncopeSin
             pushTask.setPerformCreate(pushTaskTO.isPerformCreate());
             pushTask.setPerformUpdate(pushTaskTO.isPerformUpdate());
             pushTask.setPerformDelete(pushTaskTO.isPerformDelete());
+            pushTask.setSyncStatus(pushTaskTO.isSyncStatus());
 
             profile = new ProvisioningProfile<>(connector, pushTask);
             profile.getActions().addAll(actions);
index ad460cb..ed24be5 100644 (file)
@@ -20,7 +20,7 @@ package org.apache.syncope.core.rest.cxf.service;
 
 import org.apache.syncope.common.lib.to.PullTaskTO;
 import org.apache.syncope.common.lib.to.PushTaskTO;
-import org.apache.syncope.common.lib.to.ReconciliationStatus;
+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;
 import org.apache.syncope.core.logic.ReconciliationLogic;
@@ -38,7 +38,7 @@ public class ReconciliationServiceImpl extends AbstractServiceImpl implements Re
     private AnyUtilsFactory anyUtilsFactory;
 
     @Override
-    public ReconciliationStatus status(final AnyTypeKind anyTypeKind, final String anyKey, final String resourceKey) {
+    public ReconStatus status(final AnyTypeKind anyTypeKind, final String anyKey, final String resourceKey) {
         return logic.status(
                 anyTypeKind,
                 getActualKey(anyUtilsFactory.getInstance(anyTypeKind).dao(), anyKey),
index cd20170..66486ff 100644 (file)
@@ -96,7 +96,7 @@ public class BulkActionITCase extends AbstractConsoleITCase {
                 + "first:container:content:searchContainer:resultTable:tablePanel:groupForm");
         assertNotNull(formTester);
 
-        formTester.select("checkgroup", 2);
+        formTester.select("checkgroup", 0);
 
         TESTER.executeAjaxEvent(TAB_PANEL + "outerObjectsRepeater:2:outer:form:content:status:"
                 + "firstLevelContainer:first:container:content:searchContainer:resultTable:tablePanel:bulkActionLink",
@@ -116,7 +116,7 @@ public class BulkActionITCase extends AbstractConsoleITCase {
 
     @Test
     public void userStatusOnSyncopeOnlyBulkAction() {
-        userStatusBulkAction(0, "Syncope");
+        userStatusBulkAction(0, Constants.SYNCOPE);
     }
 
     private void userStatusBulkAction(final int index, final String resource) {
@@ -169,7 +169,7 @@ public class BulkActionITCase extends AbstractConsoleITCase {
         TESTER.cleanupFeedbackMessages();
 
         TESTER.assertLabel(TAB_PANEL + "outerObjectsRepeater:2:outer:form:content:status:"
-                + "secondLevelContainer:second:container:selectedObjects:body:rows:1:cells:3:cell", "SUCCESS");
+                + "secondLevelContainer:second:container:selectedObjects:body:rows:1:cells:4:cell", "SUCCESS");
 
         TESTER.executeAjaxEvent(TAB_PANEL
                 + "outerObjectsRepeater:2:outer:form:content:status:secondLevelContainer:back",
@@ -224,7 +224,7 @@ public class BulkActionITCase extends AbstractConsoleITCase {
         TESTER.cleanupFeedbackMessages();
 
         TESTER.assertLabel(TAB_PANEL + "outerObjectsRepeater:2:outer:form:content:status:"
-                + "secondLevelContainer:second:container:selectedObjects:body:rows:1:cells:3:cell", "SUCCESS");
+                + "secondLevelContainer:second:container:selectedObjects:body:rows:1:cells:4:cell", "SUCCESS");
 
         TESTER.executeAjaxEvent(TAB_PANEL
                 + "outerObjectsRepeater:2:outer:form:content:status:secondLevelContainer:back",
@@ -268,7 +268,7 @@ public class BulkActionITCase extends AbstractConsoleITCase {
         component = findComponentByProp("resource",
                 TAB_PANEL + "outerObjectsRepeater:2:outer:form:content:status:"
                 + "firstLevelContainer:first:container:content:searchContainer:resultTable:tablePanel:groupForm:"
-                + "checkgroup:dataTable", "ws-target-resource-1");
+                + "checkgroup:dataTable", "resource-ldap");
         assertNotNull(component);
 
         FormTester formTester = TESTER.newFormTester(
@@ -276,7 +276,7 @@ public class BulkActionITCase extends AbstractConsoleITCase {
                 + "first:container:content:searchContainer:resultTable:tablePanel:groupForm");
         assertNotNull(formTester);
 
-        formTester.select("checkgroup", 7);
+        formTester.select("checkgroup", 0);
 
         TESTER.executeAjaxEvent(TAB_PANEL + "outerObjectsRepeater:2:outer:form:content:status:"
                 + "firstLevelContainer:first:container:content:searchContainer:resultTable:tablePanel:bulkActionLink",
@@ -286,7 +286,7 @@ public class BulkActionITCase extends AbstractConsoleITCase {
                 + "secondLevelContainer:second:container", WebMarkupContainer.class);
 
         assertNotNull(findComponentByProp("resource", TAB_PANEL + "outerObjectsRepeater:2:outer:"
-                + "form:content:status:secondLevelContainer:second:container:selectedObjects", "resource-testdb2"));
+                + "form:content:status:secondLevelContainer:second:container:selectedObjects", "resource-ldap"));
     }
 
     @Test
@@ -316,7 +316,7 @@ public class BulkActionITCase extends AbstractConsoleITCase {
         component = findComponentByProp("resource",
                 TAB_PANEL + "outerObjectsRepeater:2:outer:form:content:status:"
                 + "firstLevelContainer:first:container:content:searchContainer:resultTable:tablePanel:groupForm:"
-                + "checkgroup:dataTable", "ws-target-resource-1");
+                + "checkgroup:dataTable", "resource-db-scripted");
         assertNotNull(component);
 
         FormTester formTester = TESTER.newFormTester(
@@ -324,7 +324,7 @@ public class BulkActionITCase extends AbstractConsoleITCase {
                 + "first:container:content:searchContainer:resultTable:tablePanel:groupForm");
         assertNotNull(formTester);
 
-        formTester.select("checkgroup", 7);
+        formTester.select("checkgroup", 0);
 
         TESTER.executeAjaxEvent(TAB_PANEL + "outerObjectsRepeater:2:outer:form:content:status:"
                 + "firstLevelContainer:first:container:content:searchContainer:resultTable:tablePanel:bulkActionLink",
@@ -334,7 +334,7 @@ public class BulkActionITCase extends AbstractConsoleITCase {
                 + "secondLevelContainer:second:container", WebMarkupContainer.class);
 
         assertNotNull(findComponentByProp("resource", TAB_PANEL + "outerObjectsRepeater:2:outer:"
-                + "form:content:status:secondLevelContainer:second:container:selectedObjects", "resource-testdb2"));
+                + "form:content:status:secondLevelContainer:second:container:selectedObjects", "resource-db-scripted"));
     }
 
     @Test
index a5ba6a0..44518de 100644 (file)
@@ -181,16 +181,17 @@ public class RealmsITCase extends AbstractConsoleITCase {
         TESTER.clickLink(component.getPageRelativePath() + ":actions:actionRepeater:0:action:action");
 
         TESTER.assertLabel("body:content:body:outerObjectsRepeater:0:outer:form:content:customResultBody:"
-                + "secondLevelContainer:second:remoteObject:propView:0:value:oldAttribute:field-label", "__NAME__");
+                + "secondLevelContainer:second:remoteObject:propView:0:value:leftAttribute:field-label", "__NAME__");
 
         TESTER.assertModelValue("body:content:body:outerObjectsRepeater:0:outer:form:content:customResultBody:"
-                + "secondLevelContainer:second:remoteObject:propView:0:value:oldAttribute:textField", null);
+                + "secondLevelContainer:second:remoteObject:propView:0:value:leftAttribute:textField", null);
 
         TESTER.assertLabel("body:content:body:outerObjectsRepeater:0:outer:form:content:customResultBody:"
-                + "secondLevelContainer:second:remoteObject:propView:0:value:newAttribute:field-label", "__NAME__");
+                + "secondLevelContainer:second:remoteObject:propView:0:value:rightAttribute:field-label", "__NAME__");
 
         TESTER.assertModelValue("body:content:body:outerObjectsRepeater:0:outer:form:content:customResultBody:"
-                + "secondLevelContainer:second:remoteObject:propView:0:value:newAttribute:textField", "ou=even,o=isp");
+                + "secondLevelContainer:second:remoteObject:propView:0:value:rightAttribute:textField",
+                "ou=even,o=isp");
 
         TESTER.clickLink("body:content:body:outerObjectsRepeater:0:outer:form:content:customResultBody:"
                 + "secondLevelContainer:back");
@@ -226,16 +227,16 @@ public class RealmsITCase extends AbstractConsoleITCase {
         TESTER.clickLink(component.getPageRelativePath() + ":actions:actionRepeater:0:action:action");
 
         TESTER.assertLabel("body:content:body:outerObjectsRepeater:0:outer:form:content:customResultBody:"
-                + "secondLevelContainer:second:remoteObject:propView:4:value:oldAttribute:field-label", "ou");
+                + "secondLevelContainer:second:remoteObject:propView:4:value:leftAttribute:field-label", "ou");
 
         TESTER.assertModelValue("body:content:body:outerObjectsRepeater:0:outer:form:content:customResultBody:"
-                + "secondLevelContainer:second:remoteObject:propView:4:value:oldAttribute:textField", "even");
+                + "secondLevelContainer:second:remoteObject:propView:4:value:leftAttribute:textField", "even");
 
         TESTER.assertLabel("body:content:body:outerObjectsRepeater:0:outer:form:content:customResultBody:"
-                + "secondLevelContainer:second:remoteObject:propView:4:value:newAttribute:field-label", "ou");
+                + "secondLevelContainer:second:remoteObject:propView:4:value:rightAttribute:field-label", "ou");
 
         TESTER.assertModelValue("body:content:body:outerObjectsRepeater:0:outer:form:content:customResultBody:"
-                + "secondLevelContainer:second:remoteObject:propView:4:value:newAttribute:textField", null);
+                + "secondLevelContainer:second:remoteObject:propView:4:value:rightAttribute:textField", null);
 
         TESTER.clickLink("body:content:body:outerObjectsRepeater:0:outer:form:content:customResultBody:"
                 + "secondLevelContainer:back");
index ff417f6..7a99aaf 100644 (file)
@@ -84,7 +84,7 @@ public class TopologyITCase extends AbstractConsoleITCase {
         Component component = findComponentByProp("key", "body:resources", "ws-target-resource-1");
         assertNotNull(component);
         TESTER.executeAjaxEvent(component.getPageRelativePath() + ":res", Constants.ON_CLICK);
-        TESTER.clickLink("body:toggle:container:content:togglePanelContainer:container:actions:status");
+        TESTER.clickLink("body:toggle:container:content:togglePanelContainer:container:actions:reconciliation");
 
         TESTER.assertComponent("body:toggle:outerObjectsRepeater:1:outer", Modal.class);
 
index 703799f..c8fd044 100644 (file)
@@ -30,7 +30,7 @@ import org.apache.syncope.common.lib.to.AnyObjectTO;
 import org.apache.syncope.common.lib.to.AttrTO;
 import org.apache.syncope.common.lib.to.PullTaskTO;
 import org.apache.syncope.common.lib.to.PushTaskTO;
-import org.apache.syncope.common.lib.to.ReconciliationStatus;
+import org.apache.syncope.common.lib.to.ReconStatus;
 import org.apache.syncope.common.lib.types.AnyTypeKind;
 import org.apache.syncope.common.lib.types.UnmatchingRule;
 import org.apache.syncope.fit.AbstractITCase;
@@ -60,7 +60,7 @@ public class ReconciliationITCase extends AbstractITCase {
                 "SELECT id FROM testPRINTER WHERE printername=?", printer.getName()).size());
 
         // 3. verify reconciliation status
-        ReconciliationStatus status =
+        ReconStatus status =
                 reconciliationService.status(AnyTypeKind.ANY_OBJECT, printer.getName(), "resource-db-scripted");
         assertNotNull(status);
         assertNotNull(status.getOnSyncope());
@@ -110,7 +110,7 @@ public class ReconciliationITCase extends AbstractITCase {
                 printer.getKey(), printer.getName(), "Nowhere", false, new Date());
 
         // 3. verify reconciliation status
-        ReconciliationStatus status =
+        ReconStatus status =
                 reconciliationService.status(AnyTypeKind.ANY_OBJECT, printer.getName(), "resource-db-scripted");
         assertNotNull(status);
         assertNotNull(status.getOnSyncope());