This is an automated email from the ASF dual-hosted git repository.

ilgrosso pushed a commit to branch 4_0_X
in repository https://gitbox.apache.org/repos/asf/syncope.git


The following commit(s) were added to refs/heads/4_0_X by this push:
     new 5344634c36 [SYNCOPE-1621] Allow to optionally select which element(s) 
to export
5344634c36 is described below

commit 5344634c36f9a966c6515eee756669810a6b6053
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
 


Reply via email to