This is an automated email from the ASF dual-hosted git repository.
ilgrosso pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/syncope.git
The following commit(s) were added to refs/heads/master by this push:
new 831656c503 [SYNCOPE-1621] Allow to optionally select which element(s)
to export
831656c503 is described below
commit 831656c503e3b5ff5336a21c088c654180022bbd
Author: Francesco Chicchiriccò <[email protected]>
AuthorDate: Thu Apr 17 09:02:05 2025 +0200
[SYNCOPE-1621] Allow to optionally select which element(s) to export
---
.../console/panels/DashboardSystemPanel.java | 31 ++---
.../client/console/rest/SyncopeRestClient.java | 4 +-
.../client/console/pages/BasePage.properties | 1 -
.../client/console/pages/BasePage_it.properties | 1 -
.../client/console/pages/BasePage_ja.properties | 1 -
.../client/console/pages/BasePage_pt_BR.properties | 1 -
.../client/console/pages/BasePage_ru.properties | 1 -
.../console/panels/DashboardSystemPanel.html | 143 ++++++++++-----------
.../console/panels/DashboardSystemPanel.properties | 2 +
.../panels/DashboardSystemPanel_fr_CA.properties | 4 +-
.../panels/DashboardSystemPanel_it.properties | 2 +
.../panels/DashboardSystemPanel_ja.properties | 2 +
.../panels/DashboardSystemPanel_pt_BR.properties | 4 +-
.../panels/DashboardSystemPanel_ru.properties | 2 +
.../common/rest/api/service/SyncopeService.java | 18 ++-
.../apache/syncope/core/logic/SyncopeLogic.java | 11 +-
.../core/rest/cxf/service/SyncopeServiceImpl.java | 4 +-
.../persistence/api/content/ContentExporter.java | 3 +-
.../jpa/content/XMLContentExporter.java | 45 ++++---
.../jpa/outer/XMLContentExporterTest.java | 32 ++++-
.../neo4j/content/XMLContentExporter.java | 14 +-
.../neo4j/outer/XMLContentExporterTest.java | 36 ++++--
.../org/apache/syncope/fit/core/RESTITCase.java | 19 ++-
.../reference-guide/howto/importexport.adoc | 13 +-
24 files changed, 235 insertions(+), 159 deletions(-)
diff --git
a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/panels/DashboardSystemPanel.java
b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/panels/DashboardSystemPanel.java
index e7154909ae..c3c6446f99 100644
---
a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/panels/DashboardSystemPanel.java
+++
b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/panels/DashboardSystemPanel.java
@@ -19,25 +19,26 @@
package org.apache.syncope.client.console.panels;
import java.time.Duration;
+import java.util.ArrayList;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.apache.syncope.client.console.SyncopeConsoleSession;
import org.apache.syncope.client.console.rest.SyncopeRestClient;
-import org.apache.syncope.client.ui.commons.Constants;
+import
org.apache.syncope.client.console.wicket.markup.html.form.MultiFieldPanel;
import org.apache.syncope.client.ui.commons.HttpResourceStream;
-import
org.apache.syncope.client.ui.commons.ajax.form.IndicatorAjaxFormComponentUpdatingBehavior;
+import
org.apache.syncope.client.ui.commons.markup.html.form.AjaxNumberFieldPanel;
+import
org.apache.syncope.client.ui.commons.markup.html.form.AjaxTextFieldPanel;
import org.apache.syncope.client.ui.commons.rest.ResponseHolder;
import org.apache.syncope.common.lib.info.SystemInfo;
import org.apache.syncope.common.lib.types.IdRepoEntitlement;
import org.apache.wicket.AttributeModifier;
-import org.apache.wicket.ajax.AjaxRequestTarget;
import
org.apache.wicket.authroles.authorization.strategies.role.metadata.MetaDataRoleAuthorizationStrategy;
import org.apache.wicket.markup.html.WebPage;
import org.apache.wicket.markup.html.basic.Label;
-import org.apache.wicket.markup.html.form.TextField;
import org.apache.wicket.markup.html.link.Link;
import org.apache.wicket.markup.html.panel.Panel;
import org.apache.wicket.model.Model;
+import org.apache.wicket.model.util.ListModel;
import org.apache.wicket.request.handler.resource.ResourceStreamRequestHandler;
import org.apache.wicket.request.resource.ContentDisposition;
import org.apache.wicket.spring.injection.annot.SpringBean;
@@ -67,17 +68,16 @@ public class DashboardSystemPanel extends Panel {
add(new Label("os", systemInfo.getOs()));
add(new Label("jvm", systemInfo.getJvm()));
- Model<Integer> tableThresholdModel = Model.of(100);
- add(new TextField<>("tableThreshold", tableThresholdModel).add(new
IndicatorAjaxFormComponentUpdatingBehavior(
- Constants.ON_CHANGE) {
+ AjaxNumberFieldPanel<Integer> threshold = new
AjaxNumberFieldPanel.Builder<Integer>().
+ min(0).step(10).enableOnChange().
+ build("threshold", "threshold", Integer.class, Model.of(100));
+ add(threshold.addRequiredLabel());
- private static final long serialVersionUID = -1107858522700306810L;
-
- @Override
- protected void onUpdate(final AjaxRequestTarget target) {
- // nothing to do
- }
- }));
+ ListModel<String> elementsModel = new ListModel<>(new ArrayList<>());
+ add(new MultiFieldPanel.Builder<>(elementsModel).build(
+ "elements",
+ "elements",
+ new AjaxTextFieldPanel("panel", "elements", Model.of())));
Link<Void> dbExportLink = new Link<>("dbExportLink") {
@@ -87,7 +87,8 @@ public class DashboardSystemPanel extends Panel {
public void onClick() {
try {
HttpResourceStream stream = new HttpResourceStream(new
ResponseHolder(
-
syncopeRestClient.exportInternalStorageContent(tableThresholdModel.getObject())));
+ syncopeRestClient.exportInternalStorageContent(
+ threshold.getModelObject(),
elementsModel.getObject())));
ResourceStreamRequestHandler rsrh = new
ResourceStreamRequestHandler(stream);
rsrh.setFileName(
diff --git
a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/rest/SyncopeRestClient.java
b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/rest/SyncopeRestClient.java
index e01b5e6822..c6db634c21 100644
---
a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/rest/SyncopeRestClient.java
+++
b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/rest/SyncopeRestClient.java
@@ -27,8 +27,8 @@ public class SyncopeRestClient extends BaseRestClient {
private static final long serialVersionUID = -9013241672773442286L;
- public Response exportInternalStorageContent(final int tableThreshold) {
- return
getService(SyncopeService.class).exportInternalStorageContent(tableThreshold);
+ public Response exportInternalStorageContent(final int threshold, final
List<String> elements) {
+ return
getService(SyncopeService.class).exportInternalStorageContent(threshold,
elements);
}
public List<GroupTO> searchAssignableGroups(
diff --git
a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/pages/BasePage.properties
b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/pages/BasePage.properties
index 951c3c9b7f..7b00c5e538 100644
---
a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/pages/BasePage.properties
+++
b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/pages/BasePage.properties
@@ -30,4 +30,3 @@ highContrast=Toggle high contrast mode
fontSize=Change font size
delegations=Delegations
endDelegation=End Delegation
-tableThreshold=Table Threshold
diff --git
a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/pages/BasePage_it.properties
b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/pages/BasePage_it.properties
index 42b21f5767..024bd5cc0d 100644
---
a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/pages/BasePage_it.properties
+++
b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/pages/BasePage_it.properties
@@ -30,4 +30,3 @@ highContrast=(Dis)attiva alto contrasto
fontSize=Dimensione carattere
delegations=Deleghe
endDelegation=Termina Delega
-tableThreshold=Limite righe tabella
diff --git
a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/pages/BasePage_ja.properties
b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/pages/BasePage_ja.properties
index 652f018a3a..39d0b4cc00 100644
---
a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/pages/BasePage_ja.properties
+++
b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/pages/BasePage_ja.properties
@@ -30,4 +30,3 @@ highContrast=Toggle high contrast mode
fontSize=Change font size
delegations=Delegations
endDelegation=End Delegation
-tableThreshold=Table Threshold
diff --git
a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/pages/BasePage_pt_BR.properties
b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/pages/BasePage_pt_BR.properties
index 00d7c9f0a9..8d4868066f 100644
---
a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/pages/BasePage_pt_BR.properties
+++
b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/pages/BasePage_pt_BR.properties
@@ -30,4 +30,3 @@ highContrast=Toggle high contrast mode
fontSize=Change font size
delegations=Delegations
endDelegation=End Delegation
-tableThreshold=Table Threshold
diff --git
a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/pages/BasePage_ru.properties
b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/pages/BasePage_ru.properties
index b849e68598..2e1944611b 100644
---
a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/pages/BasePage_ru.properties
+++
b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/pages/BasePage_ru.properties
@@ -30,4 +30,3 @@ highContrast=Toggle high contrast mode
fontSize=Change font size
delegations=Delegations
endDelegation=End Delegation
-tableThreshold=Table Threshold
diff --git
a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/DashboardSystemPanel.html
b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/DashboardSystemPanel.html
index 4b8483a76c..178981e605 100644
---
a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/DashboardSystemPanel.html
+++
b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/DashboardSystemPanel.html
@@ -17,90 +17,89 @@ 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>
+ <wicket:panel>
<div class="card card-gray mb-4">
- <div class="card-header">
- <h3 class="card-title">
- <wicket:message key="system.info"/>
- </h3>
- </div>
- <div class="card-body mt-3">
- <div class="row g-4">
- <div class="col-md-6">
- <div class="row ms-2 me-2">
- <div class="info-box col-12 bg-gray">
- <span class="info-box-icon"><i class="fas
fa-code-branch"></i></span>
+ <div class="card-header">
+ <h3 class="card-title">
+ <wicket:message key="system.info"/>
+ </h3>
+ </div>
+ <div class="card-body mt-3">
+ <div class="row g-4">
+ <div class="col-md-6">
+ <div class="row ms-2 me-2">
+ <div class="info-box col-12 bg-secondary">
+ <span class="info-box-icon"><i class="fas
fa-code-branch"></i></span>
- <div class="info-box-content">
- <span class="info-box-text"><wicket:message
key="version"/></span>
- <span class="info-box-number"
wicket:id="version" style="text-decoration: underline;"/>
- </div>
- </div>
- </div>
- <div class="row ms-2 me-2">
- <div class="info-box col-12 bg-info">
- <span class="info-box-icon"><i class="fas
fa-network-wired"></i></span>
+ <div class="info-box-content">
+ <span class="info-box-text"><wicket:message
key="version"/></span>
+ <span class="info-box-number" wicket:id="version"
style="text-decoration: underline;"/>
+ </div>
+ </div>
+ </div>
+ <div class="row ms-2 me-2">
+ <div class="info-box col-12 bg-info">
+ <span class="info-box-icon"><i class="fas
fa-network-wired"></i></span>
- <div class="info-box-content">
- <span class="info-box-text"><wicket:message
key="hostname"/></span>
- <span class="info-box-number"
wicket:id="hostname"/>
- </div>
- </div>
- </div>
- <div class="row ms-2 me-2">
- <div class="info-box col-12 text-bg-success">
- <span class="info-box-icon"><i class="fas
fa-microchip"></i></span>
+ <div class="info-box-content">
+ <span class="info-box-text"><wicket:message
key="hostname"/></span>
+ <span class="info-box-number" wicket:id="hostname"/>
+ </div>
+ </div>
+ </div>
+ <div class="row ms-2 me-2">
+ <div class="info-box col-12 text-bg-success">
+ <span class="info-box-icon"><i class="fas
fa-microchip"></i></span>
- <div class="info-box-content">
- <span class="info-box-text"><wicket:message
key="processors"/></span>
- <span class="info-box-number"
wicket:id="processors"/>
- </div>
- </div>
- </div>
+ <div class="info-box-content">
+ <span class="info-box-text"><wicket:message
key="processors"/></span>
+ <span class="info-box-number" wicket:id="processors"/>
+ </div>
+ </div>
+ </div>
+ </div>
+ <div class="col-md-6">
+ <div class="row ms-2 me-2">
+ <div class="info-box col-12 text-bg-warning">
+ <span class="info-box-icon"><i class="fas
fa-desktop"></i></span>
+
+ <div class="info-box-content">
+ <span class="info-box-text"><wicket:message key="os"/></span>
+ <span class="info-box-number" wicket:id="os"/>
</div>
- <div class="col-md-6">
- <div class="row ms-2 me-2">
- <div class="info-box col-12 text-bg-warning">
- <span class="info-box-icon"><i class="fas
fa-desktop"></i></span>
+ </div>
+ </div>
+ <div class="row ms-2 me-2">
+ <div class="info-box col-12 bg-primary">
+ <span class="info-box-icon"><i class="fab fa-java"></i></span>
- <div class="info-box-content">
- <span class="info-box-text"><wicket:message
key="os"/></span>
- <span class="info-box-number" wicket:id="os"/>
- </div>
- </div>
- </div>
- <div class="row ms-2 me-2">
- <div class="info-box col-12 bg-primary">
- <span class="info-box-icon"><i class="fab
fa-java"></i></span>
+ <div class="info-box-content">
+ <span class="info-box-text"><wicket:message
key="jvm"/></span>
+ <span class="info-box-number" wicket:id="jvm"/>
+ </div>
+ </div>
+ </div>
+ <div class="row ms-2 me-2">
+ <div class="info-box col-12">
+ <span class="info-box-icon bg-danger"><i class="fa
fa-download"></i></span>
- <div class="info-box-content">
- <span class="info-box-text"><wicket:message
key="jvm"/></span>
- <span class="info-box-number" wicket:id="jvm"/>
- </div>
- </div>
+ <div class="info-box-content">
+ <span class="info-box-text"><wicket:message
key="exportConfiguration"/></span>
+ <span class="info-box-text">
+ <div class="form-group">
+ <div class="col-3" wicket:id="threshold"/>
+ <div class="col-6" wicket:id="elements"/>
</div>
- <h5 class="ms-2 me-2">
- <wicket:message key="exportConfiguration"/>
- </h5>
<hr class="mb-2 ms-2 me-2"/>
-
- <div class="row ms-2 me-2">
- <div class="info-box col-12 text-bg-danger">
- <span class="info-box-icon"><i class="fa
fa-download"></i></span>
-
- <div class="info-box-content">
- <span class="info-box-text col-3">
- <label><wicket:message key="tableThreshold"/></label>
- <input type="text" class="form-control"
wicket:id="tableThreshold"/>
- <a wicket:id="dbExportLink"><wicket:message
key="download"/></a>
- </span>
- </div>
- </div>
- </div>
+ <a wicket:id="dbExportLink" class="btn btn-danger
w-100"><wicket:message key="download"/></a>
+ </span>
</div>
+ </div>
</div>
+ </div>
</div>
+ </div>
</div>
-</wicket:panel>
+ </wicket:panel>
</html>
diff --git
a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/DashboardSystemPanel.properties
b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/DashboardSystemPanel.properties
index d6cdd4539b..95ed7a6f92 100644
---
a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/DashboardSystemPanel.properties
+++
b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/DashboardSystemPanel.properties
@@ -15,3 +15,5 @@
# specific language governing permissions and limitations
# under the License.
system.info=System Information
+threshold=Threshold
+elements=Elements
diff --git
a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/DashboardSystemPanel_fr_CA.properties
b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/DashboardSystemPanel_fr_CA.properties
index 2e55cc89f4..8158d718a3 100644
---
a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/DashboardSystemPanel_fr_CA.properties
+++
b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/DashboardSystemPanel_fr_CA.properties
@@ -14,4 +14,6 @@
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
-system.info=Informations syst�me
+system.info=Informations syst\u00e8me
+threshold=Threshold
+elements=Elements
diff --git
a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/DashboardSystemPanel_it.properties
b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/DashboardSystemPanel_it.properties
index c70d9e15a6..0142c20594 100644
---
a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/DashboardSystemPanel_it.properties
+++
b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/DashboardSystemPanel_it.properties
@@ -15,3 +15,5 @@
# specific language governing permissions and limitations
# under the License.
system.info=Informazioni di sistema
+threshold=Limite righe
+elements=Elementi
diff --git
a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/DashboardSystemPanel_ja.properties
b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/DashboardSystemPanel_ja.properties
index c3a61e9d81..cc914ca96c 100644
---
a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/DashboardSystemPanel_ja.properties
+++
b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/DashboardSystemPanel_ja.properties
@@ -15,3 +15,5 @@
# specific language governing permissions and limitations
# under the License.
system.info=\u30b7\u30b9\u30c6\u30e0\u30a4\u30f3\u30d5\u30a9\u30e1\u30fc\u30b7\u30e7\u30f3
+threshold=Threshold
+elements=Elements
diff --git
a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/DashboardSystemPanel_pt_BR.properties
b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/DashboardSystemPanel_pt_BR.properties
index 10216dc516..0046d79a25 100644
---
a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/DashboardSystemPanel_pt_BR.properties
+++
b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/DashboardSystemPanel_pt_BR.properties
@@ -14,4 +14,6 @@
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
-system.info=Informa��o do sistema
+system.info=Informa\u00e7\u00e3o do sistema
+threshold=Threshold
+elements=Elements
diff --git
a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/DashboardSystemPanel_ru.properties
b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/DashboardSystemPanel_ru.properties
index 7517c166fe..49e058f450 100644
---
a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/DashboardSystemPanel_ru.properties
+++
b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/DashboardSystemPanel_ru.properties
@@ -15,3 +15,5 @@
# specific language governing permissions and limitations
# under the License.
system.info=\u0421\u0438\u0441\u0442\u0435\u043c\u043d\u0430\u044f\u0020\u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f
+threshold=Threshold
+elements=Elements
diff --git
a/common/idrepo/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/SyncopeService.java
b/common/idrepo/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/SyncopeService.java
index c8fccf78b8..9cf16f0356 100644
---
a/common/idrepo/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/SyncopeService.java
+++
b/common/idrepo/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/SyncopeService.java
@@ -41,6 +41,7 @@ import jakarta.ws.rs.core.HttpHeaders;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
import java.io.InputStream;
+import java.util.List;
import org.apache.syncope.common.lib.to.GroupTO;
import org.apache.syncope.common.lib.to.PagedResult;
import org.apache.syncope.common.lib.to.TypeExtensionTO;
@@ -81,7 +82,7 @@ public interface SyncopeService extends JAXRSService {
description = "Allows the server to inform the "
+ "client about the fact that a specified
preference was applied") }) })
@POST
- @Path("/batch")
+ @Path("batch")
@Consumes(RESTHeaders.MULTIPART_MIXED)
@Produces(RESTHeaders.MULTIPART_MIXED)
Response batch(InputStream input);
@@ -104,7 +105,7 @@ public interface SyncopeService extends JAXRSService {
@Schema(type = "integer"),
description = "seconds after which attempt again
to get batch results") }),
@ApiResponse(responseCode = "404", description = "No batch process was
found for the provided boundary") })
- @Path("/batch")
+ @Path("batch")
@Produces(RESTHeaders.MULTIPART_MIXED)
Response batch();
@@ -120,7 +121,7 @@ public interface SyncopeService extends JAXRSService {
* the provided Realm
*/
@POST
- @Path("/assignableGroups/{realm:.*}")
+ @Path("assignableGroups/{realm:.*}")
@Produces({ MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML,
MediaType.APPLICATION_XML })
PagedResult<GroupTO> searchAssignableGroups(
@NotNull @PathParam("realm") String realm,
@@ -135,17 +136,20 @@ public interface SyncopeService extends JAXRSService {
* @return User type extension information, for the provided group
*/
@GET
- @Path("/userTypeExtension/{groupName}")
+ @Path("userTypeExtension/{groupName}")
@Produces({ MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML,
MediaType.APPLICATION_XML })
TypeExtensionTO readUserTypeExtension(@NotNull @PathParam("groupName")
String groupName);
/**
- * Exports internal storage content as downloadable XML file.
+ * Exports the internal storage content as downloadable XML file.
*
- * @param tableThreshold the maximum number of rows to take for each table
of internal storage
+ * @param threshold the maximum number of rows to take for each element of
internal storage
+ * @param elements if provided, the list of elements to export; otherwise
all elements will be included
* @return internal storage content as downloadable XML file
*/
@GET
@Path("internalStorage/stream")
- Response exportInternalStorageContent(@QueryParam("tableThreshold")
@DefaultValue("100") int tableThreshold);
+ Response exportInternalStorageContent(
+ @QueryParam("threshold") @DefaultValue("100") int threshold,
+ @QueryParam("elements") List<String> elements);
}
diff --git
a/core/idrepo/logic/src/main/java/org/apache/syncope/core/logic/SyncopeLogic.java
b/core/idrepo/logic/src/main/java/org/apache/syncope/core/logic/SyncopeLogic.java
index 645ed3a794..bc3896c56b 100644
---
a/core/idrepo/logic/src/main/java/org/apache/syncope/core/logic/SyncopeLogic.java
+++
b/core/idrepo/logic/src/main/java/org/apache/syncope/core/logic/SyncopeLogic.java
@@ -144,12 +144,17 @@ public class SyncopeLogic extends AbstractLogic<EntityTO>
{
@PreAuthorize("hasRole('" + IdRepoEntitlement.KEYMASTER + "')")
@Transactional(readOnly = true)
- public void exportInternalStorageContent(final int tableThreshold, final
OutputStream os) {
+ public void exportInternalStorageContent(
+ final int threshold,
+ final OutputStream os,
+ final List<String> elements) {
+
try {
exporter.export(
AuthContextUtils.getDomain(),
- tableThreshold,
- os);
+ threshold,
+ os,
+ elements.toArray(String[]::new));
LOG.debug("Internal storage content successfully exported");
} catch (Exception e) {
LOG.error("While exporting internal storage content", e);
diff --git
a/core/idrepo/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/SyncopeServiceImpl.java
b/core/idrepo/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/SyncopeServiceImpl.java
index 4265d36c9c..1a3d7ff551 100644
---
a/core/idrepo/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/SyncopeServiceImpl.java
+++
b/core/idrepo/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/SyncopeServiceImpl.java
@@ -197,8 +197,8 @@ public class SyncopeServiceImpl extends AbstractService
implements SyncopeServic
}
@Override
- public Response exportInternalStorageContent(final int tableThreshold) {
- StreamingOutput sout = os ->
logic.exportInternalStorageContent(tableThreshold, os);
+ public Response exportInternalStorageContent(final int threshold, final
List<String> elements) {
+ StreamingOutput sout = os ->
logic.exportInternalStorageContent(threshold, os, elements);
return Response.ok(sout).
type(MediaType.TEXT_XML).
diff --git
a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/content/ContentExporter.java
b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/content/ContentExporter.java
index 0568d8840d..106bde63f9 100644
---
a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/content/ContentExporter.java
+++
b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/content/ContentExporter.java
@@ -28,6 +28,7 @@ public interface ContentExporter extends ContentDealer {
void export(
String domain,
int threshold,
- OutputStream output)
+ OutputStream output,
+ String... elements)
throws SAXException, TransformerConfigurationException;
}
diff --git
a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/content/XMLContentExporter.java
b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/content/XMLContentExporter.java
index 37b64d3531..f5303bfb0d 100644
---
a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/content/XMLContentExporter.java
+++
b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/content/XMLContentExporter.java
@@ -59,6 +59,7 @@ import java.util.stream.Stream;
import javax.sql.DataSource;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.sax.TransformerHandler;
+import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.apache.cxf.helpers.IOUtils;
@@ -92,7 +93,7 @@ public class XMLContentExporter extends
AbstractXMLContentExporter {
protected static boolean isTableAllowed(final String tableName) {
return TABLE_PREFIXES_TO_BE_EXCLUDED.stream().
- noneMatch(prefix ->
tableName.toUpperCase().startsWith(prefix.toUpperCase()));
+ noneMatch(prefix ->
tableName.toUpperCase().startsWith(prefix.toUpperCase()));
}
protected static String getValues(final ResultSet rs, final String
columnName, final Integer columnType)
@@ -178,7 +179,7 @@ public class XMLContentExporter extends
AbstractXMLContentExporter {
String attrName =
Optional.ofNullable(field.getAnnotation(Column.class)).
map(Column::name).
- orElseGet(a::getName);
+ orElseGet(a::getName);
Optional.ofNullable(field.getAnnotation(CollectionTable.class)).
ifPresent(collectionTable -> relationTables.put(
@@ -375,8 +376,13 @@ public class XMLContentExporter extends
AbstractXMLContentExporter {
public void export(
final String domain,
final int threshold,
- final OutputStream os)
- throws SAXException, TransformerConfigurationException {
+ final OutputStream os,
+ final String... elements) throws SAXException,
TransformerConfigurationException {
+
+ BidiMap<String, EntityType<?>> entities = new DualHashBidiMap<>();
+ entityManagerFactory.getMetamodel().getEntities().forEach(entity ->
Optional.ofNullable(
+ entity.getBindableJavaType().getAnnotation(Table.class)).
+ ifPresent(table -> entities.put(table.name(), entity)));
TransformerHandler handler = start(os);
@@ -392,27 +398,26 @@ public class XMLContentExporter extends
AbstractXMLContentExporter {
}
Connection conn = DataSourceUtils.getConnection(dataSource);
- try (ResultSet rs = conn.getMetaData().
- getTables(null, StringUtils.isBlank(schema) ? null : schema,
null, new String[] { "TABLE" })) {
-
+ try {
Set<String> tableNames = new
TreeSet<>(String.CASE_INSENSITIVE_ORDER);
-
- while (rs.next()) {
- String tableName = rs.getString("TABLE_NAME");
- LOG.debug("Found table {}", tableName);
- if (isTableAllowed(tableName)) {
- tableNames.add(tableName);
+ if (ArrayUtils.isEmpty(elements)) {
+ try (ResultSet rs = conn.getMetaData().getTables(null, schema,
null, new String[] { "TABLE" })) {
+ while (rs.next()) {
+ String tableName = rs.getString("TABLE_NAME");
+ LOG.debug("Found table {}", tableName);
+ if (isTableAllowed(tableName)) {
+ tableNames.add(tableName);
+ }
+ }
+ } catch (SQLException e) {
+ LOG.error("While getting the list of tables", e);
}
+ } else {
+ tableNames.addAll(Stream.of(elements).toList());
}
-
LOG.debug("Tables to be exported {}", tableNames);
- BidiMap<String, EntityType<?>> entities = new DualHashBidiMap<>();
- entityManagerFactory.getMetamodel().getEntities().forEach(entity
-> Optional.ofNullable(
- entity.getBindableJavaType().getAnnotation(Table.class)).
- ifPresent(table -> entities.put(table.name(), entity)));
-
- // then sort tables based on foreign keys and dump
+ // then sort tables based on foreign keys and export
for (String tableName : sortByForeignKeys(conn, schema,
tableNames)) {
try {
exportTable(dataSource, tableName, threshold, entities,
relationTables(entities), handler);
diff --git
a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/XMLContentExporterTest.java
b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/XMLContentExporterTest.java
index 460415affc..0c2711140d 100644
---
a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/XMLContentExporterTest.java
+++
b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/XMLContentExporterTest.java
@@ -38,6 +38,15 @@ public class XMLContentExporterTest extends AbstractTest {
@Autowired
private ContentExporter exporter;
+ private static void checkRealms(final String exported) {
+ List<String> realms = exported.lines().filter(row ->
row.trim().startsWith("<Realm ")).toList();
+ assertEquals(4, realms.size());
+ assertTrue(realms.get(0).contains("name=\"/\""));
+ assertTrue(realms.get(1).contains("name=\"even\""));
+ assertTrue(realms.get(2).contains("name=\"two\""));
+ assertTrue(realms.get(3).contains("name=\"odd\""));
+ }
+
/**
* Also checks for SYNCOPE-1307.
*
@@ -52,11 +61,22 @@ public class XMLContentExporterTest extends AbstractTest {
String exported = baos.toString(StandardCharsets.UTF_8);
assertTrue(StringUtils.isNotBlank(exported));
- List<String> realms = exported.lines().filter(row ->
row.trim().startsWith("<Realm")).toList();
- assertEquals(4, realms.size());
- assertTrue(realms.get(0).contains("name=\"/\""));
- assertTrue(realms.get(1).contains("name=\"even\""));
- assertTrue(realms.get(2).contains("name=\"two\""));
- assertTrue(realms.get(3).contains("name=\"odd\""));
+ checkRealms(exported);
+ }
+
+ @Test
+ public void exportElements() throws Exception {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+
+ exporter.export(SyncopeConstants.MASTER_DOMAIN, 100, baos,
"AccountPolicy", "Realm");
+
+ String exported = baos.toString(StandardCharsets.UTF_8);
+ assertTrue(StringUtils.isNotBlank(exported));
+
+ List<String> accountPolicies = exported.lines().
+ filter(row -> row.trim().startsWith("<AccountPolicy
")).toList();
+ assertEquals(2, accountPolicies.size());
+
+ checkRealms(exported);
}
}
diff --git
a/core/persistence-neo4j/src/main/java/org/apache/syncope/core/persistence/neo4j/content/XMLContentExporter.java
b/core/persistence-neo4j/src/main/java/org/apache/syncope/core/persistence/neo4j/content/XMLContentExporter.java
index d11201253b..305b32a332 100644
---
a/core/persistence-neo4j/src/main/java/org/apache/syncope/core/persistence/neo4j/content/XMLContentExporter.java
+++
b/core/persistence-neo4j/src/main/java/org/apache/syncope/core/persistence/neo4j/content/XMLContentExporter.java
@@ -33,6 +33,7 @@ import java.util.stream.Collectors;
import java.util.stream.Stream;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.sax.TransformerHandler;
+import org.apache.commons.lang3.ArrayUtils;
import org.apache.syncope.core.persistence.api.DomainHolder;
import
org.apache.syncope.core.persistence.common.content.AbstractXMLContentExporter;
import org.apache.syncope.core.persistence.common.content.MultiParentNode;
@@ -80,7 +81,7 @@ public class XMLContentExporter extends
AbstractXMLContentExporter {
this.mappingContext = mappingContext;
}
- protected List<Neo4jPersistentEntity<?>> persistentEntities() {
+ protected List<Neo4jPersistentEntity<?>> persistentEntities(final String[]
elements) {
Map<String, Neo4jPersistentEntity<?>> entities =
mappingContext.getPersistentEntities().stream().
filter(e ->
!LABELS_TO_BE_EXCLUDED.contains(e.getPrimaryLabel())
&& !e.getPrimaryLabel().startsWith("Abstract")
@@ -88,6 +89,10 @@ public class XMLContentExporter extends
AbstractXMLContentExporter {
collect(Collectors.toMap(
Neo4jPersistentEntity::getPrimaryLabel,
Function.identity(), (first, second) -> first));
+ if (ArrayUtils.isNotEmpty(elements)) {
+ entities.entrySet().removeIf(e -> !ArrayUtils.contains(elements,
e.getKey()));
+ }
+
Set<MultiParentNode> roots = new HashSet<>();
Map<String, MultiParentNode> exploited = new
TreeMap<>(String.CASE_INSENSITIVE_ORDER);
@@ -191,11 +196,12 @@ public class XMLContentExporter extends
AbstractXMLContentExporter {
public void export(
final String domain,
final int threshold,
- final OutputStream os) throws SAXException,
TransformerConfigurationException {
+ final OutputStream os,
+ final String... elements) throws SAXException,
TransformerConfigurationException {
TransformerHandler handler = start(os);
- for (Neo4jPersistentEntity<?> entity : persistentEntities()) {
+ for (Neo4jPersistentEntity<?> entity : persistentEntities(elements)) {
try (Session session =
domainHolder.getDomains().get(domain).session()) {
StringBuilder query = new StringBuilder("MATCH (n:" +
entity.getPrimaryLabel() + ")-[r]-() ");
if (Neo4jSchedTask.NODE.equals(entity.getPrimaryLabel())) {
@@ -205,7 +211,7 @@ public class XMLContentExporter extends
AbstractXMLContentExporter {
}
query.append("RETURN n, collect(r) AS rels ORDER BY n.id");
- Stream<Record> records =
session.run(query.toString()).stream();
+ Stream<Record> records =
session.run(query.toString()).stream().limit(threshold);
if (Neo4jRealm.NODE.equals(entity.getPrimaryLabel())) {
records = records.sorted(REALM_COMPARATOR);
}
diff --git
a/core/persistence-neo4j/src/test/java/org/apache/syncope/core/persistence/neo4j/outer/XMLContentExporterTest.java
b/core/persistence-neo4j/src/test/java/org/apache/syncope/core/persistence/neo4j/outer/XMLContentExporterTest.java
index ed6c542fd7..74f84642b4 100644
---
a/core/persistence-neo4j/src/test/java/org/apache/syncope/core/persistence/neo4j/outer/XMLContentExporterTest.java
+++
b/core/persistence-neo4j/src/test/java/org/apache/syncope/core/persistence/neo4j/outer/XMLContentExporterTest.java
@@ -23,9 +23,6 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
import java.io.ByteArrayOutputStream;
import java.nio.charset.StandardCharsets;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.StandardOpenOption;
import java.util.List;
import org.apache.commons.lang3.StringUtils;
import org.apache.syncope.common.lib.SyncopeConstants;
@@ -41,6 +38,15 @@ public class XMLContentExporterTest extends AbstractTest {
@Autowired
private ContentExporter exporter;
+ private static void checkRealms(final String exported) {
+ List<String> realms = exported.lines().filter(row ->
row.trim().startsWith("<Realm ")).toList();
+ assertEquals(4, realms.size());
+ assertTrue(realms.get(0).contains("name=\"/\""));
+ assertTrue(realms.get(1).contains("name=\"even\""));
+ assertTrue(realms.get(2).contains("name=\"two\""));
+ assertTrue(realms.get(3).contains("name=\"odd\""));
+ }
+
/**
* Also checks for SYNCOPE-1307.
*
@@ -55,14 +61,22 @@ public class XMLContentExporterTest extends AbstractTest {
String exported = baos.toString(StandardCharsets.UTF_8);
assertTrue(StringUtils.isNotBlank(exported));
- Files.writeString(Path.of("/tmp/export.xml"), exported,
- StandardOpenOption.CREATE,
StandardOpenOption.TRUNCATE_EXISTING, StandardOpenOption.WRITE);
+ checkRealms(exported);
+ }
- List<String> realms = exported.lines().filter(row ->
row.trim().startsWith("<Realm ")).toList();
- assertEquals(4, realms.size());
- assertTrue(realms.get(0).contains("name=\"/\""));
- assertTrue(realms.get(1).contains("name=\"even\""));
- assertTrue(realms.get(2).contains("name=\"two\""));
- assertTrue(realms.get(3).contains("name=\"odd\""));
+ @Test
+ public void exportElements() throws Exception {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+
+ exporter.export(SyncopeConstants.MASTER_DOMAIN, 100, baos,
"AccountPolicy", "Realm");
+
+ String exported = baos.toString(StandardCharsets.UTF_8);
+ assertTrue(StringUtils.isNotBlank(exported));
+
+ List<String> accountPolicies = exported.lines().
+ filter(row -> row.trim().startsWith("<AccountPolicy
")).toList();
+ assertEquals(2, accountPolicies.size());
+
+ checkRealms(exported);
}
}
diff --git
a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/RESTITCase.java
b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/RESTITCase.java
index 60151f3584..f92f1d7a2d 100644
---
a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/RESTITCase.java
+++
b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/RESTITCase.java
@@ -187,15 +187,20 @@ public class RESTITCase extends AbstractITCase {
@Test
public void exportInternalStorageContent() throws IOException {
- Response response = SYNCOPE_SERVICE.exportInternalStorageContent(100);
- assertNotNull(response);
+ Response response = SYNCOPE_SERVICE.exportInternalStorageContent(100,
List.of());
assertEquals(Response.Status.OK.getStatusCode(),
response.getStatusInfo().getStatusCode());
assertTrue(response.getMediaType().toString().startsWith(MediaType.TEXT_XML));
- String contentDisposition =
response.getHeaderString(HttpHeaders.CONTENT_DISPOSITION);
- assertNotNull(contentDisposition);
+
assertNotNull(response.getHeaderString(HttpHeaders.CONTENT_DISPOSITION));
+ assertTrue(response.readEntity(String.class).length() > 1000);
- String configExport = response.readEntity(String.class);
- assertFalse(configExport.isEmpty());
- assertTrue(configExport.length() > 1000);
+ response = SYNCOPE_SERVICE.exportInternalStorageContent(100,
List.of("AccountPolicy", "Realm"));
+ assertEquals(Response.Status.OK.getStatusCode(),
response.getStatusInfo().getStatusCode());
+
assertTrue(response.getMediaType().toString().startsWith(MediaType.TEXT_XML));
+
assertNotNull(response.getHeaderString(HttpHeaders.CONTENT_DISPOSITION));
+
+ String export = response.readEntity(String.class);
+ assertTrue(export.contains("<AccountPolicy "));
+ assertTrue(export.contains("<Realm "));
+ assertFalse(export.contains("<AccessPolicy "));
}
}
diff --git a/src/main/asciidoc/reference-guide/howto/importexport.adoc
b/src/main/asciidoc/reference-guide/howto/importexport.adoc
index bdcf8e1bc4..f38a269e67 100644
--- a/src/main/asciidoc/reference-guide/howto/importexport.adoc
+++ b/src/main/asciidoc/reference-guide/howto/importexport.adoc
@@ -69,10 +69,19 @@ http://curl.haxx.se/[curl^], for example:
....
curl -X GET -u admin:password -o MasterContent.xml \
- http://localhost:9080/syncope/rest/configurations/stream?tableThreshold=100
+ http://localhost:9080/syncope/rest/configurations/stream?threshold=100
....
-where `tableThreshold` indicates the maximum number of rows to take for each
table of internal storage.
+where `threshold` indicates the maximum number of rows to take for each
element of internal storage.
+
+It is possible to specify which element(s) to include in the export:
+
+....
+curl -X GET -u admin:password -o MasterContent.xml \
+
http://localhost:9080/syncope/rest/configurations/stream?elements=Realm&elements=PushPolicy
+....
+
+which will include only `Realm` and `PushPolicy` elements from internal
storage.
==== Import