From 9f48fce6529f106d8b892e6e06ce11ceb10281cc Mon Sep 17 00:00:00 2001
From: Martin Weise <martin.weise@tuwien.ac.at>
Date: Wed, 19 Mar 2025 11:51:51 +0100
Subject: [PATCH 1/4] Refactored DOI WIP

Signed-off-by: Martin Weise <martin.weise@tuwien.ac.at>
---
 dbrepo-metadata-db/migration/16/update_id.sql |  11 +
 .../at/tuwien/api/doi/AffiliationDto.java     |  20 +
 .../java/at/tuwien/api/doi/AuthorDto.java     |  35 ++
 .../main/java/at/tuwien/api/doi/DoiDto.java   |  82 ++++
 .../java/at/tuwien/api/doi/LicenseDto.java    |  32 ++
 .../main/java/at/tuwien/api/doi/LinkDto.java  |  35 ++
 .../java/at/tuwien/api/doi/ReferenceDto.java  |  55 +++
 .../java/at/tuwien/api/doi/ResourceDto.java   |  20 +
 .../api/doi/ResourceRepresentationDto.java    |  20 +
 .../tuwien/api/doi/TimeRepresentationDto.java |  33 ++
 .../java/at/tuwien/mapper/MetadataMapper.java |   1 +
 .../src/main/resources/application.yml        |   1 +
 ...Test.java => CrossRefGatewayUnitTest.java} |  16 +-
 .../at/tuwien/gateway/DoiGatewayUnitTest.java |  73 ++++
 .../service/MetadataServiceUnitTest.java      |   4 +-
 .../src/test/resources/doi/database.json      |  70 +++
 .../src/test/resources/doi/dataset.json       |  25 ++
 .../test/resources/doi/journal-article.json   | 403 ++++++++++++++++++
 .../resources/doi/proceedings-article.json    | 320 ++++++++++++++
 .../java/at/tuwien/config/GatewayConfig.java  |  17 +
 ...teway.java => CrossRefServiceGateway.java} |   2 +-
 .../at/tuwien/gateway/DoiServiceGateway.java  |   8 +
 ...l.java => CrossRefServiceGatewayImpl.java} |  20 +-
 .../gateway/impl/DoiServiceGatewayImpl.java   |  43 ++
 .../service/impl/MetadataServiceImpl.java     |  10 +-
 25 files changed, 1328 insertions(+), 28 deletions(-)
 create mode 100644 dbrepo-metadata-db/migration/16/update_id.sql
 create mode 100644 dbrepo-metadata-service/api/src/main/java/at/tuwien/api/doi/AffiliationDto.java
 create mode 100644 dbrepo-metadata-service/api/src/main/java/at/tuwien/api/doi/AuthorDto.java
 create mode 100644 dbrepo-metadata-service/api/src/main/java/at/tuwien/api/doi/DoiDto.java
 create mode 100644 dbrepo-metadata-service/api/src/main/java/at/tuwien/api/doi/LicenseDto.java
 create mode 100644 dbrepo-metadata-service/api/src/main/java/at/tuwien/api/doi/LinkDto.java
 create mode 100644 dbrepo-metadata-service/api/src/main/java/at/tuwien/api/doi/ReferenceDto.java
 create mode 100644 dbrepo-metadata-service/api/src/main/java/at/tuwien/api/doi/ResourceDto.java
 create mode 100644 dbrepo-metadata-service/api/src/main/java/at/tuwien/api/doi/ResourceRepresentationDto.java
 create mode 100644 dbrepo-metadata-service/api/src/main/java/at/tuwien/api/doi/TimeRepresentationDto.java
 rename dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/gateway/{CrossrefGatewayUnitTest.java => CrossRefGatewayUnitTest.java} (79%)
 create mode 100644 dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/gateway/DoiGatewayUnitTest.java
 create mode 100644 dbrepo-metadata-service/rest-service/src/test/resources/doi/database.json
 create mode 100644 dbrepo-metadata-service/rest-service/src/test/resources/doi/dataset.json
 create mode 100644 dbrepo-metadata-service/rest-service/src/test/resources/doi/journal-article.json
 create mode 100644 dbrepo-metadata-service/rest-service/src/test/resources/doi/proceedings-article.json
 rename dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/{CrossrefGateway.java => CrossRefServiceGateway.java} (92%)
 create mode 100644 dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/DoiServiceGateway.java
 rename dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/impl/{CrossrefGatewayImpl.java => CrossRefServiceGatewayImpl.java} (56%)
 create mode 100644 dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/impl/DoiServiceGatewayImpl.java

diff --git a/dbrepo-metadata-db/migration/16/update_id.sql b/dbrepo-metadata-db/migration/16/update_id.sql
new file mode 100644
index 0000000000..a3f161cc2a
--- /dev/null
+++ b/dbrepo-metadata-db/migration/16/update_id.sql
@@ -0,0 +1,11 @@
+SET FOREIGN_KEY_CHECKS = 0;
+BEGIN;
+UPDATE mdb_users SET id = :old_id WHERE id = :new_id;
+UPDATE mdb_have_access SET user_id = :old_id WHERE user_id = :new_id;
+UPDATE mdb_databases SET owned_by = :old_id WHERE owned_by = :new_id;
+UPDATE mdb_databases SET contact_person = :old_id WHERE contact_person = :new_id;
+UPDATE mdb_tables SET owned_by = :old_id WHERE owned_by = :new_id;
+UPDATE mdb_view SET owned_by = :old_id WHERE owned_by = :new_id;
+UPDATE mdb_identifiers SET owned_by = :old_id WHERE owned_by = :new_id;
+COMMIT;
+SET FOREIGN_KEY_CHECKS = 1;
\ No newline at end of file
diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/doi/AffiliationDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/doi/AffiliationDto.java
new file mode 100644
index 0000000000..807c03f48d
--- /dev/null
+++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/doi/AffiliationDto.java
@@ -0,0 +1,20 @@
+package at.tuwien.api.doi;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.*;
+import lombok.extern.jackson.Jacksonized;
+
+@Getter
+@Setter
+@Builder
+@EqualsAndHashCode
+@NoArgsConstructor
+@AllArgsConstructor
+@Jacksonized
+@ToString
+public class AffiliationDto {
+
+    @Schema(example = "ISE, TU Wien, Data Science Research Unit, Vienna, Austria")
+    private String name;
+
+}
diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/doi/AuthorDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/doi/AuthorDto.java
new file mode 100644
index 0000000000..8f8bbb61ff
--- /dev/null
+++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/doi/AuthorDto.java
@@ -0,0 +1,35 @@
+package at.tuwien.api.doi;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.*;
+import lombok.extern.jackson.Jacksonized;
+
+import java.util.List;
+
+@Getter
+@Setter
+@Builder
+@EqualsAndHashCode
+@NoArgsConstructor
+@AllArgsConstructor
+@Jacksonized
+@ToString
+public class AuthorDto {
+
+    @Schema(example = "Weise")
+    private String family;
+
+    @Schema(example = "Martin")
+    private String given;
+
+    @JsonProperty("ORCID")
+    @Schema(example = "http://orcid.org/0000-0003-4216-302X")
+    private String orcid;
+
+    @Schema(example = "first")
+    private String sequence;
+
+    private List<AffiliationDto> affiliation;
+
+}
diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/doi/DoiDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/doi/DoiDto.java
new file mode 100644
index 0000000000..af0cd5bcc6
--- /dev/null
+++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/doi/DoiDto.java
@@ -0,0 +1,82 @@
+package at.tuwien.api.doi;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.NotNull;
+import lombok.*;
+import lombok.extern.jackson.Jacksonized;
+
+import java.util.List;
+
+@Getter
+@Setter
+@Builder
+@EqualsAndHashCode
+@NoArgsConstructor
+@AllArgsConstructor
+@Jacksonized
+@ToString
+public class DoiDto {
+
+    @NotNull
+    @Schema(example = "https://doi.org/10.5334/dsj-2022-004")
+    private String id;
+
+    @NotNull
+    private TimeRepresentationDto indexed;
+
+    private TimeRepresentationDto deposited;
+
+    private TimeRepresentationDto issued;
+
+    private TimeRepresentationDto published;
+
+    @JsonProperty("DOI")
+    @Schema(example = "10.5334/dsj-2022-004")
+    private String doi;
+
+    @NotNull
+    @Schema(example = "dataset")
+    private String type;
+
+    private List<AuthorDto> author;
+
+    @Schema(example = "Crossref")
+    private String source;
+
+    @Schema(example = "DBRepo: A Data Repository System for Research Data in Databases")
+    private String title;
+
+    @Schema(example = "10.1109")
+    private String prefix;
+
+    @Schema(example = "21")
+    private String volume;
+
+    @JsonProperty("is-referenced-by-count")
+    @Schema(example = "0")
+    private Integer isReferencedByCount;
+
+    @JsonProperty("reference-count")
+    @Schema(example = "28")
+    private Integer referenceCount;
+
+    @Schema(example = "IEEE")
+    private String publisher;
+
+    @Schema(example = "322-331")
+    private String page;
+
+    private String member;
+
+    @Schema(example = "2024 IEEE International Conference on Big Data (BigData)")
+    private String event;
+
+    private List<ReferenceDto> reference;
+
+    private Integer score;
+
+    @JsonProperty("URL")
+    private String url;
+
+}
diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/doi/LicenseDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/doi/LicenseDto.java
new file mode 100644
index 0000000000..32f5ffcd2a
--- /dev/null
+++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/doi/LicenseDto.java
@@ -0,0 +1,32 @@
+package at.tuwien.api.doi;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.*;
+import lombok.extern.jackson.Jacksonized;
+
+@Getter
+@Setter
+@Builder
+@EqualsAndHashCode
+@NoArgsConstructor
+@AllArgsConstructor
+@Jacksonized
+@ToString
+public class LicenseDto {
+
+    private TimeRepresentationDto start;
+
+    @JsonProperty("content-version")
+    @Schema(example = "stm-asf")
+    private String contentVersion;
+
+    @JsonProperty("delay-in-days")
+    @Schema(example = "0")
+    private Integer delayInDays;
+
+    @JsonProperty("URL")
+    @Schema(example = "https://doi.org/10.15223/policy-029")
+    private String url;
+
+}
diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/doi/LinkDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/doi/LinkDto.java
new file mode 100644
index 0000000000..5f70696091
--- /dev/null
+++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/doi/LinkDto.java
@@ -0,0 +1,35 @@
+package at.tuwien.api.doi;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.NotNull;
+import lombok.*;
+import lombok.extern.jackson.Jacksonized;
+
+@Getter
+@Setter
+@Builder
+@EqualsAndHashCode
+@NoArgsConstructor
+@AllArgsConstructor
+@Jacksonized
+@ToString
+public class LinkDto {
+
+    @JsonProperty("URL")
+    @Schema(example = "http://xplorestaging.ieee.org/ielx8/10824975/10824942/10825401.pdf?arnumber=10825401")
+    private String url;
+
+    @JsonProperty("content-type")
+    @Schema(example = "unspecified")
+    private String contentType;
+
+    @JsonProperty("content-version")
+    @Schema(example = "vor")
+    private String contentVersion;
+
+    @JsonProperty("intended-application")
+    @Schema(example = "similarity-checking")
+    private String intendedApplication;
+
+}
diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/doi/ReferenceDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/doi/ReferenceDto.java
new file mode 100644
index 0000000000..9458c0f919
--- /dev/null
+++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/doi/ReferenceDto.java
@@ -0,0 +1,55 @@
+package at.tuwien.api.doi;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.NotNull;
+import lombok.*;
+import lombok.extern.jackson.Jacksonized;
+
+import java.util.List;
+
+@Getter
+@Setter
+@Builder
+@EqualsAndHashCode
+@NoArgsConstructor
+@AllArgsConstructor
+@Jacksonized
+@ToString
+public class ReferenceDto {
+
+    @NotNull
+    @Schema(example = "ref1")
+    private String key;
+
+    @JsonProperty("doi-asserted-by")
+    @Schema(example = "publisher")
+    private String doiAssertedBy;
+
+    @JsonProperty("DOI")
+    @Schema(example = "10.1038/sdata.2016.18")
+    private String doi;
+
+    @Schema(example = "2024")
+    private String year;
+
+    @JsonProperty("article-title")
+    @Schema(example = "The Dryad Data Repository: a Singapore Framework metadata Architecture in a DSpace Environment")
+    private String articleTitle;
+
+    @JsonProperty("volume-title")
+    @Schema(example = "Proceedings of the 2008 International Conference on Dublin Core and Metadata Applications")
+    private String volumeTitle;
+
+    @JsonProperty("journal-title")
+    @Schema(example = "Libraries Research Publications")
+    private String journalTitle;
+
+    @Schema(example = "Witt")
+    private String author;
+
+    @JsonProperty("first-page")
+    @Schema(example = "157")
+    private String firstPage;
+
+}
diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/doi/ResourceDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/doi/ResourceDto.java
new file mode 100644
index 0000000000..a2543c2834
--- /dev/null
+++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/doi/ResourceDto.java
@@ -0,0 +1,20 @@
+package at.tuwien.api.doi;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.*;
+import lombok.extern.jackson.Jacksonized;
+
+@Getter
+@Setter
+@Builder
+@EqualsAndHashCode
+@NoArgsConstructor
+@AllArgsConstructor
+@Jacksonized
+@ToString
+public class ResourceDto {
+
+    private ResourceRepresentationDto primary;
+
+}
diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/doi/ResourceRepresentationDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/doi/ResourceRepresentationDto.java
new file mode 100644
index 0000000000..bf2312a648
--- /dev/null
+++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/doi/ResourceRepresentationDto.java
@@ -0,0 +1,20 @@
+package at.tuwien.api.doi;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.*;
+import lombok.extern.jackson.Jacksonized;
+
+@Getter
+@Setter
+@Builder
+@EqualsAndHashCode
+@NoArgsConstructor
+@AllArgsConstructor
+@Jacksonized
+@ToString
+public class ResourceRepresentationDto {
+
+    @JsonProperty("URL")
+    private String url;
+
+}
diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/doi/TimeRepresentationDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/doi/TimeRepresentationDto.java
new file mode 100644
index 0000000000..fe649217e9
--- /dev/null
+++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/doi/TimeRepresentationDto.java
@@ -0,0 +1,33 @@
+package at.tuwien.api.doi;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.*;
+import lombok.extern.jackson.Jacksonized;
+
+import java.time.Instant;
+import java.util.List;
+
+@Getter
+@Setter
+@Builder
+@EqualsAndHashCode
+@NoArgsConstructor
+@AllArgsConstructor
+@Jacksonized
+@ToString
+public class TimeRepresentationDto {
+
+    @JsonProperty("date-parts")
+    @Schema(example = "[[2025,1,18]]")
+    private List<List<Integer>> dateParts;
+
+    @JsonProperty("date-time")
+    @Schema(example = "2021-03-12T15:26:21Z")
+    @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ssX", timezone = "UTC")
+    private Instant dateTime;
+
+    private Long timestamp;
+
+}
diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/MetadataMapper.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/MetadataMapper.java
index 7428478924..7db6a745e8 100644
--- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/MetadataMapper.java
+++ b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/MetadataMapper.java
@@ -27,6 +27,7 @@ import at.tuwien.api.database.table.constraints.foreign.ReferenceTypeDto;
 import at.tuwien.api.database.table.constraints.primary.PrimaryKeyDto;
 import at.tuwien.api.database.table.constraints.unique.UniqueDto;
 import at.tuwien.api.datacite.doi.*;
