diff --git a/mdm-frontend/src/app/legacy/datapackagemanagement/resources/dataPackage.resource.js b/mdm-frontend/src/app/legacy/datapackagemanagement/resources/dataPackage.resource.js
index 3f55ec07c7f..386864e4ca8 100644
--- a/mdm-frontend/src/app/legacy/datapackagemanagement/resources/dataPackage.resource.js
+++ b/mdm-frontend/src/app/legacy/datapackagemanagement/resources/dataPackage.resource.js
@@ -25,3 +25,19 @@ angular.module('metadatamanagementApp')
});
}]);
+
+ /**
+ * Method to request the endpoint that downloads all variables of the data package as a DDI-formatted XML file.
+ * We could not put this into the "DataPackageResource"-schema (above), because the URLs would not match.
+ */
+ angular.module('metadatamanagementApp').factory('ExportDdiVariablesResource', ['$http',
+ function($http) {
+ return {
+ exportVariablesAsXml: function(dataPackageId) {
+ return $http.get('api/data-packages/exportDDI/xml/' + dataPackageId).then(function(response) {
+ return response.data;
+ });
+ }
+ }
+ }]);
+
diff --git a/mdm-frontend/src/app/legacy/datapackagemanagement/views/data-package-detail.html.tmpl b/mdm-frontend/src/app/legacy/datapackagemanagement/views/data-package-detail.html.tmpl
index 30049515cb4..7d57fada3a7 100644
--- a/mdm-frontend/src/app/legacy/datapackagemanagement/views/data-package-detail.html.tmpl
+++ b/mdm-frontend/src/app/legacy/datapackagemanagement/views/data-package-detail.html.tmpl
@@ -9,7 +9,7 @@
{{'data-package-management.detail.label.tags' | translate}}:
diff --git a/mdm-frontend/src/app/legacy/ordermanagement/components/data-package-configurator.controller.js b/mdm-frontend/src/app/legacy/ordermanagement/components/data-package-configurator.controller.js
index 9910d52a6d6..95181230c84 100644
--- a/mdm-frontend/src/app/legacy/ordermanagement/components/data-package-configurator.controller.js
+++ b/mdm-frontend/src/app/legacy/ordermanagement/components/data-package-configurator.controller.js
@@ -24,6 +24,8 @@
'$q',
'dataAcquisitionProjectSearchService',
'ElasticSearchClient',
+ 'ExportDdiVariablesResource',
+ 'Principal',
function ($scope,
$rootScope,
$location,
@@ -38,7 +40,8 @@
DataPackageAccessWaysResource, $mdDialog,
DataPackageCitationDialogService,
CurrentDataPackageService,
- DataAcquisitionProjectResource, $q, dataAcquisitionProjectSearchService, ElasticSearchClient) {
+ DataAcquisitionProjectResource, $q, dataAcquisitionProjectSearchService, ElasticSearchClient,
+ ExportDdiVariablesResource, Principal) {
var $ctrl = this;
var initReady = false;
$ctrl.dataPackageIdVersion = {};
@@ -49,6 +52,7 @@
$ctrl.isPreReleased = false;
$ctrl.variableNotAccessible = false;
$ctrl.disabled = false;
+ $ctrl.allowedToExportVariableMetadata = false;
$scope.bowser = $rootScope.bowser;
$ctrl.numberOfShoppingCartProducts = ShoppingCartService.count();
@@ -89,6 +93,7 @@
$ctrl.selectedVersion = $ctrl.dataPackageIdVersion.version;
loadDataPackage($ctrl.dataPackageIdVersion.masterId,
$ctrl.dataPackageIdVersion.version);
+ $ctrl.allowedToExportVariableMetadata = Principal.isAuthenticated();
initReady = true;
}
@@ -390,4 +395,31 @@
}
return true;
}
+
+ /**
+ * Checks if the latest version is selected.
+ * @returns true if the latest version is selected else false
+ */
+ $ctrl.isLatestVersionSelected = function() {
+ return this.selectedVersion
+ && $ctrl.releases
+ && $ctrl.releases.length > 0 ? $ctrl.releases[0].version === this.selectedVersion : false;
+ }
+
+ /**
+ * Exports Variables metadata as DDI Codebook XML.
+ */
+ $ctrl.exportVariables = function() {
+ ExportDdiVariablesResource.exportVariablesAsXml($ctrl.dataPackage.id).then(function(res) {
+ var blob = new Blob([res],{
+ type: "application/xml;charset=utf-8;"
+ });
+ var downloadLink = document.createElement('a');
+ const fileName = 'mdm_export_ddi_variables_' + $ctrl.dataPackage.id.split('$')[0] + '.xml'
+ downloadLink.setAttribute('download', fileName);
+ downloadLink.setAttribute('href', window.URL.createObjectURL(blob));
+ downloadLink.click();
+ $scope.isDownloadingData = false;
+ })
+ }
}]);
diff --git a/mdm-frontend/src/app/legacy/ordermanagement/components/data-package-configurator.html.tmpl b/mdm-frontend/src/app/legacy/ordermanagement/components/data-package-configurator.html.tmpl
index 830ccead602..5418219f905 100644
--- a/mdm-frontend/src/app/legacy/ordermanagement/components/data-package-configurator.html.tmpl
+++ b/mdm-frontend/src/app/legacy/ordermanagement/components/data-package-configurator.html.tmpl
@@ -113,6 +113,16 @@
+
+
+
+ {{'shopping-cart.buttons.export-ddi-variables-tooltip' | translate}}
+
+ {{'shopping-cart.buttons.export-ddi-variables' | translate}}
+
+
diff --git a/mdm-frontend/src/app/legacy/ordermanagement/configuration/translations-de.js b/mdm-frontend/src/app/legacy/ordermanagement/configuration/translations-de.js
index 3b57a1d20dc..201194b1043 100644
--- a/mdm-frontend/src/app/legacy/ordermanagement/configuration/translations-de.js
+++ b/mdm-frontend/src/app/legacy/ordermanagement/configuration/translations-de.js
@@ -128,7 +128,9 @@ angular.module('metadatamanagementApp').config([
'related-publications-tooltip': 'Klicken, um weitere Informationen zu Publikationen zu erhalten.',
'data-package-version-tooltip': 'Klicken, um weitere Informationen zur Version von Datenpaketen zu erhalten.',
'analysis-package-version-tooltip': 'Klicken, um weitere Informationen zur Version von Analysepaketen zu erhalten.',
- 'data-package-access-way-tooltip': 'Klicken, um weitere Informationen zu Zugangswegen zu erhalten.'
+ 'data-package-access-way-tooltip': 'Klicken, um weitere Informationen zu Zugangswegen zu erhalten.',
+ 'export-ddi-variables': 'Variablenmetadaten exportieren',
+ 'export-ddi-variables-tooltip': 'Klicken, um die Variablen-Metadaten als DDI-Codebook-XML herunterzuladen.'
},
'version-info': {
'title': 'Eine Version auswählen',
diff --git a/mdm-frontend/src/app/legacy/ordermanagement/configuration/translations-en.js b/mdm-frontend/src/app/legacy/ordermanagement/configuration/translations-en.js
index 4dbe6f75a8e..4b63b645624 100644
--- a/mdm-frontend/src/app/legacy/ordermanagement/configuration/translations-en.js
+++ b/mdm-frontend/src/app/legacy/ordermanagement/configuration/translations-en.js
@@ -127,7 +127,9 @@ angular.module('metadatamanagementApp').config([
'analysis-package-tooltip': 'Click to get more information about analysis packages',
'related-publications-tooltip': 'Click to get more information about publications',
'analysis-package-version-tooltip': 'Click to get more information about versions of analysis packages',
- 'data-package-access-way-tooltip': 'Click to get more information about access ways'
+ 'data-package-access-way-tooltip': 'Click to get more information about access ways',
+ 'export-ddi-variables': 'Export variable metadata',
+ 'export-ddi-variables-tooltip': 'Click to download the metadata of all variables as a DDI codebook XML.'
},
'version-info': {
'title': 'Select a Version',
diff --git a/mdm-frontend/src/app/legacy/surveymanagement/views/survey-detail.html.tmpl b/mdm-frontend/src/app/legacy/surveymanagement/views/survey-detail.html.tmpl
index bbae6877755..896dc20adc3 100644
--- a/mdm-frontend/src/app/legacy/surveymanagement/views/survey-detail.html.tmpl
+++ b/mdm-frontend/src/app/legacy/surveymanagement/views/survey-detail.html.tmpl
@@ -10,6 +10,14 @@
+
+
+ Daten als XML exportieren
+
+ DDI
+
diff --git a/src/main/java/eu/dzhw/fdz/metadatamanagement/datapackagemanagement/domain/ddicodebook/Catgry.java b/src/main/java/eu/dzhw/fdz/metadatamanagement/datapackagemanagement/domain/ddicodebook/Catgry.java
new file mode 100644
index 00000000000..27fc22794ac
--- /dev/null
+++ b/src/main/java/eu/dzhw/fdz/metadatamanagement/datapackagemanagement/domain/ddicodebook/Catgry.java
@@ -0,0 +1,26 @@
+package eu.dzhw.fdz.metadatamanagement.datapackagemanagement.domain.ddicodebook;
+
+import java.util.List;
+
+import javax.xml.bind.annotation.XmlElement;
+
+import lombok.AllArgsConstructor;
+
+/**
+ * Class representing the DDI catgry element.
+ */
+@AllArgsConstructor
+public class Catgry {
+
+ /**
+ * Constructor needed by JAXB.
+ */
+ public Catgry() {}
+
+ @XmlElement(name = "catValu")
+ String catValu;
+
+ @XmlElement(name = "labl")
+ List labl;
+
+}
diff --git a/src/main/java/eu/dzhw/fdz/metadatamanagement/datapackagemanagement/domain/ddicodebook/Citation.java b/src/main/java/eu/dzhw/fdz/metadatamanagement/datapackagemanagement/domain/ddicodebook/Citation.java
new file mode 100644
index 00000000000..df5224931f5
--- /dev/null
+++ b/src/main/java/eu/dzhw/fdz/metadatamanagement/datapackagemanagement/domain/ddicodebook/Citation.java
@@ -0,0 +1,21 @@
+package eu.dzhw.fdz.metadatamanagement.datapackagemanagement.domain.ddicodebook;
+
+import javax.xml.bind.annotation.XmlElement;
+
+import lombok.AllArgsConstructor;
+
+/**
+ * Class representing the DDI citation element.
+ */
+@AllArgsConstructor
+public class Citation {
+
+ /**
+ * Constructor needed by JAXB.
+ */
+ public Citation() {}
+
+ @XmlElement(name = "titlStmt")
+ TitlStmt titlStmt;
+
+}
diff --git a/src/main/java/eu/dzhw/fdz/metadatamanagement/datapackagemanagement/domain/ddicodebook/CodeBook.java b/src/main/java/eu/dzhw/fdz/metadatamanagement/datapackagemanagement/domain/ddicodebook/CodeBook.java
new file mode 100644
index 00000000000..d68f7c92fff
--- /dev/null
+++ b/src/main/java/eu/dzhw/fdz/metadatamanagement/datapackagemanagement/domain/ddicodebook/CodeBook.java
@@ -0,0 +1,41 @@
+package eu.dzhw.fdz.metadatamanagement.datapackagemanagement.domain.ddicodebook;
+
+import java.util.List;
+
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+
+/**
+ * Class representing the root element codebook of the mapping of the DDI Codebook standard.
+ */
+
+@XmlRootElement(name = "codeBook")
+public class CodeBook {
+
+ /**
+ * Constructor for codebook.
+ * @param stdyDscr the data package description in form of the DDI stdyDscr element.
+ * @param fileDscr the dataset metadata in form of the DDI fileDscr element.
+ * @param dataDscr the variable metadata in form of the DDI dataDscr element.
+ */
+ public CodeBook(StdyDscr stdyDscr, List fileDscr, DataDscr dataDscr) {
+ this.stdyDscr = stdyDscr;
+ this.fileDscr = fileDscr;
+ this.dataDscr = dataDscr;
+ }
+
+ /**
+ * Constructor needed by JAXB.
+ */
+ public CodeBook() {}
+
+ @XmlElement(name = "stdyDscr")
+ private StdyDscr stdyDscr;
+
+ @XmlElement(name = "fileDscr")
+ private List fileDscr;
+
+ @XmlElement(name = "dataDscr")
+ private DataDscr dataDscr;
+
+}
diff --git a/src/main/java/eu/dzhw/fdz/metadatamanagement/datapackagemanagement/domain/ddicodebook/DataDscr.java b/src/main/java/eu/dzhw/fdz/metadatamanagement/datapackagemanagement/domain/ddicodebook/DataDscr.java
new file mode 100644
index 00000000000..2f81233c41c
--- /dev/null
+++ b/src/main/java/eu/dzhw/fdz/metadatamanagement/datapackagemanagement/domain/ddicodebook/DataDscr.java
@@ -0,0 +1,23 @@
+package eu.dzhw.fdz.metadatamanagement.datapackagemanagement.domain.ddicodebook;
+
+import java.util.List;
+
+import javax.xml.bind.annotation.XmlElement;
+
+import lombok.AllArgsConstructor;
+
+/**
+ * Class representing the DDI dataDscr element.
+ */
+@AllArgsConstructor
+public class DataDscr {
+
+ /**
+ * Constructor needed by JAXB.
+ */
+ public DataDscr() {}
+
+ @XmlElement(name = "var")
+ List var;
+
+}
diff --git a/src/main/java/eu/dzhw/fdz/metadatamanagement/datapackagemanagement/domain/ddicodebook/FileDscr.java b/src/main/java/eu/dzhw/fdz/metadatamanagement/datapackagemanagement/domain/ddicodebook/FileDscr.java
new file mode 100644
index 00000000000..fef929c6b55
--- /dev/null
+++ b/src/main/java/eu/dzhw/fdz/metadatamanagement/datapackagemanagement/domain/ddicodebook/FileDscr.java
@@ -0,0 +1,21 @@
+package eu.dzhw.fdz.metadatamanagement.datapackagemanagement.domain.ddicodebook;
+
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlElement;
+
+import lombok.AllArgsConstructor;
+
+/**
+ * Class representing the DDI Codebook fileDscr element.
+ */
+@AllArgsConstructor
+public class FileDscr {
+
+ public FileDscr() {}
+
+ @XmlAttribute(name = "ID")
+ String id;
+
+ @XmlElement(name = "fileTxt")
+ FileTxt fileTxt;
+}
diff --git a/src/main/java/eu/dzhw/fdz/metadatamanagement/datapackagemanagement/domain/ddicodebook/FileTxt.java b/src/main/java/eu/dzhw/fdz/metadatamanagement/datapackagemanagement/domain/ddicodebook/FileTxt.java
new file mode 100644
index 00000000000..933ddb440d8
--- /dev/null
+++ b/src/main/java/eu/dzhw/fdz/metadatamanagement/datapackagemanagement/domain/ddicodebook/FileTxt.java
@@ -0,0 +1,24 @@
+package eu.dzhw.fdz.metadatamanagement.datapackagemanagement.domain.ddicodebook;
+
+import javax.xml.bind.annotation.XmlElement;
+
+import lombok.AllArgsConstructor;
+
+/**
+ * Class representing the DDI fileTxt element.
+ */
+@AllArgsConstructor
+public class FileTxt {
+
+ /**
+ * Constructor needed by JAXB.
+ */
+ public FileTxt() {}
+
+ @XmlElement(name = "fileName")
+ String fileName;
+
+ @XmlElement(name = "fileCont")
+ TextElement fileCont;
+
+}
diff --git a/src/main/java/eu/dzhw/fdz/metadatamanagement/datapackagemanagement/domain/ddicodebook/LanguageEnum.java b/src/main/java/eu/dzhw/fdz/metadatamanagement/datapackagemanagement/domain/ddicodebook/LanguageEnum.java
new file mode 100644
index 00000000000..e38c80a4729
--- /dev/null
+++ b/src/main/java/eu/dzhw/fdz/metadatamanagement/datapackagemanagement/domain/ddicodebook/LanguageEnum.java
@@ -0,0 +1,22 @@
+package eu.dzhw.fdz.metadatamanagement.datapackagemanagement.domain.ddicodebook;
+
+/**
+ * Enum representing available language abbreviations.
+ */
+public enum LanguageEnum {
+ de("de"), en("en");
+
+ /**
+ * The language string.
+ */
+ public final String languageString;
+
+ /**
+ * Construct the enum.
+ *
+ * @param languageString The language string.
+ */
+ LanguageEnum(String languageString) {
+ this.languageString = languageString;
+ }
+}
diff --git a/src/main/java/eu/dzhw/fdz/metadatamanagement/datapackagemanagement/domain/ddicodebook/StdyDscr.java b/src/main/java/eu/dzhw/fdz/metadatamanagement/datapackagemanagement/domain/ddicodebook/StdyDscr.java
new file mode 100644
index 00000000000..302ff532836
--- /dev/null
+++ b/src/main/java/eu/dzhw/fdz/metadatamanagement/datapackagemanagement/domain/ddicodebook/StdyDscr.java
@@ -0,0 +1,21 @@
+package eu.dzhw.fdz.metadatamanagement.datapackagemanagement.domain.ddicodebook;
+
+import javax.xml.bind.annotation.XmlElement;
+
+import lombok.AllArgsConstructor;
+
+/**
+ * Class representing the DDI stdyDscr element.
+ */
+@AllArgsConstructor
+public class StdyDscr {
+
+ /**
+ * Constructor needed by JAXB.
+ */
+ public StdyDscr() {}
+
+ @XmlElement(name = "citation")
+ Citation citation;
+
+}
diff --git a/src/main/java/eu/dzhw/fdz/metadatamanagement/datapackagemanagement/domain/ddicodebook/TextElement.java b/src/main/java/eu/dzhw/fdz/metadatamanagement/datapackagemanagement/domain/ddicodebook/TextElement.java
new file mode 100644
index 00000000000..67a9e86880f
--- /dev/null
+++ b/src/main/java/eu/dzhw/fdz/metadatamanagement/datapackagemanagement/domain/ddicodebook/TextElement.java
@@ -0,0 +1,37 @@
+package eu.dzhw.fdz.metadatamanagement.datapackagemanagement.domain.ddicodebook;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlValue;
+
+import lombok.AllArgsConstructor;
+
+/**
+ * General element for a language annotated XML element containing a string,
+ * e.g. labels (labl in DDI standard).
+ */
+@AllArgsConstructor
+@XmlAccessorType(XmlAccessType.NONE)
+public class TextElement {
+
+ /**
+ * Constructor needed by JAXB.
+ */
+ public TextElement() {}
+
+ @XmlAttribute(name = "xml:lang")
+ private LanguageEnum lang;
+
+ @XmlValue
+ private String value;
+
+ public String getValue() {
+ return value;
+ }
+
+ public void setValue(String value) {
+ this.value = value;
+ }
+
+}
diff --git a/src/main/java/eu/dzhw/fdz/metadatamanagement/datapackagemanagement/domain/ddicodebook/TitlStmt.java b/src/main/java/eu/dzhw/fdz/metadatamanagement/datapackagemanagement/domain/ddicodebook/TitlStmt.java
new file mode 100644
index 00000000000..365e7008762
--- /dev/null
+++ b/src/main/java/eu/dzhw/fdz/metadatamanagement/datapackagemanagement/domain/ddicodebook/TitlStmt.java
@@ -0,0 +1,24 @@
+package eu.dzhw.fdz.metadatamanagement.datapackagemanagement.domain.ddicodebook;
+
+import javax.xml.bind.annotation.XmlElement;
+
+import lombok.AllArgsConstructor;
+
+/**
+ * Class representing the DDI titlStmt element.
+ */
+@AllArgsConstructor
+public class TitlStmt {
+
+ /**
+ * Constructor needed by JAXB.
+ */
+ public TitlStmt() {}
+
+ @XmlElement(name = "titl")
+ TextElement titl;
+
+ @XmlElement(name = "parTitl")
+ TextElement parTitle;
+
+}
diff --git a/src/main/java/eu/dzhw/fdz/metadatamanagement/datapackagemanagement/domain/ddicodebook/Var.java b/src/main/java/eu/dzhw/fdz/metadatamanagement/datapackagemanagement/domain/ddicodebook/Var.java
new file mode 100644
index 00000000000..cabc51cb15d
--- /dev/null
+++ b/src/main/java/eu/dzhw/fdz/metadatamanagement/datapackagemanagement/domain/ddicodebook/Var.java
@@ -0,0 +1,39 @@
+package eu.dzhw.fdz.metadatamanagement.datapackagemanagement.domain.ddicodebook;
+
+import java.util.List;
+
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlElement;
+
+import lombok.AllArgsConstructor;
+
+/**
+ * Class representing the DDI Codebook var element.
+ */
+@AllArgsConstructor
+public class Var {
+
+ /**
+ * Constructor needed by JAXB.
+ */
+ public Var() {}
+
+ @XmlAttribute(name = "name")
+ String name;
+
+ @XmlAttribute(name = "files")
+ String files;
+
+ @XmlElement(name = "labl")
+ List labl;
+
+ @XmlElement(name = "qstn")
+ List qstn;
+
+ @XmlElement(name = "txt")
+ List txt;
+
+ @XmlElement(name = "catgry")
+ List catgry;
+
+}
diff --git a/src/main/java/eu/dzhw/fdz/metadatamanagement/datapackagemanagement/domain/ddicodebook/package-info.java b/src/main/java/eu/dzhw/fdz/metadatamanagement/datapackagemanagement/domain/ddicodebook/package-info.java
new file mode 100644
index 00000000000..3c18219797c
--- /dev/null
+++ b/src/main/java/eu/dzhw/fdz/metadatamanagement/datapackagemanagement/domain/ddicodebook/package-info.java
@@ -0,0 +1,17 @@
+/**
+ * Configuration for JAXB.
+ */
+
+@XmlSchema(
+ xmlns = {
+ @XmlNs(prefix = "", namespaceURI = "ddi:codebook:2_5"),
+ @XmlNs(prefix = "xs", namespaceURI = "http://www.w3.org/2001/XMLSchema")
+ },
+ namespace = "ddi:codebook:2_5",
+ elementFormDefault = XmlNsForm.QUALIFIED)
+
+package eu.dzhw.fdz.metadatamanagement.datapackagemanagement.domain.ddicodebook;
+
+import javax.xml.bind.annotation.XmlNs;
+import javax.xml.bind.annotation.XmlNsForm;
+import javax.xml.bind.annotation.XmlSchema;
diff --git a/src/main/java/eu/dzhw/fdz/metadatamanagement/datapackagemanagement/rest/ExportDdiVariablesResourceController.java b/src/main/java/eu/dzhw/fdz/metadatamanagement/datapackagemanagement/rest/ExportDdiVariablesResourceController.java
new file mode 100644
index 00000000000..5886f086044
--- /dev/null
+++ b/src/main/java/eu/dzhw/fdz/metadatamanagement/datapackagemanagement/rest/ExportDdiVariablesResourceController.java
@@ -0,0 +1,48 @@
+package eu.dzhw.fdz.metadatamanagement.datapackagemanagement.rest;
+
+import javax.persistence.PersistenceException;
+
+import eu.dzhw.fdz.metadatamanagement.datapackagemanagement.service.DataPackageDdiService;
+import eu.dzhw.fdz.metadatamanagement.usermanagement.security.AuthoritiesConstants;
+import lombok.RequiredArgsConstructor;
+
+import org.springframework.http.HttpStatus;
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
+import org.springframework.security.access.annotation.Secured;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+/**
+ * Controller for exporting variable metadata as DDI codebook.
+ */
+@Controller
+@RequestMapping("/api")
+@RequiredArgsConstructor
+public class ExportDdiVariablesResourceController {
+
+ private final DataPackageDdiService dataPackageDdiService;
+
+ /**
+ * Exports all variables metadata belonging to the given dataPackage ID as DDI Codebook XML file.
+ *
+ * @return an XML file
+ */
+ @GetMapping(value = "/data-packages/exportDDI/xml/{dataPackageId:.+}", produces = MediaType.APPLICATION_XML_VALUE)
+ @ResponseBody
+ @Secured(value = {AuthoritiesConstants.PUBLISHER, AuthoritiesConstants.DATA_PROVIDER})
+ public ResponseEntity> exportVariablesAsXml(@PathVariable String dataPackageId) {
+ ResponseEntity> response = new ResponseEntity<>(null, null, HttpStatus.NOT_FOUND);
+ try {
+ response = this.dataPackageDdiService.exportDdiVariablesAsXml(dataPackageId);
+ } catch (PersistenceException ex) {
+ return response;
+ }
+
+ return response;
+ }
+
+}
diff --git a/src/main/java/eu/dzhw/fdz/metadatamanagement/datapackagemanagement/service/DataPackageDdiService.java b/src/main/java/eu/dzhw/fdz/metadatamanagement/datapackagemanagement/service/DataPackageDdiService.java
new file mode 100644
index 00000000000..450eb7e67b8
--- /dev/null
+++ b/src/main/java/eu/dzhw/fdz/metadatamanagement/datapackagemanagement/service/DataPackageDdiService.java
@@ -0,0 +1,276 @@
+package eu.dzhw.fdz.metadatamanagement.datapackagemanagement.service;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBException;
+import javax.xml.bind.Marshaller;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.google.gson.Gson;
+import eu.dzhw.fdz.metadatamanagement.datapackagemanagement.domain.DataPackage;
+import eu.dzhw.fdz.metadatamanagement.datapackagemanagement.domain.ddicodebook.Catgry;
+import eu.dzhw.fdz.metadatamanagement.datapackagemanagement.domain.ddicodebook.Citation;
+import eu.dzhw.fdz.metadatamanagement.datapackagemanagement.domain.ddicodebook.CodeBook;
+import eu.dzhw.fdz.metadatamanagement.datapackagemanagement.domain.ddicodebook.DataDscr;
+import eu.dzhw.fdz.metadatamanagement.datapackagemanagement.domain.ddicodebook.FileDscr;
+import eu.dzhw.fdz.metadatamanagement.datapackagemanagement.domain.ddicodebook.FileTxt;
+import eu.dzhw.fdz.metadatamanagement.datapackagemanagement.domain.ddicodebook.LanguageEnum;
+import eu.dzhw.fdz.metadatamanagement.datapackagemanagement.domain.ddicodebook.StdyDscr;
+import eu.dzhw.fdz.metadatamanagement.datapackagemanagement.domain.ddicodebook.TextElement;
+import eu.dzhw.fdz.metadatamanagement.datapackagemanagement.domain.ddicodebook.TitlStmt;
+import eu.dzhw.fdz.metadatamanagement.datapackagemanagement.domain.ddicodebook.Var;
+import eu.dzhw.fdz.metadatamanagement.searchmanagement.documents.DataPackageSearchDocument;
+import eu.dzhw.fdz.metadatamanagement.searchmanagement.documents.DataSetSubDocument;
+import eu.dzhw.fdz.metadatamanagement.searchmanagement.documents.QuestionSearchDocument;
+import eu.dzhw.fdz.metadatamanagement.searchmanagement.documents.VariableSearchDocument;
+import eu.dzhw.fdz.metadatamanagement.searchmanagement.documents.VariableSubDocument;
+import eu.dzhw.fdz.metadatamanagement.variablemanagement.domain.Missing;
+import eu.dzhw.fdz.metadatamanagement.variablemanagement.domain.ScaleLevels;
+import eu.dzhw.fdz.metadatamanagement.variablemanagement.domain.ValidResponse;
+import eu.dzhw.fdz.metadatamanagement.variablemanagement.domain.projections.RelatedQuestionSubDocumentProjection;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.elasticsearch.ElasticsearchException;
+import org.elasticsearch.action.search.SearchRequest;
+import org.elasticsearch.action.search.SearchResponse;
+import org.elasticsearch.client.RequestOptions;
+import org.elasticsearch.client.RestHighLevelClient;
+import org.elasticsearch.index.query.QueryBuilders;
+import org.elasticsearch.search.SearchHit;
+import org.elasticsearch.search.builder.SearchSourceBuilder;
+
+import org.springframework.core.io.ByteArrayResource;
+import org.springframework.data.rest.core.annotation.RepositoryEventHandler;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.stereotype.Service;
+
+/**
+ * Service for construction DDI codebook metadata for all variables of a {@link DataPackage}.
+ *
+ * @author Theresa Möller
+ * @since Sep 2024
+ */
+@Service
+@RepositoryEventHandler
+@RequiredArgsConstructor
+@Slf4j
+public class DataPackageDdiService {
+
+ private final RestHighLevelClient client;
+
+ private final Gson gson;
+
+ /**
+ * Exports all variables metadata belonging to a given data package according to the DDI Codebook standard.
+ *
+ * @param dataPackageId the ID of the study
+ * @return DDI metadata as XML
+ */
+ public ResponseEntity> exportDdiVariablesAsXml(String dataPackageId) {
+ try {
+ CodeBook variableMetadata = this.getDdiVariablesMetadata(dataPackageId);
+ JAXBContext context = JAXBContext.newInstance(CodeBook.class);
+ Marshaller mar = context.createMarshaller();
+ mar.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
+ mar.setProperty(Marshaller.JAXB_SCHEMA_LOCATION,
+ "http://www.ddialliance.org/Specification/DDI-Codebook/2.5/XMLSchema/codebook.xsd");
+ ByteArrayOutputStream res = new ByteArrayOutputStream();
+ mar.marshal(variableMetadata, res);
+ ByteArrayResource resource = new ByteArrayResource(res.toByteArray());
+ HttpHeaders headers = new HttpHeaders();
+ headers.add("Content-Disposition", "attachment; filename=Variables_DDI_MDM_Export.xml");
+ return ResponseEntity.ok()
+ .headers(headers)
+ .body(resource);
+ } catch (JAXBException | JsonProcessingException ex) {
+ log.error("Error generating XML: " + ex);
+ return new ResponseEntity<>(null, null, HttpStatus.NOT_FOUND);
+ }
+ }
+
+ /**
+ * Collects variables metadata according to DDI Codebook standard.
+ *
+ * @return the metadata
+ */
+ private CodeBook getDdiVariablesMetadata(String dataPackageId) throws JsonProcessingException {
+ // get Data
+ SearchRequest dataPackageRequest = new SearchRequest();
+ SearchSourceBuilder builderSurveys = new SearchSourceBuilder();
+ builderSurveys.query(QueryBuilders.termsQuery("id", dataPackageId));
+ dataPackageRequest.source(builderSurveys);
+ dataPackageRequest.indices("data_packages");
+
+ try {
+ SearchResponse surveyResponse = client.search(dataPackageRequest, RequestOptions.DEFAULT);
+ List hits = Arrays.asList(surveyResponse.getHits().getHits());
+ if (hits.size() != 1) {
+ throw new ElasticsearchException(
+ String.format("Expected one data package for id '%s', but found %d", dataPackageId, hits.size()));
+ }
+ DataPackageSearchDocument dataPackageDoc = gson.fromJson(
+ hits.get(0).getSourceAsString(), DataPackageSearchDocument.class);
+ if (dataPackageDoc.getRelease() == null
+ || (dataPackageDoc.getRelease() != null && dataPackageDoc.getRelease().getIsPreRelease())) {
+ throw new ElasticsearchException(
+ String.format("DDI codebook export failed. Can only export released data packages. "
+ + "Data package with id '%s' is not released.", dataPackageDoc.getId())
+ );
+ }
+
+ StdyDscr stdyDscr = this.getDdiStdyDscr(dataPackageDoc);
+ List fileDscrList = new ArrayList<>();
+ for (DataSetSubDocument dataset : dataPackageDoc.getDataSets()) {
+ fileDscrList.add(this.getDdiFileDsrc(dataset));
+ }
+
+ List varList = new ArrayList<>();
+ for (VariableSubDocument variable : dataPackageDoc.getVariables()) {
+ varList.add(this.getDdiVar(variable));
+ }
+ DataDscr dataDscr = new DataDscr(varList);
+ CodeBook codeBook = new CodeBook(stdyDscr, fileDscrList, dataDscr);
+
+ return codeBook;
+
+ } catch (IOException e) {
+ log.error("An error occurred while querying the ES. ", e);
+ }
+ return null;
+ }
+
+ /**
+ * Create the DDI var Element with data from the variable, and its related questions.
+ *
+ * @return the var element
+ */
+ private Var getDdiVar(VariableSubDocument variableDoc) {
+ List varLablList = new ArrayList();
+ varLablList.add(new TextElement(LanguageEnum.de, variableDoc.getLabel().getDe()));
+ varLablList.add(new TextElement(LanguageEnum.en, variableDoc.getLabel().getEn()));
+ List qstnList = new ArrayList();
+ if (variableDoc.getRelatedQuestions() != null && variableDoc.getRelatedQuestions().size() > 0) {
+ for (RelatedQuestionSubDocumentProjection relQuest : variableDoc.getRelatedQuestions()) {
+ SearchRequest questionRequest = new SearchRequest();
+ SearchSourceBuilder builder = new SearchSourceBuilder();
+ builder.query(QueryBuilders.termsQuery("id", relQuest.getQuestionId()));
+ questionRequest.source(builder);
+ questionRequest.indices("questions");
+ try {
+ SearchResponse questionResponse = client.search(questionRequest, RequestOptions.DEFAULT);
+ List hits = Arrays.asList(questionResponse.getHits().getHits());
+ if (hits.size() == 0) {
+ throw new ElasticsearchException(
+ String.format("Could not find question for id '%s'", relQuest.getQuestionId()));
+ }
+ for (SearchHit hit : hits) {
+ QuestionSearchDocument relatedQuestion = gson.fromJson(
+ hit.getSourceAsString(), QuestionSearchDocument.class);
+ if (relatedQuestion.getQuestionText() != null && relatedQuestion.getQuestionText().getDe() != null) {
+ qstnList.add(new TextElement(LanguageEnum.de, relatedQuestion.getQuestionText().getDe()));
+ }
+ if (relatedQuestion.getQuestionText() != null && relatedQuestion.getQuestionText().getEn() != null) {
+ qstnList.add(new TextElement(LanguageEnum.en, relatedQuestion.getQuestionText().getEn()));
+ }
+ }
+ } catch (IOException e) {
+ log.error("An exception occurred querying the questions index. ", e);
+ }
+ }
+ }
+
+ SearchRequest variableRequest = new SearchRequest();
+ SearchSourceBuilder builderVar = new SearchSourceBuilder();
+ builderVar.query(QueryBuilders.termsQuery("id", variableDoc.getId()));
+ variableRequest.source(builderVar);
+ variableRequest.indices("variables");
+ List catgryList = new ArrayList<>();
+ List txtList = new ArrayList<>();
+ try {
+ SearchResponse variableResponse = client.search(variableRequest, RequestOptions.DEFAULT);
+ List hits = Arrays.asList(variableResponse.getHits().getHits());
+ if (hits.size() == 0) {
+ throw new ElasticsearchException(
+ String.format("Could not find variable for id '%s'", variableDoc.getId()));
+ }
+ for (SearchHit hit : hits) {
+ VariableSearchDocument varDoc = gson.fromJson(
+ hit.getSourceAsString(), VariableSearchDocument.class);
+ if (varDoc.getAnnotations() != null && varDoc.getAnnotations().getDe() != null) {
+ txtList.add(new TextElement(LanguageEnum.de, varDoc.getAnnotations().getDe()));
+ }
+ if (varDoc.getAnnotations() != null && varDoc.getAnnotations().getEn() != null) {
+ txtList.add(new TextElement(LanguageEnum.en, varDoc.getAnnotations().getEn()));
+ }
+ if ((varDoc.getScaleLevel().equals(ScaleLevels.NOMINAL) || varDoc.getScaleLevel().equals(ScaleLevels.ORDINAL))
+ && varDoc.getDistribution() != null
+ && varDoc.getDistribution().getValidResponses() != null) {
+ for (ValidResponse validResponse : varDoc.getDistribution().getValidResponses()) {
+ String catValu = validResponse.getValue();
+ List catLablList = new ArrayList<>();
+ if (validResponse.getLabel() != null && validResponse.getLabel().getDe() != null) {
+ catLablList.add(new TextElement(LanguageEnum.de, validResponse.getLabel().getDe()));
+ }
+ if (validResponse.getLabel() != null && validResponse.getLabel().getEn() != null) {
+ catLablList.add(new TextElement(LanguageEnum.en, validResponse.getLabel().getEn()));
+ }
+ catgryList.add(new Catgry(catValu, catLablList));
+ }
+ // missing values
+ if (varDoc.getDistribution() != null && varDoc.getDistribution().getMissings() != null) {
+ for (Missing missing : varDoc.getDistribution().getMissings()) {
+ String catValu = missing.getCode();
+ List catLablList = new ArrayList<>();
+ if (missing.getLabel() != null && missing.getLabel().getDe() != null) {
+ catLablList.add(new TextElement(LanguageEnum.de, missing.getLabel().getDe()));
+ }
+ if (missing.getLabel() != null && missing.getLabel().getEn() != null) {
+ catLablList.add(new TextElement(LanguageEnum.en, missing.getLabel().getEn()));
+ }
+ catgryList.add(new Catgry(catValu, catLablList));
+ }
+ }
+ }
+ }
+ } catch (IOException e) {
+ log.error("An exception occurred querying the variables index. ", e);
+ }
+ String name = variableDoc.getId().split("\\$")[0];
+ String files = variableDoc.getDataSetId().split("\\$")[0];
+ return new Var(name, files, varLablList,
+ qstnList.size() > 0 ? qstnList : null,
+ txtList.size() > 0 ? txtList : null,
+ catgryList);
+ }
+
+ /**
+ * Create the DDI element fileDscr with data from the datasets of the data package.
+ *
+ * @return the fileDscr element
+ */
+ private FileDscr getDdiFileDsrc(DataSetSubDocument dataset) {
+ String id = dataset.getId().split("\\$")[0];
+ TextElement fileCont = new TextElement(LanguageEnum.de, dataset.getDescription().getDe());
+ FileTxt fileTxt = new FileTxt(id, fileCont);
+ return new FileDscr(id, fileTxt);
+ }
+
+ /**
+ * Creates the DDI element stdyDscr with data from the data package.
+ *
+ * @return the stdyDscr element
+ */
+ private StdyDscr getDdiStdyDscr(DataPackageSearchDocument doc) {
+ TextElement titl = new TextElement(LanguageEnum.de, doc.getTitle().getDe());
+ TextElement parTitl = new TextElement(LanguageEnum.en, doc.getTitle().getEn());
+ Citation citation = new Citation(new TitlStmt(titl, parTitl));
+ return new StdyDscr(citation);
+ }
+}
diff --git a/src/main/java/eu/dzhw/fdz/metadatamanagement/datapackagemanagement/service/DataPackageManagementService.java b/src/main/java/eu/dzhw/fdz/metadatamanagement/datapackagemanagement/service/DataPackageManagementService.java
index aacef3e7ae5..59ee928a17b 100644
--- a/src/main/java/eu/dzhw/fdz/metadatamanagement/datapackagemanagement/service/DataPackageManagementService.java
+++ b/src/main/java/eu/dzhw/fdz/metadatamanagement/datapackagemanagement/service/DataPackageManagementService.java
@@ -36,6 +36,7 @@
import eu.dzhw.fdz.metadatamanagement.usermanagement.security.AuthoritiesConstants;
import eu.dzhw.fdz.metadatamanagement.variablemanagement.domain.Variable;
import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
/**
* Service for managing the domain object/aggregate {@link DataPackage}.
@@ -45,6 +46,7 @@
@Service
@RepositoryEventHandler
@RequiredArgsConstructor
+@Slf4j
public class DataPackageManagementService implements CrudService {
private final DataPackageRepository dataPackageRepository;