This is an automated email from the ASF dual-hosted git repository.
ilgrosso pushed a commit to branch 2_1_X
in repository https://gitbox.apache.org/repos/asf/syncope.git
The following commit(s) were added to refs/heads/2_1_X by this push:
new 1a5b1d6 [SYNCOPE-1511] White noise: rework to allow easier extensions
1a5b1d6 is described below
commit 1a5b1d6c83c7a07e97548e43360984a8ea4b6072
Author: Francesco Chicchiriccò <[email protected]>
AuthorDate: Wed Dec 11 11:17:32 2019 +0100
[SYNCOPE-1511] White noise: rework to allow easier extensions
---
.../console/audit/AuditHistoryDirectoryPanel.java | 190 ++++++++++-----------
.../client/console/audit/AuditHistoryModal.java | 15 +-
.../client/console/audit/HistoryAuditDetails.java | 73 ++++----
3 files changed, 132 insertions(+), 146 deletions(-)
diff --git
a/client/console/src/main/java/org/apache/syncope/client/console/audit/AuditHistoryDirectoryPanel.java
b/client/console/src/main/java/org/apache/syncope/client/console/audit/AuditHistoryDirectoryPanel.java
index 902576e..62bb700 100644
---
a/client/console/src/main/java/org/apache/syncope/client/console/audit/AuditHistoryDirectoryPanel.java
+++
b/client/console/src/main/java/org/apache/syncope/client/console/audit/AuditHistoryDirectoryPanel.java
@@ -20,8 +20,17 @@ package org.apache.syncope.client.console.audit;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Date;
+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.SyncopeConsoleSession;
+import
org.apache.syncope.client.console.audit.AuditHistoryDirectoryPanel.AuditHistoryProvider;
import org.apache.syncope.client.console.commons.Constants;
import org.apache.syncope.client.console.commons.DirectoryDataProvider;
import org.apache.syncope.client.console.pages.BasePage;
@@ -38,7 +47,6 @@ import
org.apache.syncope.client.console.wicket.markup.html.bootstrap.dialog.Bas
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.AnyOperations;
-import org.apache.syncope.common.lib.SyncopeClientException;
import org.apache.syncope.common.lib.patch.AnyObjectPatch;
import org.apache.syncope.common.lib.patch.GroupPatch;
import org.apache.syncope.common.lib.patch.UserPatch;
@@ -50,7 +58,6 @@ import org.apache.syncope.common.lib.to.ProvisioningResult;
import org.apache.syncope.common.lib.to.UserTO;
import org.apache.syncope.common.lib.types.AnyTypeKind;
import org.apache.syncope.common.lib.types.AuditElements;
-import org.apache.syncope.common.lib.types.ClientExceptionType;
import org.apache.syncope.common.lib.types.StandardEntitlement;
import org.apache.wicket.PageReference;
import org.apache.wicket.ajax.AjaxRequestTarget;
@@ -61,25 +68,15 @@ import org.apache.wicket.model.CompoundPropertyModel;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.StringResourceModel;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Date;
-import java.util.Iterator;
-import java.util.List;
-import java.util.stream.Collectors;
-
public class AuditHistoryDirectoryPanel extends
- DirectoryPanel<AuditEntryTO, AuditEntryTO,
- AuditHistoryDirectoryPanel.AuditHistoryProvider,
AuditHistoryRestClient>
- implements ModalPanel {
+ DirectoryPanel<AuditEntryTO, AuditEntryTO, AuditHistoryProvider,
AuditHistoryRestClient>
+ implements ModalPanel {
private static final long serialVersionUID = -8248734710505211261L;
private static final int TOTAL_AUDIT_HISTORY_COMPARISONS = 25;
- private static final ObjectMapper MAPPER = new ObjectMapper();
+ protected static final ObjectMapper MAPPER = new ObjectMapper();
private final BaseModal<?> baseModal;
@@ -90,10 +87,10 @@ public class AuditHistoryDirectoryPanel extends
private final AnyTypeKind anyTypeKind;
public AuditHistoryDirectoryPanel(
- final BaseModal<?> baseModal,
- final MultilevelPanel multiLevelPanelRef,
- final PageReference pageRef,
- final AnyTO anyTO) {
+ final BaseModal<?> baseModal,
+ final MultilevelPanel multiLevelPanelRef,
+ final PageReference pageRef,
+ final AnyTO anyTO) {
super(MultilevelPanel.FIRST_LEVEL_ID, pageRef);
disableCheckBoxes();
@@ -101,61 +98,46 @@ public class AuditHistoryDirectoryPanel extends
this.baseModal = baseModal;
this.multiLevelPanelRef = multiLevelPanelRef;
this.anyTO = anyTO;
+ this.anyTypeKind = AnyTypeKind.fromTOClass(anyTO.getClass());
- anyTypeKind = AnyTypeKind.fromTOClass(anyTO.getClass());
this.restClient = new AuditHistoryRestClient();
initResultTable();
}
/**
- * Restore an object based on the audit record.
- * <p>
- * Note that for user objects, the original audit record masks
- * the password and the security answer; so we cannot use the audit
- * record to resurrect the entry based on mask data. The method behavior
- * below will reset the audit record such that the current security answer
- * and the password for the object are always maintained, and such
properties
- * for the user cannot be restored using audit records.
+ * Restore an object based on the audit record.Note that for user objects,
the original audit record masks
+ * the password and the security answer; so we cannot use the audit record
to resurrect the entry based on mask
+ * data.
*
- * @param entryBean the entry bean
- * @param anyTO the any to
+ * The method behavior below will reset the audit record such that the
current security answer and the password for
+ * the object are always maintained, and such properties for the user
cannot be restored using audit records.
+ *
+ * @param json the object from audit
+ * @param anyTO the any to
* @return the response
+ * @throws JsonProcessingException if json value cannot be parsed
*/
- private static ProvisioningResult<? extends AnyTO> restore(final
AuditEntryTO entryBean,
- final AnyTO
anyTO) {
- try {
- String json = getJSONFromAuditEntry(entryBean);
- if (anyTO instanceof UserTO) {
- UserTO userTO = MAPPER.readValue(json, UserTO.class);
- UserPatch userPatch = AnyOperations.diff(userTO, anyTO, false);
- userPatch.setPassword(null);
- userPatch.setSecurityAnswer(null);
- return new UserRestClient().update(anyTO.getETagValue(),
userPatch);
- }
- if (anyTO instanceof GroupTO) {
- GroupTO groupTO = MAPPER.readValue(json, GroupTO.class);
- GroupPatch groupPatch = AnyOperations.diff(groupTO, anyTO,
false);
- return new GroupRestClient().update(anyTO.getETagValue(),
groupPatch);
- }
- if (anyTO instanceof AnyObjectTO) {
- AnyObjectTO anyObjectTO = MAPPER.readValue(json,
AnyObjectTO.class);
- AnyObjectPatch anyObjectPatch =
AnyOperations.diff(anyObjectTO, anyTO, false);
- return new AnyObjectRestClient().update(anyTO.getETagValue(),
anyObjectPatch);
- }
- } catch (final Exception e) {
- LOG.error("Could not restore object for {}", anyTO, e);
+ protected ProvisioningResult<? extends AnyTO> restore(final String json,
final AnyTO anyTO)
+ throws JsonProcessingException {
+
+ if (anyTO instanceof UserTO) {
+ UserTO userTO = MAPPER.readValue(json, UserTO.class);
+ UserPatch userPatch = AnyOperations.diff(userTO, anyTO, false);
+ userPatch.setPassword(null);
+ userPatch.setSecurityAnswer(null);
+ return new UserRestClient().update(anyTO.getETagValue(),
userPatch);
}
- throw
SyncopeClientException.build(ClientExceptionType.InvalidAnyObject);
- }
-
- private static String getJSONFromAuditEntry(final AuditEntryTO entryBean)
throws JsonProcessingException {
- final String json;
- if (entryBean.getBefore() == null) {
- json =
MAPPER.readTree(entryBean.getOutput()).get("entity").toPrettyString();
- } else {
- json = entryBean.getBefore();
+ if (anyTO instanceof GroupTO) {
+ GroupTO groupTO = MAPPER.readValue(json, GroupTO.class);
+ GroupPatch groupPatch = AnyOperations.diff(groupTO, anyTO, false);
+ return new GroupRestClient().update(anyTO.getETagValue(),
groupPatch);
+ }
+ if (anyTO instanceof AnyObjectTO) {
+ AnyObjectTO anyObjectTO = MAPPER.readValue(json,
AnyObjectTO.class);
+ AnyObjectPatch anyObjectPatch = AnyOperations.diff(anyObjectTO,
anyTO, false);
+ return new AnyObjectRestClient().update(anyTO.getETagValue(),
anyObjectPatch);
}
- return json;
+ throw new UnsupportedOperationException("Restore not supported for " +
anyTO.getClass().getName());
}
private static SortParam<String> getSortParam() {
@@ -184,24 +166,24 @@ public class AuditHistoryDirectoryPanel extends
protected List<IColumn<AuditEntryTO, String>> getColumns() {
final List<IColumn<AuditEntryTO, String>> columns = new ArrayList<>();
columns.add(new PropertyColumn<>(
- new StringResourceModel("who", this), "who"));
+ new StringResourceModel("who", this), "who"));
columns.add(new DatePropertyColumn<>(
- new StringResourceModel("date", this), null, "date"));
+ new StringResourceModel("date", this), null, "date"));
return columns;
}
@Override
protected void resultTableCustomChanges(
- final AjaxDataTablePanel.Builder<AuditEntryTO, String>
resultTableBuilder) {
+ final AjaxDataTablePanel.Builder<AuditEntryTO, String>
resultTableBuilder) {
resultTableBuilder.setMultiLevelPanel(baseModal, multiLevelPanelRef);
}
@Override
protected ActionsPanel<AuditEntryTO> getActions(final IModel<AuditEntryTO>
model) {
final ActionsPanel<AuditEntryTO> panel = super.getActions(model);
- final AuditEntryTO auditEntryTO = model.getObject();
panel.add(new ActionLink<AuditEntryTO>() {
+
private static final long serialVersionUID = -6745431735457245600L;
@Override
@@ -233,13 +215,18 @@ public class AuditHistoryDirectoryPanel extends
public void onClick(final AjaxRequestTarget target, final
AuditEntryTO modelObject) {
try {
AuditHistoryDirectoryPanel.this.getTogglePanel().close(target);
- ProvisioningResult<? extends AnyTO> result =
restore(modelObject, anyTO);
+
+ String json = modelObject.getBefore() == null
+ ?
MAPPER.readTree(modelObject.getOutput()).get("entity").toPrettyString()
+ : modelObject.getBefore();
+ ProvisioningResult<? extends AnyTO> result = restore(json,
anyTO);
anyTO.setLastChangeDate(new
Date(Long.parseLong(result.getEntity().getETagValue())));
+
target.add(container);
- } catch (SyncopeClientException e) {
- LOG.error("While restoring {}", anyTypeKind, e);
+ } catch (Exception e) {
+ LOG.error("While restoring {}",
anyTO.getClass().getName(), e);
SyncopeConsoleSession.get().error(StringUtils.isBlank(e.getMessage())
- ? e.getClass().getName() : e.getMessage());
+ ? e.getClass().getName() : e.getMessage());
}
((BasePage)
pageRef.getPage()).getNotificationPanel().refresh(target);
}
@@ -255,40 +242,41 @@ public class AuditHistoryDirectoryPanel extends
private void viewAuditHistory(final AuditEntryTO auditEntryBean, final
AjaxRequestTarget target) {
List<AuditEntryTO> search = restClient.search(anyTO.getKey(),
- 0,
- TOTAL_AUDIT_HISTORY_COMPARISONS,
- getSortParam(),
- getQueryableAuditEvents(),
- getQueryableAuditResult());
+ 0,
+ TOTAL_AUDIT_HISTORY_COMPARISONS,
+ getSortParam(),
+ getQueryableAuditEvents(),
+ getQueryableAuditResult());
multiLevelPanelRef.next(
- new StringResourceModel("audit.diff.view", this).getObject(),
- new HistoryAuditDetails(modal, auditEntryBean,
- getPage().getPageReference(), toAuditEntryTOs(search), anyTO,
anyTypeKind), target);
+ new StringResourceModel("audit.diff.view", this).getObject(),
+ new HistoryAuditDetails(modal, auditEntryBean,
+ getPage().getPageReference(), toAuditEntryTOs(search),
anyTO), target);
}
private List<AuditEntryTO> toAuditEntryTOs(final List<AuditEntryTO>
search) {
return search
- .stream()
- .map(entry -> {
- AuditEntryTO bean = new AuditEntryTO();
- bean.setKey(anyTO.getKey());
- bean.setBefore(entry.getBefore());
- bean.setDate(entry.getDate());
- bean.setEvent(entry.getEvent());
- bean.getInputs().addAll(entry.getInputs());
- bean.setLoggerName(entry.getLoggerName());
- bean.setOutput(entry.getOutput());
- bean.setResult(entry.getResult());
- bean.setSubCategory(entry.getSubCategory());
- bean.setThrowable(entry.getThrowable());
- bean.setWho(entry.getWho());
- return bean;
- })
- .collect(Collectors.toList());
+ .stream()
+ .map(entry -> {
+ AuditEntryTO bean = new AuditEntryTO();
+ bean.setKey(anyTO.getKey());
+ bean.setBefore(entry.getBefore());
+ bean.setDate(entry.getDate());
+ bean.setEvent(entry.getEvent());
+ bean.getInputs().addAll(entry.getInputs());
+ bean.setLoggerName(entry.getLoggerName());
+ bean.setOutput(entry.getOutput());
+ bean.setResult(entry.getResult());
+ bean.setSubCategory(entry.getSubCategory());
+ bean.setThrowable(entry.getThrowable());
+ bean.setWho(entry.getWho());
+ return bean;
+ })
+ .collect(Collectors.toList());
}
protected class AuditHistoryProvider extends
DirectoryDataProvider<AuditEntryTO> {
+
private static final long serialVersionUID = 415113175628260864L;
AuditHistoryProvider(final int paginatorRows) {
@@ -313,11 +301,11 @@ public class AuditHistoryDirectoryPanel extends
private List<AuditEntryTO> getAuditEntryBeans(final long first, final
long count) {
int page = (int) first / paginatorRows;
return restClient.search(anyTO.getKey(),
- Math.max(page, 0) + 1,
- Long.valueOf(count).intValue(),
- getSortParam(),
- getQueryableAuditEvents(),
- getQueryableAuditResult());
+ Math.max(page, 0) + 1,
+ Long.valueOf(count).intValue(),
+ getSortParam(),
+ getQueryableAuditEvents(),
+ getQueryableAuditResult());
}
}
}
diff --git
a/client/console/src/main/java/org/apache/syncope/client/console/audit/AuditHistoryModal.java
b/client/console/src/main/java/org/apache/syncope/client/console/audit/AuditHistoryModal.java
index 6b553f1..7b42c6e 100644
---
a/client/console/src/main/java/org/apache/syncope/client/console/audit/AuditHistoryModal.java
+++
b/client/console/src/main/java/org/apache/syncope/client/console/audit/AuditHistoryModal.java
@@ -26,14 +26,15 @@ import org.apache.wicket.PageReference;
import org.apache.wicket.markup.html.panel.Panel;
public class AuditHistoryModal<T extends AnyTO> extends Panel implements
ModalPanel {
+
private static final long serialVersionUID = 1066124171682570080L;
protected final AuditHistoryDirectoryPanel directoryPanel;
public AuditHistoryModal(
- final BaseModal<?> baseModal,
- final PageReference pageReference,
- final T entity) {
+ final BaseModal<?> baseModal,
+ final PageReference pageReference,
+ final T entity) {
super(BaseModal.CONTENT_ID);
@@ -44,10 +45,10 @@ public class AuditHistoryModal<T extends AnyTO> extends
Panel implements ModalPa
}
protected AuditHistoryDirectoryPanel getDirectoryPanel(
- final MultilevelPanel mlp,
- final BaseModal<?> baseModal,
- final PageReference pageReference,
- final T entity) {
+ final MultilevelPanel mlp,
+ final BaseModal<?> baseModal,
+ final PageReference pageReference,
+ final T entity) {
return new AuditHistoryDirectoryPanel(baseModal, mlp, pageReference,
entity);
}
diff --git
a/client/console/src/main/java/org/apache/syncope/client/console/audit/HistoryAuditDetails.java
b/client/console/src/main/java/org/apache/syncope/client/console/audit/HistoryAuditDetails.java
index 9628a05..0973991 100644
---
a/client/console/src/main/java/org/apache/syncope/client/console/audit/HistoryAuditDetails.java
+++
b/client/console/src/main/java/org/apache/syncope/client/console/audit/HistoryAuditDetails.java
@@ -19,6 +19,11 @@
package org.apache.syncope.client.console.audit;
import com.fasterxml.jackson.databind.ObjectMapper;
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
import org.apache.commons.lang3.tuple.Pair;
import org.apache.syncope.client.console.SyncopeConsoleSession;
import org.apache.syncope.client.console.commons.Constants;
@@ -31,7 +36,6 @@ import
org.apache.syncope.client.console.wicket.markup.html.form.JsonEditorPanel
import org.apache.syncope.common.lib.to.AnyTO;
import org.apache.syncope.common.lib.to.AuditEntryTO;
import org.apache.syncope.common.lib.to.UserTO;
-import org.apache.syncope.common.lib.types.AnyTypeKind;
import org.apache.wicket.PageReference;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.ajax.form.AjaxFormComponentUpdatingBehavior;
@@ -41,38 +45,34 @@ import org.apache.wicket.model.CompoundPropertyModel;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.PropertyModel;
-import java.util.ArrayList;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.stream.Collectors;
-
public class HistoryAuditDetails extends MultilevelPanel.SecondLevel {
- private static final String KEY_CURRENT = "current";
private static final long serialVersionUID = -7400543686272100483L;
private static final ObjectMapper MAPPER = new ObjectMapper();
+ private static final String KEY_CURRENT = "current";
+
private final AuditEntryTO selected;
private final List<AuditEntryTO> availableTOs;
- private final AnyTypeKind anyTypeKind;
-
private AbstractModalPanel<String> jsonPanel;
private final AnyTO currentTO;
- public HistoryAuditDetails(final BaseModal<?> baseModal, final
AuditEntryTO selected,
- final PageReference pageRef, final
List<AuditEntryTO> availableTOs,
- final AnyTO currentTO, final AnyTypeKind
anyTypeKind) {
+ public HistoryAuditDetails(
+ final BaseModal<?> baseModal,
+ final AuditEntryTO selected,
+ final PageReference pageRef,
+ final List<AuditEntryTO> availableTOs,
+ final AnyTO currentTO) {
+
super();
- this.availableTOs = availableTOs.stream()
- .filter(object -> !selected.equals(object) && selected.getBefore()
!= null)
- .collect(Collectors.toList());
+ this.availableTOs = availableTOs.stream().
+ filter(object -> !selected.equals(object) &&
selected.getBefore() != null).
+ collect(Collectors.toList());
this.selected = selected;
- this.anyTypeKind = anyTypeKind;
this.currentTO = currentTO;
addCurrentInstanceConf();
@@ -105,7 +105,7 @@ public class HistoryAuditDetails extends
MultilevelPanel.SecondLevel {
entries.forEach(entry -> infos.add(getJSONInfo(entry)));
jsonPanel = new JsonDiffPanel(null, new PropertyModel<>(infos.get(0),
"value"),
- new PropertyModel<>(infos.get(1), "value"), null) {
+ new PropertyModel<>(infos.get(1), "value"), null) {
private static final long serialVersionUID = -8927036362466990179L;
@@ -119,7 +119,7 @@ public class HistoryAuditDetails extends
MultilevelPanel.SecondLevel {
}
private String getSanitizedTOAsJSON(final AnyTO anyTO) throws Exception {
- if (this.anyTypeKind == AnyTypeKind.USER) {
+ if (anyTO instanceof UserTO) {
UserTO userTO = (UserTO) anyTO;
userTO.setPassword(null);
userTO.setSecurityAnswer(null);
@@ -130,15 +130,12 @@ public class HistoryAuditDetails extends
MultilevelPanel.SecondLevel {
private Pair<String, String> getJSONInfo(final AuditEntryTO
auditEntryBean) {
try {
- final String content;
- if (auditEntryBean.getBefore() == null) {
- content =
MAPPER.readTree(auditEntryBean.getOutput()).get("entity").toPrettyString();
- } else {
- content = auditEntryBean.getBefore();
- }
+ String content = auditEntryBean.getBefore() == null
+ ?
MAPPER.readTree(auditEntryBean.getOutput()).get("entity").toPrettyString()
+ : auditEntryBean.getBefore();
- AnyTO userTO = MAPPER.readValue(content, anyTypeKind.getTOClass());
- String json = getSanitizedTOAsJSON(userTO);
+ AnyTO anyTO = MAPPER.readValue(content, currentTO.getClass());
+ String json = getSanitizedTOAsJSON(anyTO);
return Pair.of(auditEntryBean.getKey(), json);
} catch (Exception e) {
throw new RuntimeException(e);
@@ -147,14 +144,13 @@ public class HistoryAuditDetails extends
MultilevelPanel.SecondLevel {
private static <T extends AuditEntryTO> Map<String, String>
getDropdownNamesMap(final List<T> entries) {
Map<String, String> map = new LinkedHashMap<>();
- for (AuditEntryTO audit : entries) {
- String value = audit.getWho()
- + " - " +
SyncopeConsoleSession.get().getDateFormat().format(audit.getDate());
+ entries.forEach(audit -> {
+ String value = audit.getWho() + " - " +
SyncopeConsoleSession.get().getDateFormat().format(audit.getDate());
if (audit.getKey().equalsIgnoreCase(KEY_CURRENT)) {
value += " - " + audit.getKey();
}
map.put(audit.getKey(), value);
- }
+ });
return map;
}
@@ -163,14 +159,14 @@ public class HistoryAuditDetails extends
MultilevelPanel.SecondLevel {
form.setModel(new CompoundPropertyModel<>(selected));
form.setOutputMarkupId(true);
- final Map<String, String> namesMap = getDropdownNamesMap(availableTOs);
+ Map<String, String> namesMap = getDropdownNamesMap(availableTOs);
List<String> keys = new ArrayList<>(namesMap.keySet());
final AjaxDropDownChoicePanel<String> dropdownElem = new
AjaxDropDownChoicePanel<>(
- "compareDropdown",
- getString("compare"),
- new PropertyModel<>(selected, "key"),
- false);
+ "compareDropdown",
+ getString("compare"),
+ new PropertyModel<>(selected, "key"),
+ false);
dropdownElem.setChoices(keys);
dropdownElem.setChoiceRenderer(new IChoiceRenderer<String>() {
@@ -188,12 +184,13 @@ public class HistoryAuditDetails extends
MultilevelPanel.SecondLevel {
@Override
public String getObject(
- final String id, final IModel<? extends List<? extends
String>> choices) {
+ final String id, final IModel<? extends List<? extends
String>> choices) {
return id;
}
});
dropdownElem.setNullValid(false);
dropdownElem.getField().add(new
AjaxFormComponentUpdatingBehavior(Constants.ON_CHANGE) {
+
private static final long serialVersionUID = -1107858522700306810L;
@Override
@@ -205,7 +202,7 @@ public class HistoryAuditDetails extends
MultilevelPanel.SecondLevel {
if (selectedKey != null) {
if (!selectedKey.isEmpty()) {
AuditEntryTO confToCompare = availableTOs.stream().
- filter(object ->
object.getKey().equals(selectedKey)).findAny().orElse(null);
+ filter(object ->
object.getKey().equals(selectedKey)).findAny().orElse(null);
elemsToCompare.add(confToCompare);
showConfigurationDiffPanel(elemsToCompare);
} else {