+import at.tuwien.api.doi.DoiDto;
 import at.tuwien.api.identifier.*;
 import at.tuwien.api.identifier.ld.LdCreatorDto;
 import at.tuwien.api.identifier.ld.LdDatasetDto;
diff --git a/dbrepo-metadata-service/rest-service/src/main/resources/application.yml b/dbrepo-metadata-service/rest-service/src/main/resources/application.yml
index 5bde7a292b..41ce44a076 100644
--- a/dbrepo-metadata-service/rest-service/src/main/resources/application.yml
+++ b/dbrepo-metadata-service/rest-service/src/main/resources/application.yml
@@ -62,6 +62,7 @@ dbrepo:
     storageService: "${S3_ENDPOINT:http://storage-service:9000}"
     rorService: "${ROR_ENDPOINT:https://api.ror.org}"
     crossRefService: "${CROSSREF_ENDPOINT:http://data.crossref.org}"
+    doiService: "${DOI_ENDPOINT:https://doi.org}"
   s3:
     accessKeyId: "${S3_ACCESS_KEY_ID:seaweedfsadmin}"
     secretAccessKey: "${S3_SECRET_ACCESS_KEY:seaweedfsadmin}"
diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/gateway/CrossrefGatewayUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/gateway/CrossRefGatewayUnitTest.java
similarity index 79%
rename from dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/gateway/CrossrefGatewayUnitTest.java
rename to dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/gateway/CrossRefGatewayUnitTest.java
index 881f29ed04..811f23d020 100644
--- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/gateway/CrossrefGatewayUnitTest.java
+++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/gateway/CrossRefGatewayUnitTest.java
@@ -1,8 +1,8 @@
 package at.tuwien.gateway;
 
-import at.tuwien.test.AbstractUnitTest;
 import at.tuwien.api.crossref.CrossrefDto;
 import at.tuwien.exception.DoiNotFoundException;
+import at.tuwien.test.AbstractUnitTest;
 import lombok.extern.log4j.Log4j2;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.ExtendWith;
@@ -16,7 +16,6 @@ import org.springframework.http.HttpStatus;
 import org.springframework.http.ResponseEntity;
 import org.springframework.test.context.junit.jupiter.SpringExtension;
 import org.springframework.web.client.HttpServerErrorException;
-import org.springframework.web.client.ResourceAccessException;
 import org.springframework.web.client.RestTemplate;
 
 import static org.junit.jupiter.api.Assertions.assertThrows;
@@ -25,24 +24,25 @@ import static org.mockito.Mockito.*;
 @Log4j2
 @SpringBootTest
 @ExtendWith(SpringExtension.class)
-public class CrossrefGatewayUnitTest extends AbstractUnitTest {
+public class CrossRefGatewayUnitTest extends AbstractUnitTest {
 
     @MockBean
+    @Qualifier("crossRefServiceRestTemplate")
     private RestTemplate restTemplate;
 
     @Autowired
-    private CrossrefGateway crossrefGateway;
+    private CrossRefServiceGateway crossRefGateway;
 
     @Test
     public void findById_succeeds() throws DoiNotFoundException {
 
         /* mock */
-        when(restTemplate.exchange(anyString(), eq(HttpMethod.GET), any(HttpEntity.class), eq(CrossrefDto.class)))
+        when(restTemplate.exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(CrossrefDto.class)))
                 .thenReturn(ResponseEntity.status(HttpStatus.OK)
                         .build());
 
         /* test */
-        crossrefGateway.findById("501100004729");
+        crossRefGateway.findById("501100004729");
     }
 
     @Test
@@ -51,11 +51,11 @@ public class CrossrefGatewayUnitTest extends AbstractUnitTest {
         /* mock */
         doThrow(HttpServerErrorException.class)
                 .when(restTemplate)
-                .exchange(anyString(), eq(HttpMethod.GET), any(HttpEntity.class), eq(CrossrefDto.class));
+                .exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(CrossrefDto.class));
 
         /* test */
         assertThrows(DoiNotFoundException.class, () -> {
-            crossrefGateway.findById("501100004729");
+            crossRefGateway.findById("501100004729");
         });
     }
 
diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/gateway/DoiGatewayUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/gateway/DoiGatewayUnitTest.java
new file mode 100644
index 0000000000..0b6752fefc
--- /dev/null
+++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/gateway/DoiGatewayUnitTest.java
@@ -0,0 +1,73 @@
+package at.tuwien.gateway;
+
+import at.tuwien.api.doi.DoiDto;
+import at.tuwien.exception.DoiNotFoundException;
+import at.tuwien.test.AbstractUnitTest;
+import com.fasterxml.jackson.databind.DeserializationFeature;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import lombok.extern.log4j.Log4j2;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.mock.mockito.MockBean;
+import org.springframework.http.*;
+import org.springframework.test.context.junit.jupiter.SpringExtension;
+import org.springframework.web.client.RestTemplate;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.stream.Stream;
+
+import static org.mockito.Mockito.*;
+
+@Log4j2
+@SpringBootTest
+@ExtendWith(SpringExtension.class)
+public class DoiGatewayUnitTest extends AbstractUnitTest {
+
+    @MockBean
+    @Qualifier("doiServiceRestTemplate")
+    private RestTemplate restTemplate;
+
+    @Autowired
+    private DoiServiceGateway doiServiceGateway;
+
+    @Autowired
+    private ObjectMapper objectMapper;
+
+    public static Stream<Arguments> findById_parameters() {
+        return Stream.of(
+                Arguments.arguments("proceedings-article", "10.1109/bigdata62323.2024.10825401", "proceedings-article.json"),
+                Arguments.arguments("journal-article", "10.5334/dsj-2022-004", "journal-article.json"),
+                Arguments.arguments("dataset", "10.5281/zenodo.1404173", "dataset.json"),
+                Arguments.arguments("database", "10.15223/policy-037", "database.json")
+        );
+    }
+
+    @ParameterizedTest
+    @MethodSource("findById_parameters")
+    public void findById_succeeds(String name, String doi, String jsonFileName) throws DoiNotFoundException, IOException {
+        final DoiDto body = objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
+                .readValue(new File("src/test/resources/doi/" + jsonFileName), DoiDto.class);
+
+        /* mock */
+        when(restTemplate.exchange(anyString(), eq(HttpMethod.GET), eq(getEmptyEntity()), eq(DoiDto.class)))
+                .thenReturn(ResponseEntity.status(HttpStatus.OK)
+                        .body(body));
+
+        /* test */
+        doiServiceGateway.findById(doi);
+    }
+
+    private HttpEntity<DoiDto> getEmptyEntity() {
+        final HttpHeaders headers = new HttpHeaders();
+        headers.set("Accept", "application/vnd.citationstyles.csl+json");
+        return new HttpEntity<>(null, headers);
+    }
+
+}
diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/MetadataServiceUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/MetadataServiceUnitTest.java
index 2f4fd3a85a..dd493a99c8 100644
--- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/MetadataServiceUnitTest.java
+++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/MetadataServiceUnitTest.java
@@ -6,7 +6,7 @@ import at.tuwien.api.ror.RorDto;
 import at.tuwien.api.user.external.ExternalMetadataDto;
 import at.tuwien.api.user.external.affiliation.ExternalAffiliationDto;
 import at.tuwien.exception.*;
-import at.tuwien.gateway.CrossrefGateway;
+import at.tuwien.gateway.CrossRefServiceGateway;
 import at.tuwien.gateway.OrcidGateway;
 import at.tuwien.gateway.RorGateway;
 import at.tuwien.oaipmh.OaiErrorType;
@@ -49,7 +49,7 @@ public class MetadataServiceUnitTest extends AbstractUnitTest {
     private RorGateway rorGateway;
 
     @MockBean
-    private CrossrefGateway crossrefGateway;
+    private CrossRefServiceGateway crossrefGateway;
 
     @MockBean
     private IdentifierService identifierService;
diff --git a/dbrepo-metadata-service/rest-service/src/test/resources/doi/database.json b/dbrepo-metadata-service/rest-service/src/test/resources/doi/database.json
new file mode 100644
index 0000000000..94508d61a5
--- /dev/null
+++ b/dbrepo-metadata-service/rest-service/src/test/resources/doi/database.json
@@ -0,0 +1,70 @@
+{
+  "indexed": {
+    "date-parts": [
+      [
+        2024,
+        12,
+        11
+      ]
+    ],
+    "date-time": "2024-12-11T00:54:48Z",
+    "timestamp": 1733878488241,
+    "version": "3.30.1"
+  },
+  "reference-count": 0,
+  "publisher": "International STM Association",
+  "content-domain": {
+    "domain": [],
+    "crossmark-restriction": false
+  },
+  "DOI": "10.15223\/policy-037",
+  "type": "database",
+  "created": {
+    "date-parts": [
+      [
+        2021,
+        5,
+        3
+      ]
+    ],
+    "date-time": "2021-05-03T21:10:23Z",
+    "timestamp": 1620076223000
+  },
+  "source": "Crossref",
+  "is-referenced-by-count": 0,
+  "title": "Article Sharing Framework Policy #37",
+  "prefix": "10.15223",
+  "member": "5868",
+  "container-title": [],
+  "original-title": [],
+  "deposited": {
+    "date-parts": [
+      [
+        2021,
+        5,
+        3
+      ]
+    ],
+    "date-time": "2021-05-03T21:10:23Z",
+    "timestamp": 1620076223000
+  },
+  "score": 1,
+  "resource": {
+    "primary": {
+      "URL": "https:\/\/www.stm-assoc.org\/asf\/policy-037"
+    }
+  },
+  "subtitle": [],
+  "short-title": [],
+  "issued": {
+    "date-parts": [
+      [
+        null
+      ]
+    ]
+  },
+  "references-count": 0,
+  "URL": "http:\/\/dx.doi.org\/10.15223\/policy-037",
+  "relation": {},
+  "subject": []
+}
\ No newline at end of file
diff --git a/dbrepo-metadata-service/rest-service/src/test/resources/doi/dataset.json b/dbrepo-metadata-service/rest-service/src/test/resources/doi/dataset.json
new file mode 100644
index 0000000000..f231138689
--- /dev/null
+++ b/dbrepo-metadata-service/rest-service/src/test/resources/doi/dataset.json
@@ -0,0 +1,25 @@
+{
+  "type": "dataset",
+  "id": "https://doi.org/10.5281/zenodo.1404173",
+  "author": [
+    {
+      "family": "Marshall",
+      "given": "Michael"
+    }
+  ],
+  "issued": {
+    "date-parts": [
+      [
+        2018,
+        8,
+        27
+      ]
+    ]
+  },
+  "abstract": "<strong>Data Set Characteristics:</strong>\n\nNumber of Instances:\n150 (50 in each of three classes)\nNumber of Attributes:\n\n4 numeric, predictive attributes and the class\nAttribute Information:\n\n\n\tsepal length in cm\n\tsepal width in cm\n\tpetal length in cm\n\tpetal width in cm\n\t\n\tclass:\n\n\t\n\t\tIris-Setosa\n\t\tIris-Versicolour\n\t\tIris-Virginica",
+  "DOI": "10.5281/ZENODO.1404173",
+  "publisher": "Zenodo",
+  "title": "Scikit-Learn Iris",
+  "URL": "https://zenodo.org/record/1404173",
+  "copyright": "Creative Commons Attribution 4.0"
+}
\ No newline at end of file
diff --git a/dbrepo-metadata-service/rest-service/src/test/resources/doi/journal-article.json b/dbrepo-metadata-service/rest-service/src/test/resources/doi/journal-article.json
new file mode 100644
index 0000000000..627ca16767
--- /dev/null
+++ b/dbrepo-metadata-service/rest-service/src/test/resources/doi/journal-article.json
@@ -0,0 +1,403 @@
+{
+  "indexed": {
+    "date-parts": [
+      [
+        2024,
+        7,
+        1
+      ]
+    ],
+    "date-time": "2024-07-01T09:15:12Z",
+    "timestamp": 1719825312147
+  },
+  "reference-count": 37,
+  "publisher": "Ubiquity Press, Ltd.",
+  "content-domain": {
+    "domain": [],
+    "crossmark-restriction": false
+  },
+  "published-print": {
+    "date-parts": [
+      [
+        2022,
+        2,
+        9
+      ]
+    ]
+  },
+  "DOI": "10.5334\/dsj-2022-004",
+  "type": "journal-article",
+  "created": {
+    "date-parts": [
+      [
+        2022,
+        2,
+        9
+      ]
+    ],
+    "date-time": "2022-02-09T11:11:20Z",
+    "timestamp": 1644405080000
+  },
+  "source": "Crossref",
+  "is-referenced-by-count": 5,
+  "title": "OSSDIP: Open Source Secure Data Infrastructure and Processes Supporting Data Visiting",
+  "prefix": "10.5334",
+  "volume": "21",
+  "author": [
+    {
+      "ORCID": "http:\/\/orcid.org\/0000-0003-4216-302X",
+      "authenticated-orcid": false,
+      "given": "Martin",
+      "family": "Weise",
+      "sequence": "first",
+      "affiliation": []
+    },
+    {
+      "ORCID": "http:\/\/orcid.org\/0000-0002-2854-0434",
+      "authenticated-orcid": false,
+      "given": "Filip",
+      "family": "Kovacevic",
+      "sequence": "additional",
+      "affiliation": []
+    },
+    {
+      "ORCID": "http:\/\/orcid.org\/0000-0003-4615-2774",
+      "authenticated-orcid": false,
+      "given": "Nikolas",
+      "family": "Popper",
+      "sequence": "additional",
+      "affiliation": []
+    },
+    {
+      "ORCID": "http:\/\/orcid.org\/0000-0002-9272-6225",
+      "authenticated-orcid": false,
+      "given": "Andreas",
+      "family": "Rauber",
+      "sequence": "additional",
+      "affiliation": []
+    }
+  ],
+  "member": "3285",
+  "reference": [
+    {
+      "key": "key20220209060905_B1",
+      "volume-title": "Defenders\u2019 Guide to Container Infrastructure Security",
+      "year": "2019"
+    },
+    {
+      "issue": "2",
+      "key": "key20220209060905_B2",
+      "first-page": "315",
+      "article-title": "20 remoteneps: Data Dissemination in a Collaborative Workspace",
+      "volume": "14",
+      "year": "2011",
+      "journal-title": "Zeitschrift f\u00fcr Erziehungswissenschaft"
+    },
+    {
+      "issue": "1",
+      "key": "key20220209060905_B3",
+      "article-title": "Kadi4Mat: A Research Data Infrastructure for Materials Science",
+      "volume": "20",
+      "year": "2021",
+      "journal-title": "Data Science Journal"
+    },
+    {
+      "issue": "1",
+      "key": "key20220209060905_B4",
+      "doi-asserted-by": "crossref",
+      "first-page": "195",
+      "DOI": "10.1055\/s-0039-1677917",
+      "article-title": "The French Health Data Hub and the German Medical Informatics Initiatives: Two National Projects to Promote Data Sharing in Healthcare",
+      "volume": "28",
+      "year": "2019",
+      "journal-title": "EN. Yearbook of Medical Informatics"
+    },
+    {
+      "key": "key20220209060905_B5",
+      "article-title": "Five Safes: Designing data access for research [Online]",
+      "year": "2016",
+      "journal-title": "Economics Working Paper Series 1601"
+    },
+    {
+      "key": "key20220209060905_B6",
+      "article-title": "Remote Access to Official Microdata",
+      "year": "2020"
+    },
+    {
+      "key": "key20220209060905_B7",
+      "first-page": "554",
+      "article-title": "Role-Based Access Controls",
+      "year": "1992"
+    },
+    {
+      "key": "key20220209060905_B8",
+      "article-title": "De-identification of personal information",
+      "year": "2015",
+      "journal-title": "National institute of standards and technology"
+    },
+    {
+      "key": "key20220209060905_B9",
+      "first-page": "16",
+      "article-title": "Secure cloud computing with a virtualized network infrastructure",
+      "year": "2010"
+    },
+    {
+      "key": "key20220209060905_B10",
+      "doi-asserted-by": "crossref",
+      "first-page": "196",
+      "DOI": "10.1016\/j.jbi.2014.01.003",
+      "article-title": "A case study of the Secure Anonymous Information Linkage (SAIL) Gateway: A privacy-protecting remote access system for health-related research and evaluation",
+      "volume": "50",
+      "year": "2014",
+      "journal-title": "Journal of Biomedical Informatics"
+    },
+    {
+      "issue": "4",
+      "key": "key20220209060905_B11",
+      "doi-asserted-by": "crossref",
+      "first-page": "533",
+      "DOI": "10.1016\/j.giq.2010.10.008",
+      "article-title": "Key Issues in Data Center Security: An Investigation of Government Audit Reports",
+      "volume": "28",
+      "year": "2011",
+      "journal-title": "Government Information Quarterly"
+    },
+    {
+      "issue": "5",
+      "key": "key20220209060905_B12",
+      "doi-asserted-by": "crossref",
+      "first-page": "38",
+      "DOI": "10.1109\/MSEC.2020.2990230",
+      "article-title": "Dedicated Security Chips in the Age of Secure Enclaves",
+      "volume": "18",
+      "year": "2020",
+      "journal-title": "IEEE Security & Privacy"
+    },
+    {
+      "issue": "3",
+      "key": "key20220209060905_B13",
+      "first-page": "34",
+      "volume": "41",
+      "year": "2012",
+      "journal-title": "Temporal Features in SQL:2011"
+    },
+    {
+      "issue": "4",
+      "key": "key20220209060905_B14",
+      "article-title": "Watermill: An Optimized Fingerprinting System for Databases under Constraints",
+      "volume": "20",
+      "year": "2008",
+      "journal-title": "IEEE Transactions on Knowledge and Data Engineering"
+    },
+    {
+      "key": "key20220209060905_B15",
+      "article-title": "Keystone: An Open Framework for Architecting Trusted Execution Environments",
+      "year": "2020"
+    },
+    {
+      "key": "key20220209060905_B16",
+      "first-page": "106",
+      "article-title": "T-closeness: privacy beyond k-anonymity and l-diversity",
+      "year": "2007"
+    },
+    {
+      "issue": "1",
+      "key": "key20220209060905_B17",
+      "article-title": "Fingerprinting Relational Databases: Schemes and Specialties",
+      "volume": "2",
+      "year": "2005",
+      "journal-title": "Transactions on Dependable and Secure Computing"
+    },
+    {
+      "issue": "1",
+      "key": "key20220209060905_B18",
+      "doi-asserted-by": "crossref",
+      "first-page": "3",
+      "DOI": "10.1145\/1217299.1217302",
+      "article-title": "L-diversity: privacy beyond k-anonymity",
+      "volume": "1",
+      "year": "2007",
+      "journal-title": "Acm transactions on knowledge discovery from data (tkdd)"
+    },
+    {
+      "key": "key20220209060905_B19",
+      "first-page": "1",
+      "article-title": "Database security threats and challenges",
+      "year": "2020"
+    },
+    {
+      "key": "key20220209060905_B20",
+      "article-title": "Data grid concepts for data security in distributed computing",
+      "year": "2013",
+      "journal-title": "Arxiv preprint arxiv:1308.6058"
+    },
+    {
+      "key": "key20220209060905_B21",
+      "volume-title": "A vision of a Nordic secure digital infrastructure for health data: The Nordic Commons",
+      "year": "2019"
+    },
+    {
+      "key": "key20220209060905_B22",
+      "unstructured": "Peisert, S. 2021. An Examination and Survey of Data Confidentiality Issues and Solutions in Academic Research Computing. https:\/\/escholarship.org\/uc\/item\/7cz7m1ws. Online; accessed 22 December 2021."
+    },
+    {
+      "key": "key20220209060905_B23",
+      "first-page": "561",
+      "article-title": "Real-Time Screen Watermarking Using Overlaying Layer",
+      "year": "2014",
+      "journal-title": "2014 Ninth International Conference on Availability, Reliability and Security"
+    },
+    {
+      "issue": "4",
+      "key": "key20220209060905_B24",
+      "doi-asserted-by": "crossref",
+      "first-page": "203",
+      "DOI": "10.11128\/sne.27.tn.10396",
+      "article-title": "Planning Future Health: Developing Big Data and System Modelling Pipelines for Health System Research",
+      "volume": "27",
+      "year": "2017",
+      "journal-title": "Simulation Notes Europe"
+    },
+    {
+      "key": "key20220209060905_B25",
+      "first-page": "231",
+      "article-title": "Preventing Privilege Escalation",
+      "year": "2003"
+    },
+    {
+      "key": "key20220209060905_B26",
+      "year": "2015",
+      "journal-title": "Data Citation of Evolving Data: Recommendations of the Working Group on Data Citation (WGDC)"
+    },
+    {
+      "issue": "1",
+      "key": "key20220209060905_B27",
+      "article-title": "Identification of Reproducible Subsets for Data Citation, Sharing and Re-Use",
+      "volume": "12",
+      "year": "2016",
+      "journal-title": "Bulletin of the IEEE Technical Committe on Digital Libraries (TCDL)"
+    },
+    {
+      "key": "key20220209060905_B28",
+      "first-page": "199",
+      "article-title": "Hey, you, get off of my cloud: exploring information leakage in third-party compute clouds",
+      "year": "2009"
+    },
+    {
+      "key": "key20220209060905_B29",
+      "doi-asserted-by": "crossref",
+      "first-page": "221",
+      "DOI": "10.1109\/SERVICES.2015.40",
+      "volume-title": "2015 IEEE world congress on services",
+      "year": "2015"
+    },
+    {
+      "key": "key20220209060905_B30",
+      "doi-asserted-by": "crossref",
+      "first-page": "611",
+      "DOI": "10.1007\/978-3-658-11994-2_34",
+      "volume-title": "Methodological Issues of Longitudinal Surveys: The Example of the National Educational Panel Study",
+      "year": "2016"
+    },
+    {
+      "key": "key20220209060905_B31",
+      "first-page": "1",
+      "article-title": "A collective attestation scheme towards cloud system",
+      "year": "2020",
+      "journal-title": "Cluster computing"
+    },
+    {
+      "issue": "5",
+      "key": "key20220209060905_B32",
+      "doi-asserted-by": "crossref",
+      "first-page": "557",
+      "DOI": "10.1142\/S0218488502001648",
+      "article-title": "K-anonymity: a model for protecting privacy",
+      "volume": "10",
+      "year": "2002",
+      "journal-title": "International journal of uncertainty, fuzziness and knowledge-based systems"
+    },
+    {
+      "key": "key20220209060905_B33",
+      "unstructured": "United Kingdom Health Data Research Alliance. 2020. Trusted Research Environments [Online]. URL: https:\/\/ukhealthdata.org\/projects\/aligning-approach-to-trusted-research-environments\/. Accessed September 2020. Version 2.0."
+    },
+    {
+      "key": "key20220209060905_B34",
+      "first-page": "34",
+      "article-title": "FDA-DBRepo: A Data Preservation Repository Supporting FAIR Principles, Data Versioning and Reproducible Queries",
+      "year": "2021"
+    },
+    {
+      "key": "key20220209060905_B35",
+      "first-page": "51",
+      "article-title": "A Data-Visiting Infrastructure for Providing Access to Preserved Databases that Cannot be Shared or Made Publicly Accessible",
+      "year": "2021"
+    },
+    {
+      "key": "key20220209060905_B36",
+      "article-title": "OpenSAFELY: factors associated with COVID-19-related hospital death in the linked electronic health records of 17 million adult NHS patients",
+      "year": "2020",
+      "journal-title": "Medrxiv"
+    },
+    {
+      "key": "key20220209060905_B37",
+      "first-page": "305",
+      "article-title": "Cross-vm side channels and their use to extract private keys",
+      "year": "2012"
+    }
+  ],
+  "container-title": "Data Science Journal",
+  "original-title": [],
+  "language": "en",
+  "link": [
+    {
+      "URL": "https:\/\/doi.org\/10.5334\/dsj-2022-004",
+      "content-type": "unspecified",
+      "content-version": "vor",
+      "intended-application": "similarity-checking"
+    }
+  ],
+  "deposited": {
+    "date-parts": [
+      [
+        2022,
+        7,
+        11
+      ]
+    ],
+    "date-time": "2022-07-11T09:21:08Z",
+    "timestamp": 1657531268000
+  },
+  "score": 1,
+  "resource": {
+    "primary": {
+      "URL": "http:\/\/datascience.codata.org\/articles\/10.5334\/dsj-2022-004\/"
+    }
+  },
+  "subtitle": [],
+  "short-title": [],
+  "issued": {
+    "date-parts": [
+      [
+        2022
+      ]
+    ]
+  },
+  "references-count": 37,
+  "alternative-id": [
+    "10.5334\/dsj-2022-004"
+  ],
+  "URL": "http:\/\/dx.doi.org\/10.5334\/dsj-2022-004",
+  "relation": {},
+  "ISSN": [
+    "1683-1470"
+  ],
+  "subject": [],
+  "published": {
+    "date-parts": [
+      [
+        2022
+      ]
+    ]
+  }
+}
\ No newline at end of file
diff --git a/dbrepo-metadata-service/rest-service/src/test/resources/doi/proceedings-article.json b/dbrepo-metadata-service/rest-service/src/test/resources/doi/proceedings-article.json
new file mode 100644
index 0000000000..429179549a
--- /dev/null
+++ b/dbrepo-metadata-service/rest-service/src/test/resources/doi/proceedings-article.json
@@ -0,0 +1,320 @@
+{
+  "indexed": {
+    "date-parts": [
+      [
+        2025,
+        1,
+        18
+      ]
+    ],
+    "date-time": "2025-01-18T05:07:56Z",
+    "timestamp": 1737176876420,
+    "version": "3.33.0"
+  },
+  "reference-count": 28,
+  "publisher": "IEEE",
+  "license": [
+    {
+      "start": {
+        "date-parts": [
+          [
+            2024,
+            12,
+            15
+          ]
+        ],
+        "date-time": "2024-12-15T00:00:00Z",
+        "timestamp": 1734220800000
+      },
+      "content-version": "stm-asf",
+      "delay-in-days": 0,
+      "URL": "https:\/\/doi.org\/10.15223\/policy-029"
+    },
+    {
+      "start": {
+        "date-parts": [
+          [
+            2024,
+            12,
+            15
+          ]
+        ],
+        "date-time": "2024-12-15T00:00:00Z",
+        "timestamp": 1734220800000
+      },
+      "content-version": "stm-asf",
+      "delay-in-days": 0,
+      "URL": "https:\/\/doi.org\/10.15223\/policy-037"
+    }
+  ],
+  "funder": [
+    {
+      "DOI": "10.13039\/100016234",
+      "name": "ASEAN-European Academic University Network",
+      "doi-asserted-by": "publisher",
+      "id": [
+        {
+          "id": "10.13039\/100016234",
+          "id-type": "DOI",
+          "asserted-by": "publisher"
+        }
+      ]
+    }
+  ],
+  "content-domain": {
+    "domain": [],
+    "crossmark-restriction": false
+  },
+  "published-print": {
+    "date-parts": [
+      [
+        2024,
+        12,
+        15
+      ]
+    ]
+  },
+  "DOI": "10.1109\/bigdata62323.2024.10825401",
+  "type": "proceedings-article",
+  "created": {
+    "date-parts": [
+      [
+        2025,
+        1,
+        16
+      ]
+    ],
+    "date-time": "2025-01-16T18:31:23Z",
+    "timestamp": 1737052283000
+  },
+  "page": "322-331",
+  "source": "Crossref",
+  "is-referenced-by-count": 0,
+  "title": "DBRepo: A Data Repository System for Research Data in Databases",
+  "prefix": "10.1109",
+  "author": [
+    {
+      "given": "Martin",
+      "family": "Weise",
+      "sequence": "first",
+      "affiliation": [
+        {
+          "name": "ISE, TU Wien,Data Science Research Unit,Vienna,Austria"
+        }
+      ]
+    },
+    {
+      "given": "Andreas",
+      "family": "Rauber",
+      "sequence": "additional",
+      "affiliation": [
+        {
+          "name": "ISE, TU Wien,Data Science Research Unit,Vienna,Austria"
+        }
+      ]
+    }
+  ],
+  "member": "263",
+  "reference": [
+    {
+      "key": "ref1",
+      "doi-asserted-by": "publisher",
+      "DOI": "10.1002\/0470867167.ch36"
+    },
+    {
+      "key": "ref2",
+      "doi-asserted-by": "publisher",
+      "DOI": "10.2218\/ijdc.v17i1.825"
+    },
+    {
+      "key": "ref3",
+      "doi-asserted-by": "publisher",
+      "DOI": "10.1145\/2380776.2380786"
+    },
+    {
+      "key": "ref4",
+      "doi-asserted-by": "publisher",
+      "DOI": "10.1038\/sdata.2016.18"
+    },
+    {
+      "year": "2024",
+      "key": "ref5",
+      "article-title": "DataCite Metadata Schema Documentation for the Publication and Citation of Research Data and Other Research Outputs v4.5"
+    },
+    {
+      "article-title": "Digital Cartographic Standard for Geologic Map Symbolization",
+      "volume-title": "Tech. Rep.",
+      "year": "2006",
+      "key": "ref6"
+    },
+    {
+      "article-title": "FAIR Digital Objects and FAIR Signposting",
+      "year": "2023",
+      "author": "Van de Sompel",
+      "key": "ref7"
+    },
+    {
+      "key": "ref8",
+      "doi-asserted-by": "publisher",
+      "DOI": "10.1086\/666656"
+    },
+    {
+      "key": "ref9",
+      "doi-asserted-by": "publisher",
+      "DOI": "10.1162\/99608f92.be565013"
+    },
+    {
+      "key": "ref10",
+      "doi-asserted-by": "publisher",
+      "DOI": "10.1045\/january2003-smith"
+    },
+    {
+      "key": "ref11",
+      "doi-asserted-by": "publisher",
+      "DOI": "10.1177\/0049124107306660"
+    },
+    {
+      "key": "ref12",
+      "first-page": "157",
+      "article-title": "The Dryad Data Repository: a Singapore Framework metadata Architecture in a DSpace Environment",
+      "volume-title": "Proceedings of the 2008 International Conference on Dublin Core and Metadata Applications",
+      "author": "White"
+    },
+    {
+      "key": "ref13",
+      "doi-asserted-by": "publisher",
+      "DOI": "10.5670\/oceanog.2014.50"
+    },
+    {
+      "key": "ref14",
+      "doi-asserted-by": "publisher",
+      "DOI": "10.1109\/SOCA.2016.15"
+    },
+    {
+      "key": "ref15",
+      "first-page": "83",
+      "article-title": "Introduction to Institutional Data Repositories Workshop",
+      "author": "Witt",
+      "year": "2008",
+      "journal-title": "Libraries Research Publications"
+    },
+    {
+      "key": "ref16",
+      "doi-asserted-by": "publisher",
+      "DOI": "10.1109\/ICDE.2018.00098"
+    },
+    {
+      "key": "ref17",
+      "doi-asserted-by": "publisher",
+      "DOI": "10.1145\/2737924.2737959"
+    },
+    {
+      "key": "ref18",
+      "doi-asserted-by": "publisher",
+      "DOI": "10.1109\/ICoDSE56892.2022.9971958"
+    },
+    {
+      "key": "ref19",
+      "doi-asserted-by": "publisher",
+      "DOI": "10.1016\/j.promfg.2019.03.032"
+    },
+    {
+      "key": "ref20",
+      "doi-asserted-by": "publisher",
+      "DOI": "10.1016\/j.trpro.2023.11.866"
+    },
+    {
+      "volume-title": "Emissionstrends 1990-2022",
+      "year": "2024",
+      "author": "Anderl",
+      "key": "ref21"
+    },
+    {
+      "key": "ref22",
+      "doi-asserted-by": "publisher",
+      "DOI": "10.1109\/TVCG.2018.2864903"
+    },
+    {
+      "key": "ref23",
+      "doi-asserted-by": "publisher",
+      "DOI": "10.1016\/j.scitotenv.2016.06.235"
+    },
+    {
+      "key": "ref24",
+      "doi-asserted-by": "publisher",
+      "DOI": "10.1186\/s12302-024-00862-4"
+    },
+    {
+      "key": "ref25",
+      "doi-asserted-by": "publisher",
+      "DOI": "10.1038\/533452a"
+    },
+    {
+      "key": "ref26",
+      "doi-asserted-by": "publisher",
+      "DOI": "10.18653\/v1\/2024.findings-acl.137"
+    },
+    {
+      "author": "Altug",
+      "key": "ref27",
+      "article-title": "Generating Semantic Context for Data Interoperability in Relational Databases using bge M3-Embeddings"
+    },
+    {
+      "key": "ref28",
+      "doi-asserted-by": "publisher",
+      "DOI": "10.1186\/s13643-019-1250-y"
+    }
+  ],
+  "event": "2024 IEEE International Conference on Big Data (BigData)",
+  "container-title": "2024 IEEE International Conference on Big Data (BigData)",
+  "original-title": [],
+  "link": [
+    {
+      "URL": "http:\/\/xplorestaging.ieee.org\/ielx8\/10824975\/10824942\/10825401.pdf?arnumber=10825401",
+      "content-type": "unspecified",
+      "content-version": "vor",
+      "intended-application": "similarity-checking"
+    }
+  ],
+  "deposited": {
+    "date-parts": [
+      [
+        2025,
+        1,
+        17
+      ]
+    ],
+    "date-time": "2025-01-17T07:55:27Z",
+    "timestamp": 1737100527000
+  },
+  "score": 1,
+  "resource": {
+    "primary": {
+      "URL": "https:\/\/ieeexplore.ieee.org\/document\/10825401\/"
+    }
+  },
+  "subtitle": [],
+  "short-title": [],
+  "issued": {
+    "date-parts": [
+      [
+        2024,
+        12,
+        15
+      ]
+    ]
+  },
+  "references-count": 28,
+  "URL": "http:\/\/dx.doi.org\/10.1109\/BigData62323.2024.10825401",
+  "relation": {},
+  "subject": [],
+  "published": {
+    "date-parts": [
+      [
+        2024,
+        12,
+        15
+      ]
+    ]
+  }
+}
\ No newline at end of file
diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/config/GatewayConfig.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/config/GatewayConfig.java
index 34b0acbcb7..8790d6a783 100644
--- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/config/GatewayConfig.java
+++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/config/GatewayConfig.java
@@ -33,6 +33,9 @@ public class GatewayConfig {
     @Value("${dbrepo.endpoints.crossRefService}")
     private String crossRefEndpoint;
 
+    @Value("${dbrepo.endpoints.doiService}")
+    private String doiEndpoint;
+
     @Value("${spring.rabbitmq.username}")
     private String brokerUsername;
 
@@ -89,4 +92,18 @@ public class GatewayConfig {
         return restTemplate;
     }
 
+    @Bean("doiServiceRestTemplate")
+    public RestTemplate doiServiceRestTemplate() {
+        final RestTemplate restTemplate = new RestTemplate();
+        restTemplate.setUriTemplateHandler(new DefaultUriBuilderFactory(doiEndpoint));
+        return restTemplate;
+    }
+
+    @Bean("crossRefServiceRestTemplate")
+    public RestTemplate crossRefServiceRestTemplate() {
+        final RestTemplate restTemplate = new RestTemplate();
+        restTemplate.setUriTemplateHandler(new DefaultUriBuilderFactory(crossRefEndpoint));
+        return restTemplate;
+    }
+
 }
diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/CrossrefGateway.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/CrossRefServiceGateway.java
similarity index 92%
rename from dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/CrossrefGateway.java
rename to dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/CrossRefServiceGateway.java
index 58e023ac9d..995498e533 100644
--- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/CrossrefGateway.java
+++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/CrossRefServiceGateway.java
@@ -3,7 +3,7 @@ package at.tuwien.gateway;
 import at.tuwien.api.crossref.CrossrefDto;
 import at.tuwien.exception.DoiNotFoundException;
 
-public interface CrossrefGateway {
+public interface CrossRefServiceGateway {
 
     /**
      * Retrieves metadata from the CrossRef funder database for a given CrossRef id.
diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/DoiServiceGateway.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/DoiServiceGateway.java
new file mode 100644
index 0000000000..a7f82c57f5
--- /dev/null
+++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/DoiServiceGateway.java
@@ -0,0 +1,8 @@
+package at.tuwien.gateway;
+
+import at.tuwien.api.doi.DoiDto;
+import at.tuwien.exception.DoiNotFoundException;
+
+public interface DoiServiceGateway {
+    DoiDto findById(String doi) throws DoiNotFoundException;
+}
diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/impl/CrossrefGatewayImpl.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/impl/CrossRefServiceGatewayImpl.java
similarity index 56%
rename from dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/impl/CrossrefGatewayImpl.java
rename to dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/impl/CrossRefServiceGatewayImpl.java
index 8fd957f330..b4a437e767 100644
--- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/impl/CrossrefGatewayImpl.java
+++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/impl/CrossRefServiceGatewayImpl.java
@@ -1,43 +1,39 @@
 package at.tuwien.gateway.impl;
 
 import at.tuwien.api.crossref.CrossrefDto;
-import at.tuwien.config.GatewayConfig;
 import at.tuwien.exception.DoiNotFoundException;
-import at.tuwien.gateway.CrossrefGateway;
+import at.tuwien.gateway.CrossRefServiceGateway;
 import lombok.extern.log4j.Log4j2;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
 import org.springframework.http.HttpEntity;
-import org.springframework.http.HttpHeaders;
 import org.springframework.http.HttpMethod;
 import org.springframework.http.ResponseEntity;
 import org.springframework.stereotype.Service;
 import org.springframework.web.client.HttpServerErrorException;
-import org.springframework.web.client.ResourceAccessException;
 import org.springframework.web.client.RestTemplate;
 
 @Log4j2
 @Service
-public class CrossrefGatewayImpl implements CrossrefGateway {
+public class CrossRefServiceGatewayImpl implements CrossRefServiceGateway {
 
     private final RestTemplate restTemplate;
-    private final GatewayConfig gatewayConfig;
 
     @Autowired
-    public CrossrefGatewayImpl(RestTemplate restTemplate, GatewayConfig gatewayConfig) {
+    public CrossRefServiceGatewayImpl(@Qualifier("crossRefServiceRestTemplate") RestTemplate restTemplate) {
         this.restTemplate = restTemplate;
-        this.gatewayConfig = gatewayConfig;
     }
 
     @Override
     public CrossrefDto findById(String id) throws DoiNotFoundException {
         final String path = "/fundingdata/funder/" + id;
-        log.trace("find crossref metadata by id from endpoint {} with path {}", gatewayConfig.getCrossRefEndpoint(), path);
+        log.trace("find crossRef metadata with path {}", path);
         final ResponseEntity<CrossrefDto> response;
         try {
-            response = restTemplate.exchange(gatewayConfig.getCrossRefEndpoint() + path, HttpMethod.GET, HttpEntity.EMPTY, CrossrefDto.class);
+            response = restTemplate.exchange(path, HttpMethod.GET, HttpEntity.EMPTY, CrossrefDto.class);
         } catch (HttpServerErrorException e) {
-            log.error("Failed to retrieve crossref metadata: {}", e.getMessage());
-            throw new DoiNotFoundException("Failed to retrieve crossref metadata: " + e.getMessage(), e);
+            log.error("Failed to retrieve crossRef metadata: {}", e.getMessage());
+            throw new DoiNotFoundException("Failed to retrieve crossRef metadata: " + e.getMessage(), e);
         }
         return response.getBody();
     }
diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/impl/DoiServiceGatewayImpl.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/impl/DoiServiceGatewayImpl.java
new file mode 100644
index 0000000000..e32c0f923d
--- /dev/null
+++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/impl/DoiServiceGatewayImpl.java
@@ -0,0 +1,43 @@
+package at.tuwien.gateway.impl;
+
+import at.tuwien.api.doi.DoiDto;
+import at.tuwien.exception.DoiNotFoundException;
+import at.tuwien.gateway.DoiServiceGateway;
+import lombok.extern.log4j.Log4j2;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.http.HttpEntity;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpMethod;
+import org.springframework.http.ResponseEntity;
+import org.springframework.stereotype.Service;
+import org.springframework.web.client.HttpServerErrorException;
+import org.springframework.web.client.RestTemplate;
+
+@Log4j2
+@Service
+public class DoiServiceGatewayImpl implements DoiServiceGateway {
+
+    private final RestTemplate restTemplate;
+
+    @Autowired
+    public DoiServiceGatewayImpl(@Qualifier("doiServiceRestTemplate") RestTemplate restTemplate) {
+        this.restTemplate = restTemplate;
+    }
+
+    @Override
+    public DoiDto findById(String doi) throws DoiNotFoundException {
+        final String path = "/" + doi;
+        log.trace("find doi metadata with path {}", path);
+        final HttpHeaders headers = new HttpHeaders();
+        headers.set("Accept", "application/vnd.citationstyles.csl+json");
+        final ResponseEntity<DoiDto> response;
+        try {
+            response = restTemplate.exchange(path, HttpMethod.GET, new HttpEntity<>(null, headers), DoiDto.class);
+        } catch (HttpServerErrorException e) {
+            log.error("Failed to retrieve doi metadata: {}", e.getMessage());
+            throw new DoiNotFoundException("Failed to retrieve doi metadata: " + e.getMessage(), e);
+        }
+        return response.getBody();
+    }
+}
\ No newline at end of file
diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/MetadataServiceImpl.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/MetadataServiceImpl.java
index 1b6051f543..a8186721e9 100644
--- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/MetadataServiceImpl.java
+++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/MetadataServiceImpl.java
@@ -7,7 +7,7 @@ import at.tuwien.api.user.external.ExternalMetadataDto;
 import at.tuwien.config.MetadataConfig;
 import at.tuwien.entities.identifier.Identifier;
 import at.tuwien.exception.*;
-import at.tuwien.gateway.CrossrefGateway;
+import at.tuwien.gateway.CrossRefServiceGateway;
 import at.tuwien.gateway.OrcidGateway;
 import at.tuwien.gateway.RorGateway;
 import at.tuwien.mapper.MetadataMapper;
@@ -39,21 +39,21 @@ public class MetadataServiceImpl implements MetadataService {
     private final MetadataConfig metadataConfig;
     private final MetadataMapper metadataMapper;
     private final TemplateEngine templateEngine;
-    private final CrossrefGateway crossrefGateway;
+    private final CrossRefServiceGateway CrossRefServiceGateway;
     private final IdentifierService identifierService;
     private final IdentifierRepository identifierRepository;
 
     @Autowired
     public MetadataServiceImpl(RorGateway rorGateway, OrcidGateway orcidGateway, MetadataConfig metadataConfig,
                                MetadataMapper metadataMapper, TemplateEngine templateEngine,
-                               CrossrefGateway crossrefGateway, IdentifierService identifierService,
+                               CrossRefServiceGateway CrossRefServiceGateway, IdentifierService identifierService,
                                IdentifierRepository identifierRepository) {
         this.rorGateway = rorGateway;
         this.orcidGateway = orcidGateway;
         this.metadataConfig = metadataConfig;
         this.metadataMapper = metadataMapper;
         this.templateEngine = templateEngine;
-        this.crossrefGateway = crossrefGateway;
+        this.CrossRefServiceGateway = CrossRefServiceGateway;
         this.identifierService = identifierService;
         this.identifierRepository = identifierRepository;
     }
@@ -178,7 +178,7 @@ public class MetadataServiceImpl implements MetadataService {
                 throw new RorNotFoundException("Failed to find metadata from CrossRef URL: too short");
             }
             final String id = url.substring(idx + 8);
-            final CrossrefDto crossrefDto = crossrefGateway.findById(id);
+            final CrossrefDto crossrefDto = CrossRefServiceGateway.findById(id);
             return metadataMapper.crossrefDtoToExternalMetadataDto(crossrefDto);
         }
         log.error("Failed to find metadata: unsupported identifier {}", url);
-- 
GitLab


From a7a28c2b9f84b7f141fb962cb8459be0cd79bb15 Mon Sep 17 00:00:00 2001
From: Martin Weise <martin.weise@tuwien.ac.at>
Date: Mon, 31 Mar 2025 19:27:41 +0200
Subject: [PATCH 2/4] WIP

Signed-off-by: Martin Weise <martin.weise@tuwien.ac.at>
---
 .../dbrepo/core/mapper/MetadataMapper.java    | 148 +++++++++---------
 1 file changed, 77 insertions(+), 71 deletions(-)

diff --git a/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/mapper/MetadataMapper.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/mapper/MetadataMapper.java
index 14df1ef609..3db28cc7d6 100644
--- a/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/mapper/MetadataMapper.java
+++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/mapper/MetadataMapper.java
@@ -1,76 +1,82 @@
 package at.ac.tuwien.ifs.dbrepo.core.mapper;
 
-import at.tuwien.api.container.ContainerBriefDto;
-import at.tuwien.api.container.ContainerDto;
-import at.tuwien.api.container.CreateContainerDto;
-import at.tuwien.api.container.image.DataTypeDto;
-import at.tuwien.api.container.image.ImageBriefDto;
-import at.tuwien.api.container.image.ImageCreateDto;
-import at.tuwien.api.container.image.ImageDto;
-import at.tuwien.api.crossref.CrossrefDto;
-import at.tuwien.api.database.*;
-import at.tuwien.api.database.table.TableBriefDto;
-import at.tuwien.api.database.table.TableDto;
-import at.tuwien.api.database.table.columns.ColumnBriefDto;
-import at.tuwien.api.database.table.columns.ColumnDto;
-import at.tuwien.api.database.table.columns.CreateTableColumnDto;
-import at.tuwien.api.database.table.columns.concepts.ConceptDto;
-import at.tuwien.api.database.table.columns.concepts.ConceptSaveDto;
-import at.tuwien.api.database.table.columns.concepts.UnitDto;
-import at.tuwien.api.database.table.columns.concepts.UnitSaveDto;
-import at.tuwien.api.database.table.constraints.ConstraintsDto;
-import at.tuwien.api.database.table.constraints.CreateTableConstraintsDto;
-import at.tuwien.api.database.table.constraints.foreign.ForeignKeyBriefDto;
-import at.tuwien.api.database.table.constraints.foreign.ForeignKeyDto;
-import at.tuwien.api.database.table.constraints.foreign.ForeignKeyReferenceDto;
-import at.tuwien.api.database.table.constraints.foreign.ReferenceTypeDto;
-import at.tuwien.api.database.table.constraints.primary.PrimaryKeyDto;
-import at.tuwien.api.database.table.constraints.unique.UniqueDto;
-import at.tuwien.api.datacite.doi.*;
-import at.tuwien.api.identifier.*;
-import at.tuwien.api.identifier.ld.LdCreatorDto;
-import at.tuwien.api.identifier.ld.LdDatasetDto;
-import at.tuwien.api.keycloak.TokenDto;
-import at.tuwien.api.keycloak.UserCreateDto;
-import at.tuwien.api.maintenance.BannerMessageBriefDto;
-import at.tuwien.api.maintenance.BannerMessageCreateDto;
-import at.tuwien.api.maintenance.BannerMessageDto;
-import at.tuwien.api.maintenance.BannerMessageTypeDto;
-import at.tuwien.api.orcid.OrcidDto;
-import at.tuwien.api.orcid.activities.employments.affiliation.OrcidAffiliationGroupDto;
-import at.tuwien.api.orcid.activities.employments.affiliation.group.OrcidEmploymentSummaryDto;
-import at.tuwien.api.orcid.activities.employments.affiliation.group.summary.organization.disambiguated.OrcidDisambiguatedDto;
-import at.tuwien.api.orcid.activities.employments.affiliation.group.summary.organization.disambiguated.OrcidDisambiguatedSourceTypeDto;
-import at.tuwien.api.ror.RorDto;
-import at.tuwien.api.semantics.EntityDto;
-import at.tuwien.api.semantics.OntologyBriefDto;
-import at.tuwien.api.semantics.OntologyCreateDto;
-import at.tuwien.api.semantics.OntologyDto;
-import at.tuwien.api.user.UserBriefDto;
-import at.tuwien.api.user.UserDto;
-import at.tuwien.api.user.UserUpdateDto;
-import at.tuwien.api.user.external.ExternalMetadataDto;
-import at.tuwien.api.user.external.ExternalResultType;
-import at.tuwien.api.user.external.affiliation.ExternalAffiliationDto;
-import at.tuwien.entities.container.Container;
-import at.tuwien.entities.container.image.ContainerImage;
-import at.tuwien.entities.container.image.DataType;
-import at.tuwien.entities.database.*;
-import at.tuwien.entities.database.table.Table;
-import at.tuwien.entities.database.table.columns.TableColumn;
-import at.tuwien.entities.database.table.columns.TableColumnConcept;
-import at.tuwien.entities.database.table.columns.TableColumnUnit;
-import at.tuwien.entities.database.table.constraints.Constraints;
-import at.tuwien.entities.database.table.constraints.foreignKey.ForeignKey;
-import at.tuwien.entities.database.table.constraints.foreignKey.ForeignKeyReference;
-import at.tuwien.entities.database.table.constraints.foreignKey.ReferenceType;
-import at.tuwien.entities.database.table.constraints.primaryKey.PrimaryKey;
-import at.tuwien.entities.database.table.constraints.unique.Unique;
-import at.tuwien.entities.identifier.*;
-import at.tuwien.entities.maintenance.BannerMessage;
-import at.tuwien.entities.maintenance.BannerMessageType;
-import at.tuwien.entities.semantics.Ontology;
-import at.tuwien.entities.user.User;
+import at.ac.tuwien.ifs.dbrepo.core.api.container.ContainerBriefDto;
+import at.ac.tuwien.ifs.dbrepo.core.api.container.ContainerDto;
+import at.ac.tuwien.ifs.dbrepo.core.api.container.CreateContainerDto;
+import at.ac.tuwien.ifs.dbrepo.core.api.container.image.DataTypeDto;
+import at.ac.tuwien.ifs.dbrepo.core.api.container.image.ImageBriefDto;
+import at.ac.tuwien.ifs.dbrepo.core.api.container.image.ImageCreateDto;
+import at.ac.tuwien.ifs.dbrepo.core.api.container.image.ImageDto;
+import at.ac.tuwien.ifs.dbrepo.core.api.crossref.CrossrefDto;
+import at.ac.tuwien.ifs.dbrepo.core.api.database.*;
+import at.ac.tuwien.ifs.dbrepo.core.api.database.table.TableBriefDto;
+import at.ac.tuwien.ifs.dbrepo.core.api.database.table.TableDto;
+import at.ac.tuwien.ifs.dbrepo.core.api.database.table.columns.ColumnBriefDto;
+import at.ac.tuwien.ifs.dbrepo.core.api.database.table.columns.ColumnDto;
+import at.ac.tuwien.ifs.dbrepo.core.api.database.table.columns.CreateTableColumnDto;
+import at.ac.tuwien.ifs.dbrepo.core.api.database.table.columns.concepts.*;
+import at.ac.tuwien.ifs.dbrepo.core.api.database.table.constraints.ConstraintsDto;
+import at.ac.tuwien.ifs.dbrepo.core.api.database.table.constraints.CreateTableConstraintsDto;
+import at.ac.tuwien.ifs.dbrepo.core.api.database.table.constraints.foreign.ForeignKeyBriefDto;
+import at.ac.tuwien.ifs.dbrepo.core.api.database.table.constraints.foreign.ForeignKeyDto;
+import at.ac.tuwien.ifs.dbrepo.core.api.database.table.constraints.foreign.ForeignKeyReferenceDto;
+import at.ac.tuwien.ifs.dbrepo.core.api.database.table.constraints.foreign.ReferenceTypeDto;
+import at.ac.tuwien.ifs.dbrepo.core.api.database.table.constraints.primary.PrimaryKeyDto;
+import at.ac.tuwien.ifs.dbrepo.core.api.database.table.constraints.unique.UniqueDto;
+import at.ac.tuwien.ifs.dbrepo.core.api.datacite.doi.*;
+import at.ac.tuwien.ifs.dbrepo.core.api.grafana.CreateDashboardDto;
+import at.ac.tuwien.ifs.dbrepo.core.api.grafana.PermissionTypeDto;
+import at.ac.tuwien.ifs.dbrepo.core.api.identifier.*;
+import at.ac.tuwien.ifs.dbrepo.core.api.identifier.ld.LdCreatorDto;
+import at.ac.tuwien.ifs.dbrepo.core.api.identifier.ld.LdDatasetDto;
+import at.ac.tuwien.ifs.dbrepo.core.api.keycloak.TokenDto;
+import at.ac.tuwien.ifs.dbrepo.core.api.keycloak.UserCreateDto;
+import at.ac.tuwien.ifs.dbrepo.core.api.maintenance.BannerMessageBriefDto;
+import at.ac.tuwien.ifs.dbrepo.core.api.maintenance.BannerMessageCreateDto;
+import at.ac.tuwien.ifs.dbrepo.core.api.maintenance.BannerMessageDto;
+import at.ac.tuwien.ifs.dbrepo.core.api.maintenance.BannerMessageTypeDto;
+import at.ac.tuwien.ifs.dbrepo.core.api.orcid.OrcidDto;
+import at.ac.tuwien.ifs.dbrepo.core.api.orcid.activities.OrcidActivitiesSummaryDto;
+import at.ac.tuwien.ifs.dbrepo.core.api.orcid.activities.employments.OrcidEmploymentsDto;
+import at.ac.tuwien.ifs.dbrepo.core.api.orcid.activities.employments.affiliation.OrcidAffiliationGroupDto;
+import at.ac.tuwien.ifs.dbrepo.core.api.orcid.activities.employments.affiliation.group.OrcidEmploymentSummaryDto;
+import at.ac.tuwien.ifs.dbrepo.core.api.orcid.activities.employments.affiliation.group.summary.OrcidSummaryDto;
+import at.ac.tuwien.ifs.dbrepo.core.api.orcid.activities.employments.affiliation.group.summary.organization.OrcidOrganizationDto;
+import at.ac.tuwien.ifs.dbrepo.core.api.orcid.activities.employments.affiliation.group.summary.organization.disambiguated.OrcidDisambiguatedDto;
+import at.ac.tuwien.ifs.dbrepo.core.api.orcid.activities.employments.affiliation.group.summary.organization.disambiguated.OrcidDisambiguatedSourceTypeDto;
+import at.ac.tuwien.ifs.dbrepo.core.api.orcid.person.OrcidPersonDto;
+import at.ac.tuwien.ifs.dbrepo.core.api.orcid.person.name.OrcidNameDto;
+import at.ac.tuwien.ifs.dbrepo.core.api.orcid.person.name.OrcidValueDto;
+import at.ac.tuwien.ifs.dbrepo.core.api.ror.RorDto;
+import at.ac.tuwien.ifs.dbrepo.core.api.semantics.EntityDto;
+import at.ac.tuwien.ifs.dbrepo.core.api.semantics.OntologyBriefDto;
+import at.ac.tuwien.ifs.dbrepo.core.api.semantics.OntologyCreateDto;
+import at.ac.tuwien.ifs.dbrepo.core.api.semantics.OntologyDto;
+import at.ac.tuwien.ifs.dbrepo.core.api.user.UserBriefDto;
+import at.ac.tuwien.ifs.dbrepo.core.api.user.UserDto;
+import at.ac.tuwien.ifs.dbrepo.core.api.user.UserUpdateDto;
+import at.ac.tuwien.ifs.dbrepo.core.api.user.external.ExternalMetadataDto;
+import at.ac.tuwien.ifs.dbrepo.core.api.user.external.ExternalResultType;
+import at.ac.tuwien.ifs.dbrepo.core.api.user.external.affiliation.ExternalAffiliationDto;
+import at.ac.tuwien.ifs.dbrepo.core.entity.container.Container;
+import at.ac.tuwien.ifs.dbrepo.core.entity.container.image.ContainerImage;
+import at.ac.tuwien.ifs.dbrepo.core.entity.container.image.DataType;
+import at.ac.tuwien.ifs.dbrepo.core.entity.database.*;
+import at.ac.tuwien.ifs.dbrepo.core.entity.database.table.Table;
+import at.ac.tuwien.ifs.dbrepo.core.entity.database.table.columns.TableColumn;
+import at.ac.tuwien.ifs.dbrepo.core.entity.database.table.columns.TableColumnConcept;
+import at.ac.tuwien.ifs.dbrepo.core.entity.database.table.columns.TableColumnUnit;
+import at.ac.tuwien.ifs.dbrepo.core.entity.database.table.constraints.Constraints;
+import at.ac.tuwien.ifs.dbrepo.core.entity.database.table.constraints.foreignKey.ForeignKey;
+import at.ac.tuwien.ifs.dbrepo.core.entity.database.table.constraints.foreignKey.ForeignKeyReference;
+import at.ac.tuwien.ifs.dbrepo.core.entity.database.table.constraints.foreignKey.ReferenceType;
+import at.ac.tuwien.ifs.dbrepo.core.entity.database.table.constraints.primaryKey.PrimaryKey;
+import at.ac.tuwien.ifs.dbrepo.core.entity.database.table.constraints.unique.Unique;
+import at.ac.tuwien.ifs.dbrepo.core.entity.identifier.*;
+import at.ac.tuwien.ifs.dbrepo.core.entity.maintenance.BannerMessage;
+import at.ac.tuwien.ifs.dbrepo.core.entity.maintenance.BannerMessageType;
+import at.ac.tuwien.ifs.dbrepo.core.entity.semantics.Ontology;
+import at.ac.tuwien.ifs.dbrepo.core.entity.user.User;
 import org.keycloak.representations.AccessTokenResponse;
 import org.keycloak.representations.idm.UserRepresentation;
 import org.mapstruct.*;
-- 
GitLab


From 49d6b2787ead90a95775f5604f0396a12a322424 Mon Sep 17 00:00:00 2001
From: Martin Weise <martin.weise@tuwien.ac.at>
Date: Mon, 31 Mar 2025 19:54:08 +0200
Subject: [PATCH 3/4] WIP

Signed-off-by: Martin Weise <martin.weise@tuwien.ac.at>
---
 ...Test.java => CrossRefGatewayUnitTest.java} | 21 +++-------
 .../service/MetadataServiceUnitTest.java      | 36 ++++++++--------
 .../ifs/dbrepo/gateway/CrossRefGateway.java   | 16 +++++++
 .../gateway/impl/CrossRefGatewayImpl.java     | 42 +++++++++++++++++++
 .../service/impl/MetadataServiceImpl.java     | 40 +++++++++---------
 .../{CrossrefDto.java => CrossRefDto.java}    |  6 +--
 ...rmDto.java => CrossRefLiteralFormDto.java} |  2 +-
 ...refLabelDto.java => CrossRefLabelDto.java} |  6 +--
 ...abelDto.java => CrossRefPrefLabelDto.java} |  4 +-
 .../dbrepo/core/mapper/MetadataMapper.java    |  4 +-
 10 files changed, 114 insertions(+), 63 deletions(-)
 rename dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/gateway/{CrossrefGatewayUnitTest.java => CrossRefGatewayUnitTest.java} (64%)
 create mode 100644 dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/gateway/CrossRefGateway.java
 create mode 100644 dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/gateway/impl/CrossRefGatewayImpl.java
 rename lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/crossref/{CrossrefDto.java => CrossRefDto.java} (73%)
 rename lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/crossref/form/{CrossrefLiteralFormDto.java => CrossRefLiteralFormDto.java} (91%)
 rename lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/crossref/label/{CrossrefLabelDto.java => CrossRefLabelDto.java} (73%)
 rename lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/crossref/label/{CrossrefPrefLabelDto.java => CrossRefPrefLabelDto.java} (81%)

diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/gateway/CrossrefGatewayUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/gateway/CrossRefGatewayUnitTest.java
similarity index 64%
rename from dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/gateway/CrossrefGatewayUnitTest.java
rename to dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/gateway/CrossRefGatewayUnitTest.java
index 44b6fd2567..7513622f37 100644
--- a/dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/gateway/CrossrefGatewayUnitTest.java
+++ b/dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/gateway/CrossRefGatewayUnitTest.java
@@ -1,18 +1,13 @@
 package at.ac.tuwien.ifs.dbrepo.gateway;
 
-<<<<<<<< HEAD:dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/gateway/CrossRefGatewayUnitTest.java
-import at.tuwien.api.crossref.CrossrefDto;
-import at.tuwien.exception.DoiNotFoundException;
-import at.tuwien.test.AbstractUnitTest;
-========
-import at.ac.tuwien.ifs.dbrepo.core.api.crossref.CrossrefDto;
+import at.ac.tuwien.ifs.dbrepo.core.api.crossref.CrossRefDto;
 import at.ac.tuwien.ifs.dbrepo.core.exception.DoiNotFoundException;
 import at.ac.tuwien.ifs.dbrepo.core.test.BaseTest;
->>>>>>>> dev:dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/gateway/CrossrefGatewayUnitTest.java
 import lombok.extern.log4j.Log4j2;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.ExtendWith;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
 import org.springframework.boot.test.context.SpringBootTest;
 import org.springframework.boot.test.mock.mockito.MockBean;
 import org.springframework.http.HttpEntity;
@@ -29,24 +24,20 @@ import static org.mockito.Mockito.*;
 @Log4j2
 @SpringBootTest
 @ExtendWith(SpringExtension.class)
-<<<<<<<< HEAD:dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/gateway/CrossRefGatewayUnitTest.java
-public class CrossRefGatewayUnitTest extends AbstractUnitTest {
-========
-public class CrossrefGatewayUnitTest extends BaseTest {
->>>>>>>> dev:dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/gateway/CrossrefGatewayUnitTest.java
+public class CrossRefGatewayUnitTest extends BaseTest {
 
     @MockBean
     @Qualifier("crossRefServiceRestTemplate")
     private RestTemplate restTemplate;
 
     @Autowired
-    private CrossRefServiceGateway crossRefGateway;
+    private CrossRefGateway crossRefGateway;
 
     @Test
     public void findById_succeeds() throws DoiNotFoundException {
 
         /* mock */
-        when(restTemplate.exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(CrossrefDto.class)))
+        when(restTemplate.exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(CrossRefDto.class)))
                 .thenReturn(ResponseEntity.status(HttpStatus.OK)
                         .build());
 
@@ -60,7 +51,7 @@ public class CrossrefGatewayUnitTest extends BaseTest {
         /* mock */
         doThrow(HttpServerErrorException.class)
                 .when(restTemplate)
-                .exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(CrossrefDto.class));
+                .exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(CrossRefDto.class));
 
         /* test */
         assertThrows(DoiNotFoundException.class, () -> {
diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/service/MetadataServiceUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/service/MetadataServiceUnitTest.java
index cb1e168978..f96d6807f0 100644
--- a/dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/service/MetadataServiceUnitTest.java
+++ b/dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/service/MetadataServiceUnitTest.java
@@ -1,18 +1,18 @@
 package at.ac.tuwien.ifs.dbrepo.service;
 
-import at.tuwien.api.crossref.CrossrefDto;
-import at.tuwien.api.orcid.OrcidDto;
-import at.tuwien.api.ror.RorDto;
-import at.tuwien.api.user.external.ExternalMetadataDto;
-import at.tuwien.api.user.external.affiliation.ExternalAffiliationDto;
-import at.tuwien.exception.*;
-import at.tuwien.gateway.CrossrefGateway;
-import at.tuwien.gateway.OrcidGateway;
-import at.tuwien.gateway.RorGateway;
-import at.tuwien.oaipmh.OaiErrorType;
-import at.tuwien.oaipmh.OaiListIdentifiersParameters;
-import at.tuwien.oaipmh.OaiRecordParameters;
-import at.tuwien.test.AbstractUnitTest;
+import at.ac.tuwien.ifs.dbrepo.core.api.crossref.CrossRefDto;
+import at.ac.tuwien.ifs.dbrepo.core.api.orcid.OrcidDto;
+import at.ac.tuwien.ifs.dbrepo.core.api.ror.RorDto;
+import at.ac.tuwien.ifs.dbrepo.core.api.user.external.ExternalMetadataDto;
+import at.ac.tuwien.ifs.dbrepo.core.api.user.external.affiliation.ExternalAffiliationDto;
+import at.ac.tuwien.ifs.dbrepo.core.exception.*;
+import at.ac.tuwien.ifs.dbrepo.core.test.BaseTest;
+import at.ac.tuwien.ifs.dbrepo.gateway.CrossRefGateway;
+import at.ac.tuwien.ifs.dbrepo.gateway.OrcidGateway;
+import at.ac.tuwien.ifs.dbrepo.gateway.RorGateway;
+import at.ac.tuwien.ifs.dbrepo.oaipmh.OaiErrorType;
+import at.ac.tuwien.ifs.dbrepo.oaipmh.OaiListIdentifiersParameters;
+import at.ac.tuwien.ifs.dbrepo.oaipmh.OaiRecordParameters;
 import com.fasterxml.jackson.databind.DeserializationFeature;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import lombok.extern.log4j.Log4j2;
@@ -48,7 +48,7 @@ public class MetadataServiceUnitTest extends BaseTest {
     private RorGateway rorGateway;
 
     @MockBean
-    private CrossRefServiceGateway crossrefGateway;
+    private CrossRefGateway crossRefGateway;
 
     @MockBean
     private IdentifierService identifierService;
@@ -203,11 +203,11 @@ public class MetadataServiceUnitTest extends BaseTest {
     @Test
     public void findByUrl_doi_succeeds() throws OrcidNotFoundException, RorNotFoundException, IOException,
             DoiNotFoundException, IdentifierNotSupportedException {
-        final CrossrefDto doi = objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
-                .readValue(new File("src/test/resources/json/doi_ec.json"), CrossrefDto.class);
+        final CrossRefDto doi = objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
+                .readValue(new File("src/test/resources/json/doi_ec.json"), CrossRefDto.class);
 
         /* mock */
-        when(crossrefGateway.findById(FUNDER_1_IDENTIFIER_ID_ONLY))
+        when(crossRefGateway.findById(FUNDER_1_IDENTIFIER_ID_ONLY))
                 .thenReturn(doi);
 
         /* test */
@@ -223,7 +223,7 @@ public class MetadataServiceUnitTest extends BaseTest {
 
         /* mock */
         doThrow(DoiNotFoundException.class)
-                .when(crossrefGateway)
+                .when(crossRefGateway)
                 .findById(anyString());
 
         /* test */
diff --git a/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/gateway/CrossRefGateway.java b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/gateway/CrossRefGateway.java
new file mode 100644
index 0000000000..83b0446827
--- /dev/null
+++ b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/gateway/CrossRefGateway.java
@@ -0,0 +1,16 @@
+package at.ac.tuwien.ifs.dbrepo.gateway;
+
+import at.ac.tuwien.ifs.dbrepo.core.api.crossref.CrossRefDto;
+import at.ac.tuwien.ifs.dbrepo.core.exception.DoiNotFoundException;
+
+public interface CrossRefGateway {
+
+    /**
+     * Retrieves metadata from the CrossRef funder database for a given CrossRef id.
+     *
+     * @param id The CrossRef id.
+     * @return The CrossRef metadata from the CrossRef funder database.
+     * @throws DoiNotFoundException The metadata was not found in the CrossRef funder database.
+     */
+    CrossRefDto findById(String id) throws DoiNotFoundException;
+}
diff --git a/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/gateway/impl/CrossRefGatewayImpl.java b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/gateway/impl/CrossRefGatewayImpl.java
new file mode 100644
index 0000000000..2c3f77dd4c
--- /dev/null
+++ b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/gateway/impl/CrossRefGatewayImpl.java
@@ -0,0 +1,42 @@
+package at.ac.tuwien.ifs.dbrepo.gateway.impl;
+
+import at.ac.tuwien.ifs.dbrepo.core.api.crossref.CrossRefDto;
+import at.ac.tuwien.ifs.dbrepo.config.GatewayConfig;
+import at.ac.tuwien.ifs.dbrepo.core.exception.DoiNotFoundException;
+import at.ac.tuwien.ifs.dbrepo.gateway.CrossRefGateway;
+import lombok.extern.log4j.Log4j2;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpEntity;
+import org.springframework.http.HttpMethod;
+import org.springframework.http.ResponseEntity;
+import org.springframework.stereotype.Service;
+import org.springframework.web.client.HttpServerErrorException;
+import org.springframework.web.client.RestTemplate;
+
+@Log4j2
+@Service
+public class CrossRefGatewayImpl implements CrossRefGateway {
+
+    private final RestTemplate restTemplate;
+    private final GatewayConfig gatewayConfig;
+
+    @Autowired
+    public CrossRefGatewayImpl(RestTemplate restTemplate, GatewayConfig gatewayConfig) {
+        this.restTemplate = restTemplate;
+        this.gatewayConfig = gatewayConfig;
+    }
+
+    @Override
+    public CrossRefDto findById(String id) throws DoiNotFoundException {
+        final String path = "/fundingdata/funder/" + id;
+        log.trace("find crossref metadata by id from endpoint {} with path {}", gatewayConfig.getCrossRefEndpoint(), path);
+        final ResponseEntity<CrossRefDto> response;
+        try {
+            response = restTemplate.exchange(gatewayConfig.getCrossRefEndpoint() + path, HttpMethod.GET, HttpEntity.EMPTY, CrossRefDto.class);
+        } catch (HttpServerErrorException e) {
+            log.error("Failed to retrieve crossref metadata: {}", e.getMessage());
+            throw new DoiNotFoundException("Failed to retrieve crossref metadata: " + e.getMessage(), e);
+        }
+        return response.getBody();
+    }
+}
\ No newline at end of file
diff --git a/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/service/impl/MetadataServiceImpl.java b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/service/impl/MetadataServiceImpl.java
index fd340b5086..1c4376184a 100644
--- a/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/service/impl/MetadataServiceImpl.java
+++ b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/service/impl/MetadataServiceImpl.java
@@ -1,22 +1,22 @@
 package at.ac.tuwien.ifs.dbrepo.service.impl;
 
-import at.tuwien.api.crossref.CrossrefDto;
-import at.tuwien.api.orcid.OrcidDto;
-import at.tuwien.api.ror.RorDto;
-import at.tuwien.api.user.external.ExternalMetadataDto;
-import at.tuwien.config.MetadataConfig;
-import at.tuwien.entities.identifier.Identifier;
-import at.tuwien.exception.*;
-import at.tuwien.gateway.CrossrefGateway;
-import at.tuwien.gateway.OrcidGateway;
-import at.tuwien.gateway.RorGateway;
-import at.tuwien.mapper.MetadataMapper;
-import at.tuwien.oaipmh.OaiErrorType;
-import at.tuwien.oaipmh.OaiListIdentifiersParameters;
-import at.tuwien.oaipmh.OaiRecordParameters;
-import at.tuwien.repository.IdentifierRepository;
-import at.tuwien.service.IdentifierService;
-import at.tuwien.service.MetadataService;
+import at.ac.tuwien.ifs.dbrepo.config.MetadataConfig;
+import at.ac.tuwien.ifs.dbrepo.core.api.crossref.CrossRefDto;
+import at.ac.tuwien.ifs.dbrepo.core.api.orcid.OrcidDto;
+import at.ac.tuwien.ifs.dbrepo.core.api.ror.RorDto;
+import at.ac.tuwien.ifs.dbrepo.core.api.user.external.ExternalMetadataDto;
+import at.ac.tuwien.ifs.dbrepo.core.entity.identifier.Identifier;
+import at.ac.tuwien.ifs.dbrepo.core.exception.*;
+import at.ac.tuwien.ifs.dbrepo.core.mapper.MetadataMapper;
+import at.ac.tuwien.ifs.dbrepo.gateway.CrossRefGateway;
+import at.ac.tuwien.ifs.dbrepo.gateway.OrcidGateway;
+import at.ac.tuwien.ifs.dbrepo.gateway.RorGateway;
+import at.ac.tuwien.ifs.dbrepo.oaipmh.OaiErrorType;
+import at.ac.tuwien.ifs.dbrepo.oaipmh.OaiListIdentifiersParameters;
+import at.ac.tuwien.ifs.dbrepo.oaipmh.OaiRecordParameters;
+import at.ac.tuwien.ifs.dbrepo.repository.IdentifierRepository;
+import at.ac.tuwien.ifs.dbrepo.service.IdentifierService;
+import at.ac.tuwien.ifs.dbrepo.service.MetadataService;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
@@ -39,19 +39,21 @@ public class MetadataServiceImpl implements MetadataService {
     private final MetadataConfig metadataConfig;
     private final MetadataMapper metadataMapper;
     private final TemplateEngine templateEngine;
+    private final CrossRefGateway crossRefGateway;
     private final IdentifierService identifierService;
     private final IdentifierRepository identifierRepository;
 
     @Autowired
     public MetadataServiceImpl(RorGateway rorGateway, OrcidGateway orcidGateway, MetadataConfig metadataConfig,
                                MetadataMapper metadataMapper, TemplateEngine templateEngine,
-                               IdentifierService identifierService,
+                               CrossRefGateway crossRefGateway, IdentifierService identifierService,
                                IdentifierRepository identifierRepository) {
         this.rorGateway = rorGateway;
         this.orcidGateway = orcidGateway;
         this.metadataConfig = metadataConfig;
         this.metadataMapper = metadataMapper;
         this.templateEngine = templateEngine;
+        this.crossRefGateway = crossRefGateway;
         this.identifierService = identifierService;
         this.identifierRepository = identifierRepository;
     }
@@ -175,7 +177,7 @@ public class MetadataServiceImpl implements MetadataService {
                 throw new RorNotFoundException("Failed to find metadata from CrossRef URL: too short");
             }
             final String id = url.substring(idx + 8);
-            final CrossrefDto crossrefDto = CrossRefServiceGateway.findById(id);
+            final CrossRefDto crossrefDto = crossRefGateway.findById(id);
             return metadataMapper.crossrefDtoToExternalMetadataDto(crossrefDto);
         }
         log.error("Failed to find metadata: unsupported identifier {}", url);
diff --git a/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/crossref/CrossrefDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/crossref/CrossRefDto.java
similarity index 73%
rename from lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/crossref/CrossrefDto.java
rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/crossref/CrossRefDto.java
index cd4afbb463..f32d2d4125 100644
--- a/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/crossref/CrossrefDto.java
+++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/crossref/CrossRefDto.java
@@ -1,6 +1,6 @@
 package at.ac.tuwien.ifs.dbrepo.core.api.crossref;
 
-import at.ac.tuwien.ifs.dbrepo.core.api.crossref.label.CrossrefPrefLabelDto;
+import at.ac.tuwien.ifs.dbrepo.core.api.crossref.label.CrossRefPrefLabelDto;
 import io.swagger.v3.oas.annotations.media.Schema;
 import lombok.*;
 import lombok.extern.jackson.Jacksonized;
@@ -13,11 +13,11 @@ import lombok.extern.jackson.Jacksonized;
 @AllArgsConstructor
 @Jacksonized
 @ToString
-public class CrossrefDto {
+public class CrossRefDto {
 
     @Schema(example = "https://doi.org/10.13039/100000001")
     private String id;
 
-    private CrossrefPrefLabelDto prefLabel;
+    private CrossRefPrefLabelDto prefLabel;
 
 }
diff --git a/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/crossref/form/CrossrefLiteralFormDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/crossref/form/CrossRefLiteralFormDto.java
similarity index 91%
rename from lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/crossref/form/CrossrefLiteralFormDto.java
rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/crossref/form/CrossRefLiteralFormDto.java
index 060cb73885..473937a111 100644
--- a/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/crossref/form/CrossrefLiteralFormDto.java
+++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/crossref/form/CrossRefLiteralFormDto.java
@@ -12,7 +12,7 @@ import lombok.extern.jackson.Jacksonized;
 @AllArgsConstructor
 @Jacksonized
 @ToString
-public class CrossrefLiteralFormDto {
+public class CrossRefLiteralFormDto {
 
     @Schema(example = "en")
     private String lang;
diff --git a/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/crossref/label/CrossrefLabelDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/crossref/label/CrossRefLabelDto.java
similarity index 73%
rename from lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/crossref/label/CrossrefLabelDto.java
rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/crossref/label/CrossRefLabelDto.java
index 5ee179f328..684557115f 100644
--- a/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/crossref/label/CrossrefLabelDto.java
+++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/crossref/label/CrossRefLabelDto.java
@@ -1,6 +1,6 @@
 package at.ac.tuwien.ifs.dbrepo.core.api.crossref.label;
 
-import at.ac.tuwien.ifs.dbrepo.core.api.crossref.form.CrossrefLiteralFormDto;
+import at.ac.tuwien.ifs.dbrepo.core.api.crossref.form.CrossRefLiteralFormDto;
 import io.swagger.v3.oas.annotations.media.Schema;
 import lombok.*;
 import lombok.extern.jackson.Jacksonized;
@@ -13,9 +13,9 @@ import lombok.extern.jackson.Jacksonized;
 @AllArgsConstructor
 @Jacksonized
 @ToString
-public class CrossrefLabelDto {
+public class CrossRefLabelDto {
 
-    private CrossrefLiteralFormDto literalForm;
+    private CrossRefLiteralFormDto literalForm;
 
     @Schema(example = "http://data.crossref.org/fundingdata/vocabulary/Label-36515")
     private String about;
diff --git a/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/crossref/label/CrossrefPrefLabelDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/crossref/label/CrossRefPrefLabelDto.java
similarity index 81%
rename from lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/crossref/label/CrossrefPrefLabelDto.java
rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/crossref/label/CrossRefPrefLabelDto.java
index b64b9785f3..0ec889622b 100644
--- a/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/crossref/label/CrossrefPrefLabelDto.java
+++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/crossref/label/CrossRefPrefLabelDto.java
@@ -12,9 +12,9 @@ import lombok.extern.jackson.Jacksonized;
 @AllArgsConstructor
 @Jacksonized
 @ToString
-public class CrossrefPrefLabelDto {
+public class CrossRefPrefLabelDto {
 
     @JsonProperty("Label")
-    private CrossrefLabelDto label;
+    private CrossRefLabelDto label;
 
 }
diff --git a/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/mapper/MetadataMapper.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/mapper/MetadataMapper.java
index 3db28cc7d6..e6c354e35e 100644
--- a/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/mapper/MetadataMapper.java
+++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/mapper/MetadataMapper.java
@@ -7,7 +7,7 @@ import at.ac.tuwien.ifs.dbrepo.core.api.container.image.DataTypeDto;
 import at.ac.tuwien.ifs.dbrepo.core.api.container.image.ImageBriefDto;
 import at.ac.tuwien.ifs.dbrepo.core.api.container.image.ImageCreateDto;
 import at.ac.tuwien.ifs.dbrepo.core.api.container.image.ImageDto;
-import at.ac.tuwien.ifs.dbrepo.core.api.crossref.CrossrefDto;
+import at.ac.tuwien.ifs.dbrepo.core.api.crossref.CrossRefDto;
 import at.ac.tuwien.ifs.dbrepo.core.api.database.*;
 import at.ac.tuwien.ifs.dbrepo.core.api.database.table.TableBriefDto;
 import at.ac.tuwien.ifs.dbrepo.core.api.database.table.TableDto;
@@ -355,7 +355,7 @@ public interface MetadataMapper {
                 .build();
     }
 
-    default ExternalMetadataDto crossrefDtoToExternalMetadataDto(CrossrefDto data) {
+    default ExternalMetadataDto crossrefDtoToExternalMetadataDto(CrossRefDto data) {
         return ExternalMetadataDto.builder()
                 .affiliations(new ExternalAffiliationDto[]{
                         ExternalAffiliationDto.builder()
-- 
GitLab


From c1a3efc9b4e2c5543ed24dd0ca1cca7f9eb33228 Mon Sep 17 00:00:00 2001
From: Martin Weise <martin.weise@tuwien.ac.at>
Date: Mon, 31 Mar 2025 21:16:50 +0200
Subject: [PATCH 4/4] WIP

Signed-off-by: Martin Weise <martin.weise@tuwien.ac.at>
---
 .../tuwien/ifs/dbrepo/gateway/impl/CrossRefGatewayImpl.java | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/gateway/impl/CrossRefGatewayImpl.java b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/gateway/impl/CrossRefGatewayImpl.java
index 2c3f77dd4c..559f3b7657 100644
--- a/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/gateway/impl/CrossRefGatewayImpl.java
+++ b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/gateway/impl/CrossRefGatewayImpl.java
@@ -1,11 +1,12 @@
 package at.ac.tuwien.ifs.dbrepo.gateway.impl;
 
-import at.ac.tuwien.ifs.dbrepo.core.api.crossref.CrossRefDto;
 import at.ac.tuwien.ifs.dbrepo.config.GatewayConfig;
+import at.ac.tuwien.ifs.dbrepo.core.api.crossref.CrossRefDto;
 import at.ac.tuwien.ifs.dbrepo.core.exception.DoiNotFoundException;
 import at.ac.tuwien.ifs.dbrepo.gateway.CrossRefGateway;
 import lombok.extern.log4j.Log4j2;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
 import org.springframework.http.HttpEntity;
 import org.springframework.http.HttpMethod;
 import org.springframework.http.ResponseEntity;
@@ -21,7 +22,8 @@ public class CrossRefGatewayImpl implements CrossRefGateway {
     private final GatewayConfig gatewayConfig;
 
     @Autowired
-    public CrossRefGatewayImpl(RestTemplate restTemplate, GatewayConfig gatewayConfig) {
+    public CrossRefGatewayImpl(@Qualifier("crossRefServiceRestTemplate") RestTemplate restTemplate,
+                               GatewayConfig gatewayConfig) {
         this.restTemplate = restTemplate;
         this.gatewayConfig = gatewayConfig;
     }
-- 
GitLab