diff --git a/.github/workflows/.trivyignore b/.github/workflows/.trivyignore
index 546adac9..6d205aed 100644
--- a/.github/workflows/.trivyignore
+++ b/.github/workflows/.trivyignore
@@ -1,3 +1,3 @@
-# April 17
-# Spring boot needs to update its version of spring
-CVE-2024-22262
\ No newline at end of file
+# July 17
+# Spring boot needs to update its version of Apache Tomcat
+CVE-2024-34750
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index 844b0ba3..868ca982 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,4 @@
target/
.idea
-src/main/resources/*
+src/main/resources/application.properties
.mvn/
diff --git a/pom.xml b/pom.xml
index c207c821..4ea42527 100644
--- a/pom.xml
+++ b/pom.xml
@@ -6,7 +6,7 @@
spring-boot-starter-parent
org.springframework.boot
- 3.2.4
+ 3.3.1
handle-manager
0.0.1-SNAPSHOT
@@ -18,17 +18,17 @@
17
UTF-8
- 1.17.6
+ 1.19.8
4.3
5.2.0
+ 5.1.1
4.10.0
+ 4.35.0
../app-it/target/site/jacoco-aggregate/jacoco.xml
https://sonarcloud.io
dissco
- 6.2.3
- 4.28.0
@@ -97,21 +97,17 @@
- org.postgresql
- postgresql
- ${postgresql.version}
+ org.apache.commons
+ commons-lang3
- org.jooq
- jooq
+ org.springframework.boot
+ spring-boot-starter-data-mongodb
- org.springframework
- spring-jdbc
-
-
- org.apache.commons
- commons-lang3
+ org.mongodb
+ mongodb-driver-sync
+ ${mongodb-driver.version}
@@ -177,6 +173,11 @@
org.springframework.boot
test
+
+ org.testcontainers
+ mongodb
+ test
+
com.squareup.okhttp3
okhttp
diff --git a/src/main/java/eu/dissco/core/handlemanager/configuration/AppConfig.java b/src/main/java/eu/dissco/core/handlemanager/configuration/AppConfig.java
index 3059535e..1350c1d6 100644
--- a/src/main/java/eu/dissco/core/handlemanager/configuration/AppConfig.java
+++ b/src/main/java/eu/dissco/core/handlemanager/configuration/AppConfig.java
@@ -1,6 +1,8 @@
package eu.dissco.core.handlemanager.configuration;
import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.module.SimpleModule;
+import java.time.Instant;
import java.util.Random;
import javax.xml.XMLConstants;
import javax.xml.parsers.DocumentBuilderFactory;
@@ -13,6 +15,8 @@
@Configuration
public class AppConfig {
+ public static final String DATE_STRING = "yyyy-MM-dd'T'HH:mm:ss.SSSXXX";
+
@Bean
public DocumentBuilderFactory documentBuilderFactory() throws ParserConfigurationException {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
@@ -31,7 +35,13 @@ public TransformerFactory transformerFactory() throws TransformerConfigurationEx
@Bean
public ObjectMapper objectMapper() {
- return new ObjectMapper().findAndRegisterModules();
+ var mapper = new ObjectMapper()
+ .findAndRegisterModules();
+ SimpleModule dateModule = new SimpleModule();
+ dateModule.addSerializer(Instant.class, new InstantSerializer());
+ dateModule.addDeserializer(Instant.class, new InstantDeserializer());
+ mapper.registerModule(dateModule);
+ return mapper;
}
@Bean
diff --git a/src/main/java/eu/dissco/core/handlemanager/configuration/BatchInserterConfig.java b/src/main/java/eu/dissco/core/handlemanager/configuration/BatchInserterConfig.java
deleted file mode 100644
index 8b641eb8..00000000
--- a/src/main/java/eu/dissco/core/handlemanager/configuration/BatchInserterConfig.java
+++ /dev/null
@@ -1,25 +0,0 @@
-package eu.dissco.core.handlemanager.configuration;
-
-import java.sql.DriverManager;
-import java.sql.SQLException;
-import lombok.RequiredArgsConstructor;
-import org.postgresql.copy.CopyManager;
-import org.postgresql.core.BaseConnection;
-import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-
-@Configuration
-@RequiredArgsConstructor
-public class BatchInserterConfig {
-
- private final DataSourceProperties properties;
-
- @Bean
- public CopyManager copyManager() throws SQLException {
- var connection = DriverManager.getConnection(properties.getUrl(), properties.getUsername(),
- properties.getPassword());
- return new CopyManager((BaseConnection) connection);
- }
-
-}
diff --git a/src/main/java/eu/dissco/core/handlemanager/configuration/InstantDeserializer.java b/src/main/java/eu/dissco/core/handlemanager/configuration/InstantDeserializer.java
new file mode 100644
index 00000000..454fa05d
--- /dev/null
+++ b/src/main/java/eu/dissco/core/handlemanager/configuration/InstantDeserializer.java
@@ -0,0 +1,30 @@
+package eu.dissco.core.handlemanager.configuration;
+
+import static eu.dissco.core.handlemanager.configuration.AppConfig.DATE_STRING;
+
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.JsonDeserializer;
+import java.io.IOException;
+import java.time.Instant;
+import java.time.ZoneOffset;
+import java.time.format.DateTimeFormatter;
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+public class InstantDeserializer extends JsonDeserializer {
+
+ private final DateTimeFormatter formatter = DateTimeFormatter.ofPattern(DATE_STRING).withZone(
+ ZoneOffset.UTC);
+
+ @Override
+ public Instant deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) {
+ try {
+ return Instant.from(formatter.parse(jsonParser.getText()));
+ } catch (IOException e) {
+ log.error("An error has occurred deserializing a date. More information: {}", e.getMessage());
+ return null;
+ }
+ }
+
+}
diff --git a/src/main/java/eu/dissco/core/handlemanager/configuration/InstantSerializer.java b/src/main/java/eu/dissco/core/handlemanager/configuration/InstantSerializer.java
new file mode 100644
index 00000000..fc2e9846
--- /dev/null
+++ b/src/main/java/eu/dissco/core/handlemanager/configuration/InstantSerializer.java
@@ -0,0 +1,30 @@
+package eu.dissco.core.handlemanager.configuration;
+
+import static eu.dissco.core.handlemanager.configuration.AppConfig.DATE_STRING;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.databind.JsonSerializer;
+import com.fasterxml.jackson.databind.SerializerProvider;
+import java.io.IOException;
+import java.time.Instant;
+import java.time.ZoneOffset;
+import java.time.format.DateTimeFormatter;
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+public class InstantSerializer extends JsonSerializer {
+
+ private final DateTimeFormatter formatter = DateTimeFormatter.ofPattern(DATE_STRING).withZone(
+ ZoneOffset.UTC);
+
+ @Override
+ public void serialize(Instant value, JsonGenerator jsonGenerator,
+ SerializerProvider serializerProvider) {
+ try {
+ jsonGenerator.writeString(formatter.format(value));
+ } catch (IOException e) {
+ log.error("An error has occurred serializing a date. More information: {}", e.getMessage());
+ }
+ }
+
+}
diff --git a/src/main/java/eu/dissco/core/handlemanager/configuration/MongoConfig.java b/src/main/java/eu/dissco/core/handlemanager/configuration/MongoConfig.java
new file mode 100644
index 00000000..e1b7b833
--- /dev/null
+++ b/src/main/java/eu/dissco/core/handlemanager/configuration/MongoConfig.java
@@ -0,0 +1,23 @@
+package eu.dissco.core.handlemanager.configuration;
+
+import com.mongodb.client.MongoClients;
+import com.mongodb.client.MongoCollection;
+import eu.dissco.core.handlemanager.properties.MongoProperties;
+import lombok.RequiredArgsConstructor;
+import org.bson.Document;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+@RequiredArgsConstructor
+public class MongoConfig {
+
+ private final MongoProperties properties;
+
+ @Bean
+ public MongoCollection getHandleCollection() {
+ var client = MongoClients.create(properties.getConnectionString());
+ var database = client.getDatabase(properties.getDatabase());
+ return database.getCollection("handles");
+ }
+}
diff --git a/src/main/java/eu/dissco/core/handlemanager/controller/PidController.java b/src/main/java/eu/dissco/core/handlemanager/controller/PidController.java
index 074f6d11..a8722e02 100644
--- a/src/main/java/eu/dissco/core/handlemanager/controller/PidController.java
+++ b/src/main/java/eu/dissco/core/handlemanager/controller/PidController.java
@@ -6,7 +6,6 @@
import com.fasterxml.jackson.databind.JsonNode;
import eu.dissco.core.handlemanager.domain.jsonapi.JsonApiWrapperRead;
-import eu.dissco.core.handlemanager.domain.jsonapi.JsonApiWrapperReadSingle;
import eu.dissco.core.handlemanager.domain.jsonapi.JsonApiWrapperWrite;
import eu.dissco.core.handlemanager.domain.requests.RollbackRequest;
import eu.dissco.core.handlemanager.domain.validation.JsonSchemaValidator;
@@ -18,7 +17,6 @@
import io.swagger.v3.oas.annotations.Operation;
import jakarta.servlet.http.HttpServletRequest;
import java.nio.charset.StandardCharsets;
-import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import lombok.RequiredArgsConstructor;
@@ -54,13 +52,13 @@ public class PidController {
// Getters
@Operation(summary = "Resolve single PID record")
@GetMapping("/{prefix}/{suffix}")
- public ResponseEntity resolvePid(@PathVariable("prefix") String prefix,
+ public ResponseEntity resolvePid(@PathVariable("prefix") String prefix,
@PathVariable("suffix") String suffix, HttpServletRequest r) throws PidResolutionException {
- String path = applicationProperties.getUiUrl() + r.getRequestURI();
+ String link = applicationProperties.getUiUrl() + "/" + r.getRequestURI();
String handle = prefix + "/" + suffix;
if (prefix.equals(applicationProperties.getPrefix())) {
- var node = service.resolveSingleRecord(handle.getBytes(StandardCharsets.UTF_8), path);
+ var node = service.resolveSingleRecord(handle, link);
return ResponseEntity.status(HttpStatus.OK).body(node);
}
throw new PidResolutionException(
@@ -73,17 +71,15 @@ public ResponseEntity resolvePid(@PathVariable("prefix
public ResponseEntity resolvePids(
@RequestParam List handles,
HttpServletRequest r) throws InvalidRequestException {
- String path = applicationProperties.getUiUrl() + r.getRequestURI();
+ String link = applicationProperties.getUiUrl() + "/" + r.getRequestURI();
if (handles.size() > applicationProperties.getMaxHandles()) {
throw new InvalidRequestException(
"Attempting to resolve more than maximum permitted PIDs in a single request. Maximum handles: "
+ applicationProperties.getMaxHandles());
}
- List handleBytes = new ArrayList<>();
- handles.forEach(h -> handleBytes.add(h.getBytes(StandardCharsets.UTF_8)));
- return ResponseEntity.status(HttpStatus.OK).body(service.resolveBatchRecord(handleBytes, path));
+ return ResponseEntity.status(HttpStatus.OK).body(service.resolveBatchRecord(handles, link));
}
@Operation(summary = "Given a physical identifier (i.e. local identifier), resolve PID record")
@@ -124,18 +120,14 @@ public ResponseEntity updateRecord(@PathVariable("prefix")
log.info("Received single update request for PID {}/{} from user {}", prefix, suffix,
authentication.getName());
schemaValidator.validatePatchRequest(request);
-
- JsonNode data = request.get(NODE_DATA);
- byte[] handle = (prefix + "/" + suffix).getBytes(StandardCharsets.UTF_8);
- byte[] handleData = data.get(NODE_ID).asText().getBytes(StandardCharsets.UTF_8);
-
- if (!Arrays.equals(handle, handleData)) {
+ var handle = (prefix + "/" + suffix);
+ var handleData = request.get(NODE_DATA).get(NODE_ID).asText();
+ if (!handle.equals(handleData)) {
throw new InvalidRequestException(String.format(
"Handle in request path does not match id in request body. Path: %s, Body: %s",
- new String(handle, StandardCharsets.UTF_8),
- new String(handleData, StandardCharsets.UTF_8)));
+ handle,
+ handleData));
}
-
return ResponseEntity.status(HttpStatus.OK).body(service.updateRecords(List.of(request), true));
}
@@ -171,7 +163,8 @@ public ResponseEntity archiveRecord(@PathVariable("prefix")
+ new String(handle, StandardCharsets.UTF_8)
+ ". Body: " + new String(handleRequest, StandardCharsets.UTF_8));
}
- return ResponseEntity.status(HttpStatus.OK).body(service.archiveRecordBatch(List.of(request)));
+ return ResponseEntity.status(HttpStatus.OK)
+ .body(service.tombstoneRecords(List.of(request)));
}
@Operation(summary = "rollback handle creation")
@@ -227,7 +220,7 @@ public ResponseEntity archiveRecords(@RequestBody ListDEFAULT_CATALOG
- */
- public static final DefaultCatalog DEFAULT_CATALOG = new DefaultCatalog();
-
- /**
- * The schema public
.
- */
- public final Public PUBLIC = Public.PUBLIC;
-
- /**
- * No further instances allowed
- */
- private DefaultCatalog() {
- super("");
- }
-
- @Override
- public final List getSchemas() {
- return Arrays.asList(
- Public.PUBLIC);
- }
-}
diff --git a/src/main/java/eu/dissco/core/handlemanager/database/jooq/Indexes.java b/src/main/java/eu/dissco/core/handlemanager/database/jooq/Indexes.java
deleted file mode 100644
index 9bcf7052..00000000
--- a/src/main/java/eu/dissco/core/handlemanager/database/jooq/Indexes.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * This file is generated by jOOQ.
- */
-package eu.dissco.core.handlemanager.database.jooq;
-
-
-import eu.dissco.core.handlemanager.database.jooq.tables.Handles;
-import org.jooq.Index;
-import org.jooq.OrderField;
-import org.jooq.impl.DSL;
-import org.jooq.impl.Internal;
-
-
-/**
- * A class modelling indexes of tables in public.
- */
-@SuppressWarnings({"all", "unchecked", "rawtypes"})
-public class Indexes {
-
- // -------------------------------------------------------------------------
- // INDEX definitions
- // -------------------------------------------------------------------------
-
- public static final Index DATAINDEX = Internal.createIndex(DSL.name("dataindex"), Handles.HANDLES,
- new OrderField[]{Handles.HANDLES.DATA}, false);
- public static final Index HANDLEINDEX = Internal.createIndex(DSL.name("handleindex"),
- Handles.HANDLES, new OrderField[]{Handles.HANDLES.HANDLE}, false);
-}
diff --git a/src/main/java/eu/dissco/core/handlemanager/database/jooq/Keys.java b/src/main/java/eu/dissco/core/handlemanager/database/jooq/Keys.java
deleted file mode 100644
index ad4139e1..00000000
--- a/src/main/java/eu/dissco/core/handlemanager/database/jooq/Keys.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * This file is generated by jOOQ.
- */
-package eu.dissco.core.handlemanager.database.jooq;
-
-
-import eu.dissco.core.handlemanager.database.jooq.tables.Handles;
-import eu.dissco.core.handlemanager.database.jooq.tables.records.HandlesRecord;
-import org.jooq.TableField;
-import org.jooq.UniqueKey;
-import org.jooq.impl.DSL;
-import org.jooq.impl.Internal;
-
-
-/**
- * A class modelling foreign key relationships and constraints of tables in public.
- */
-@SuppressWarnings({"all", "unchecked", "rawtypes"})
-public class Keys {
-
- // -------------------------------------------------------------------------
- // UNIQUE and PRIMARY KEY definitions
- // -------------------------------------------------------------------------
-
- public static final UniqueKey HANDLES_PKEY = Internal.createUniqueKey(
- Handles.HANDLES, DSL.name("handles_pkey"),
- new TableField[]{Handles.HANDLES.HANDLE, Handles.HANDLES.IDX}, true);
-}
diff --git a/src/main/java/eu/dissco/core/handlemanager/database/jooq/Public.java b/src/main/java/eu/dissco/core/handlemanager/database/jooq/Public.java
deleted file mode 100644
index fe5ae76b..00000000
--- a/src/main/java/eu/dissco/core/handlemanager/database/jooq/Public.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * This file is generated by jOOQ.
- */
-package eu.dissco.core.handlemanager.database.jooq;
-
-
-import eu.dissco.core.handlemanager.database.jooq.tables.Handles;
-import java.util.Arrays;
-import java.util.List;
-import org.jooq.Catalog;
-import org.jooq.Table;
-import org.jooq.impl.SchemaImpl;
-
-
-/**
- * This class is generated by jOOQ.
- */
-@SuppressWarnings({"all", "unchecked", "rawtypes"})
-public class Public extends SchemaImpl {
-
- private static final long serialVersionUID = 1L;
-
- /**
- * The reference instance of public
- */
- public static final Public PUBLIC = new Public();
-
- /**
- * The table public.handles
.
- */
- public final Handles HANDLES = Handles.HANDLES;
-
- /**
- * No further instances allowed
- */
- private Public() {
- super("public", null);
- }
-
-
- @Override
- public Catalog getCatalog() {
- return DefaultCatalog.DEFAULT_CATALOG;
- }
-
- @Override
- public final List> getTables() {
- return Arrays.>asList(
- Handles.HANDLES);
- }
-}
diff --git a/src/main/java/eu/dissco/core/handlemanager/database/jooq/Tables.java b/src/main/java/eu/dissco/core/handlemanager/database/jooq/Tables.java
deleted file mode 100644
index 488e0242..00000000
--- a/src/main/java/eu/dissco/core/handlemanager/database/jooq/Tables.java
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * This file is generated by jOOQ.
- */
-package eu.dissco.core.handlemanager.database.jooq;
-
-
-import eu.dissco.core.handlemanager.database.jooq.tables.Handles;
-
-
-/**
- * Convenience access to all tables in public.
- */
-@SuppressWarnings({"all", "unchecked", "rawtypes"})
-public class Tables {
-
- /**
- * The table public.handles
.
- */
- public static final Handles HANDLES = Handles.HANDLES;
-}
diff --git a/src/main/java/eu/dissco/core/handlemanager/database/jooq/tables/Handles.java b/src/main/java/eu/dissco/core/handlemanager/database/jooq/tables/Handles.java
deleted file mode 100644
index 7772dabf..00000000
--- a/src/main/java/eu/dissco/core/handlemanager/database/jooq/tables/Handles.java
+++ /dev/null
@@ -1,209 +0,0 @@
-/*
- * This file is generated by jOOQ.
- */
-package eu.dissco.core.handlemanager.database.jooq.tables;
-
-
-import eu.dissco.core.handlemanager.database.jooq.Indexes;
-import eu.dissco.core.handlemanager.database.jooq.Keys;
-import eu.dissco.core.handlemanager.database.jooq.Public;
-import eu.dissco.core.handlemanager.database.jooq.tables.records.HandlesRecord;
-import java.util.Arrays;
-import java.util.List;
-import org.jooq.Field;
-import org.jooq.ForeignKey;
-import org.jooq.Index;
-import org.jooq.Name;
-import org.jooq.Record;
-import org.jooq.Row12;
-import org.jooq.Schema;
-import org.jooq.Table;
-import org.jooq.TableField;
-import org.jooq.TableOptions;
-import org.jooq.UniqueKey;
-import org.jooq.impl.DSL;
-import org.jooq.impl.SQLDataType;
-import org.jooq.impl.TableImpl;
-
-
-/**
- * This class is generated by jOOQ.
- */
-@SuppressWarnings({"all", "unchecked", "rawtypes"})
-public class Handles extends TableImpl {
-
- private static final long serialVersionUID = 1L;
-
- /**
- * The reference instance of public.handles
- */
- public static final Handles HANDLES = new Handles();
-
- /**
- * The class holding records for this type
- */
- @Override
- public Class getRecordType() {
- return HandlesRecord.class;
- }
-
- /**
- * The column public.handles.handle
.
- */
- public final TableField HANDLE = createField(DSL.name("handle"),
- SQLDataType.BLOB.nullable(false), this, "");
-
- /**
- * The column public.handles.idx
.
- */
- public final TableField IDX = createField(DSL.name("idx"),
- SQLDataType.INTEGER.nullable(false), this, "");
-
- /**
- * The column public.handles.type
.
- */
- public final TableField TYPE = createField(DSL.name("type"),
- SQLDataType.BLOB, this, "");
-
- /**
- * The column public.handles.data
.
- */
- public final TableField DATA = createField(DSL.name("data"),
- SQLDataType.BLOB, this, "");
-
- /**
- * The column public.handles.ttl_type
.
- */
- public final TableField TTL_TYPE = createField(DSL.name("ttl_type"),
- SQLDataType.SMALLINT, this, "");
-
- /**
- * The column public.handles.ttl
.
- */
- public final TableField TTL = createField(DSL.name("ttl"),
- SQLDataType.INTEGER, this, "");
-
- /**
- * The column public.handles.timestamp
.
- */
- public final TableField TIMESTAMP = createField(DSL.name("timestamp"),
- SQLDataType.BIGINT, this, "");
-
- /**
- * The column public.handles.refs
.
- */
- public final TableField REFS = createField(DSL.name("refs"),
- SQLDataType.CLOB, this, "");
-
- /**
- * The column public.handles.admin_read
.
- */
- public final TableField ADMIN_READ = createField(DSL.name("admin_read"),
- SQLDataType.BOOLEAN, this, "");
-
- /**
- * The column public.handles.admin_write
.
- */
- public final TableField ADMIN_WRITE = createField(DSL.name("admin_write"),
- SQLDataType.BOOLEAN, this, "");
-
- /**
- * The column public.handles.pub_read
.
- */
- public final TableField PUB_READ = createField(DSL.name("pub_read"),
- SQLDataType.BOOLEAN, this, "");
-
- /**
- * The column public.handles.pub_write
.
- */
- public final TableField PUB_WRITE = createField(DSL.name("pub_write"),
- SQLDataType.BOOLEAN, this, "");
-
- private Handles(Name alias, Table aliased) {
- this(alias, aliased, null);
- }
-
- private Handles(Name alias, Table aliased, Field>[] parameters) {
- super(alias, null, aliased, parameters, DSL.comment(""), TableOptions.table());
- }
-
- /**
- * Create an aliased public.handles
table reference
- */
- public Handles(String alias) {
- this(DSL.name(alias), HANDLES);
- }
-
- /**
- * Create an aliased public.handles
table reference
- */
- public Handles(Name alias) {
- this(alias, HANDLES);
- }
-
- /**
- * Create a public.handles
table reference
- */
- public Handles() {
- this(DSL.name("handles"), null);
- }
-
- public Handles(Table child, ForeignKey key) {
- super(child, key, HANDLES);
- }
-
- @Override
- public Schema getSchema() {
- return Public.PUBLIC;
- }
-
- @Override
- public List getIndexes() {
- return Arrays.asList(Indexes.DATAINDEX, Indexes.HANDLEINDEX);
- }
-
- @Override
- public UniqueKey getPrimaryKey() {
- return Keys.HANDLES_PKEY;
- }
-
- @Override
- public List> getKeys() {
- return Arrays.>asList(Keys.HANDLES_PKEY);
- }
-
- @Override
- public Handles as(String alias) {
- return new Handles(DSL.name(alias), this);
- }
-
- @Override
- public Handles as(Name alias) {
- return new Handles(alias, this);
- }
-
- /**
- * Rename this table
- */
- @Override
- public Handles rename(String name) {
- return new Handles(DSL.name(name), null);
- }
-
- /**
- * Rename this table
- */
- @Override
- public Handles rename(Name name) {
- return new Handles(name, null);
- }
-
- // -------------------------------------------------------------------------
- // Row12 type methods
- // -------------------------------------------------------------------------
-
- @Override
- public Row12 fieldsRow() {
- return (Row12) super.fieldsRow();
- }
-}
diff --git a/src/main/java/eu/dissco/core/handlemanager/database/jooq/tables/records/HandlesRecord.java b/src/main/java/eu/dissco/core/handlemanager/database/jooq/tables/records/HandlesRecord.java
deleted file mode 100644
index d0a1aea8..00000000
--- a/src/main/java/eu/dissco/core/handlemanager/database/jooq/tables/records/HandlesRecord.java
+++ /dev/null
@@ -1,518 +0,0 @@
-/*
- * This file is generated by jOOQ.
- */
-package eu.dissco.core.handlemanager.database.jooq.tables.records;
-
-
-import eu.dissco.core.handlemanager.database.jooq.tables.Handles;
-import org.jooq.Field;
-import org.jooq.Record12;
-import org.jooq.Record2;
-import org.jooq.Row12;
-import org.jooq.impl.UpdatableRecordImpl;
-
-
-/**
- * This class is generated by jOOQ.
- */
-@SuppressWarnings({"all", "unchecked", "rawtypes"})
-public class HandlesRecord extends UpdatableRecordImpl implements
- Record12 {
-
- private static final long serialVersionUID = 1L;
-
- /**
- * Setter for public.handles.handle
.
- */
- public void setHandle(byte[] value) {
- set(0, value);
- }
-
- /**
- * Getter for public.handles.handle
.
- */
- public byte[] getHandle() {
- return (byte[]) get(0);
- }
-
- /**
- * Setter for public.handles.idx
.
- */
- public void setIdx(Integer value) {
- set(1, value);
- }
-
- /**
- * Getter for public.handles.idx
.
- */
- public Integer getIdx() {
- return (Integer) get(1);
- }
-
- /**
- * Setter for public.handles.type
.
- */
- public void setType(byte[] value) {
- set(2, value);
- }
-
- /**
- * Getter for public.handles.type
.
- */
- public byte[] getType() {
- return (byte[]) get(2);
- }
-
- /**
- * Setter for public.handles.data
.
- */
- public void setData(byte[] value) {
- set(3, value);
- }
-
- /**
- * Getter for public.handles.data
.
- */
- public byte[] getData() {
- return (byte[]) get(3);
- }
-
- /**
- * Setter for public.handles.ttl_type
.
- */
- public void setTtlType(Short value) {
- set(4, value);
- }
-
- /**
- * Getter for public.handles.ttl_type
.
- */
- public Short getTtlType() {
- return (Short) get(4);
- }
-
- /**
- * Setter for public.handles.ttl
.
- */
- public void setTtl(Integer value) {
- set(5, value);
- }
-
- /**
- * Getter for public.handles.ttl
.
- */
- public Integer getTtl() {
- return (Integer) get(5);
- }
-
- /**
- * Setter for public.handles.timestamp
.
- */
- public void setTimestamp(Long value) {
- set(6, value);
- }
-
- /**
- * Getter for public.handles.timestamp
.
- */
- public Long getTimestamp() {
- return (Long) get(6);
- }
-
- /**
- * Setter for public.handles.refs
.
- */
- public void setRefs(String value) {
- set(7, value);
- }
-
- /**
- * Getter for public.handles.refs
.
- */
- public String getRefs() {
- return (String) get(7);
- }
-
- /**
- * Setter for public.handles.admin_read
.
- */
- public void setAdminRead(Boolean value) {
- set(8, value);
- }
-
- /**
- * Getter for public.handles.admin_read
.
- */
- public Boolean getAdminRead() {
- return (Boolean) get(8);
- }
-
- /**
- * Setter for public.handles.admin_write
.
- */
- public void setAdminWrite(Boolean value) {
- set(9, value);
- }
-
- /**
- * Getter for public.handles.admin_write
.
- */
- public Boolean getAdminWrite() {
- return (Boolean) get(9);
- }
-
- /**
- * Setter for public.handles.pub_read
.
- */
- public void setPubRead(Boolean value) {
- set(10, value);
- }
-
- /**
- * Getter for public.handles.pub_read
.
- */
- public Boolean getPubRead() {
- return (Boolean) get(10);
- }
-
- /**
- * Setter for public.handles.pub_write
.
- */
- public void setPubWrite(Boolean value) {
- set(11, value);
- }
-
- /**
- * Getter for public.handles.pub_write
.
- */
- public Boolean getPubWrite() {
- return (Boolean) get(11);
- }
-
- // -------------------------------------------------------------------------
- // Primary key information
- // -------------------------------------------------------------------------
-
- @Override
- public Record2 key() {
- return (Record2) super.key();
- }
-
- // -------------------------------------------------------------------------
- // Record12 type implementation
- // -------------------------------------------------------------------------
-
- @Override
- public Row12 fieldsRow() {
- return (Row12) super.fieldsRow();
- }
-
- @Override
- public Row12 valuesRow() {
- return (Row12) super.valuesRow();
- }
-
- @Override
- public Field field1() {
- return Handles.HANDLES.HANDLE;
- }
-
- @Override
- public Field field2() {
- return Handles.HANDLES.IDX;
- }
-
- @Override
- public Field field3() {
- return Handles.HANDLES.TYPE;
- }
-
- @Override
- public Field field4() {
- return Handles.HANDLES.DATA;
- }
-
- @Override
- public Field field5() {
- return Handles.HANDLES.TTL_TYPE;
- }
-
- @Override
- public Field field6() {
- return Handles.HANDLES.TTL;
- }
-
- @Override
- public Field field7() {
- return Handles.HANDLES.TIMESTAMP;
- }
-
- @Override
- public Field field8() {
- return Handles.HANDLES.REFS;
- }
-
- @Override
- public Field field9() {
- return Handles.HANDLES.ADMIN_READ;
- }
-
- @Override
- public Field field10() {
- return Handles.HANDLES.ADMIN_WRITE;
- }
-
- @Override
- public Field field11() {
- return Handles.HANDLES.PUB_READ;
- }
-
- @Override
- public Field field12() {
- return Handles.HANDLES.PUB_WRITE;
- }
-
- @Override
- public byte[] component1() {
- return getHandle();
- }
-
- @Override
- public Integer component2() {
- return getIdx();
- }
-
- @Override
- public byte[] component3() {
- return getType();
- }
-
- @Override
- public byte[] component4() {
- return getData();
- }
-
- @Override
- public Short component5() {
- return getTtlType();
- }
-
- @Override
- public Integer component6() {
- return getTtl();
- }
-
- @Override
- public Long component7() {
- return getTimestamp();
- }
-
- @Override
- public String component8() {
- return getRefs();
- }
-
- @Override
- public Boolean component9() {
- return getAdminRead();
- }
-
- @Override
- public Boolean component10() {
- return getAdminWrite();
- }
-
- @Override
- public Boolean component11() {
- return getPubRead();
- }
-
- @Override
- public Boolean component12() {
- return getPubWrite();
- }
-
- @Override
- public byte[] value1() {
- return getHandle();
- }
-
- @Override
- public Integer value2() {
- return getIdx();
- }
-
- @Override
- public byte[] value3() {
- return getType();
- }
-
- @Override
- public byte[] value4() {
- return getData();
- }
-
- @Override
- public Short value5() {
- return getTtlType();
- }
-
- @Override
- public Integer value6() {
- return getTtl();
- }
-
- @Override
- public Long value7() {
- return getTimestamp();
- }
-
- @Override
- public String value8() {
- return getRefs();
- }
-
- @Override
- public Boolean value9() {
- return getAdminRead();
- }
-
- @Override
- public Boolean value10() {
- return getAdminWrite();
- }
-
- @Override
- public Boolean value11() {
- return getPubRead();
- }
-
- @Override
- public Boolean value12() {
- return getPubWrite();
- }
-
- @Override
- public HandlesRecord value1(byte[] value) {
- setHandle(value);
- return this;
- }
-
- @Override
- public HandlesRecord value2(Integer value) {
- setIdx(value);
- return this;
- }
-
- @Override
- public HandlesRecord value3(byte[] value) {
- setType(value);
- return this;
- }
-
- @Override
- public HandlesRecord value4(byte[] value) {
- setData(value);
- return this;
- }
-
- @Override
- public HandlesRecord value5(Short value) {
- setTtlType(value);
- return this;
- }
-
- @Override
- public HandlesRecord value6(Integer value) {
- setTtl(value);
- return this;
- }
-
- @Override
- public HandlesRecord value7(Long value) {
- setTimestamp(value);
- return this;
- }
-
- @Override
- public HandlesRecord value8(String value) {
- setRefs(value);
- return this;
- }
-
- @Override
- public HandlesRecord value9(Boolean value) {
- setAdminRead(value);
- return this;
- }
-
- @Override
- public HandlesRecord value10(Boolean value) {
- setAdminWrite(value);
- return this;
- }
-
- @Override
- public HandlesRecord value11(Boolean value) {
- setPubRead(value);
- return this;
- }
-
- @Override
- public HandlesRecord value12(Boolean value) {
- setPubWrite(value);
- return this;
- }
-
- @Override
- public HandlesRecord values(byte[] value1, Integer value2, byte[] value3, byte[] value4,
- Short value5, Integer value6, Long value7, String value8, Boolean value9, Boolean value10,
- Boolean value11, Boolean value12) {
- value1(value1);
- value2(value2);
- value3(value3);
- value4(value4);
- value5(value5);
- value6(value6);
- value7(value7);
- value8(value8);
- value9(value9);
- value10(value10);
- value11(value11);
- value12(value12);
- return this;
- }
-
- // -------------------------------------------------------------------------
- // Constructors
- // -------------------------------------------------------------------------
-
- /**
- * Create a detached HandlesRecord
- */
- public HandlesRecord() {
- super(Handles.HANDLES);
- }
-
- /**
- * Create a detached, initialised HandlesRecord
- */
- public HandlesRecord(byte[] handle, Integer idx, byte[] type, byte[] data, Short ttlType,
- Integer ttl, Long timestamp, String refs, Boolean adminRead, Boolean adminWrite,
- Boolean pubRead, Boolean pubWrite) {
- super(Handles.HANDLES);
-
- setHandle(handle);
- setIdx(idx);
- setType(type);
- setData(data);
- setTtlType(ttlType);
- setTtl(ttl);
- setTimestamp(timestamp);
- setRefs(refs);
- setAdminRead(adminRead);
- setAdminWrite(adminWrite);
- setPubRead(pubRead);
- setPubWrite(pubWrite);
- }
-}
diff --git a/src/main/java/eu/dissco/core/handlemanager/domain/fdo/DigitalMediaRequest.java b/src/main/java/eu/dissco/core/handlemanager/domain/fdo/DigitalMediaRequest.java
index d1a19f28..30dacf94 100644
--- a/src/main/java/eu/dissco/core/handlemanager/domain/fdo/DigitalMediaRequest.java
+++ b/src/main/java/eu/dissco/core/handlemanager/domain/fdo/DigitalMediaRequest.java
@@ -23,7 +23,7 @@ public class DigitalMediaRequest extends DoiRecordRequest {
private final String mediaHostName;
@Nullable
@JsonProperty(value = "dcterms:format")
- private final MediaFormat mediaFormat;
+ private final MediaFormat dctermsFormat;
@JsonProperty(required = true)
private final Boolean isDerivedFromSpecimen;
@JsonProperty(required = true)
@@ -32,6 +32,7 @@ public class DigitalMediaRequest extends DoiRecordRequest {
private final LinkedDigitalObjectType linkedDigitalObjectType;
@Nullable
private final String linkedAttribute;
+ @JsonProperty(required = true)
private final String primaryMediaId;
@Nullable
private final PrimarySpecimenObjectIdType primaryMediaObjectIdType;
@@ -41,13 +42,14 @@ public class DigitalMediaRequest extends DoiRecordRequest {
@JsonProperty(value = "dcterms:type")
private final DcTermsType dcTermsType;
@Nullable
- private final String mediaMimeType;
+ @JsonProperty(value = "dcterms:subject")
+ private final String dctermsSubject;
@Nullable
private final String derivedFromEntity;
@Nullable
private final String licenseName;
@Nullable
- private final String license;
+ private final String licenseUrl;
@Nullable
private final String rightsholderName;
@Nullable
@@ -68,7 +70,7 @@ public DigitalMediaRequest(
// Media
String mediaHost,
String mediaHostName,
- MediaFormat mediaFormat,
+ MediaFormat dctermsFormat,
Boolean isDerivedFromSpecimen,
String linkedDigitalObjectPid,
LinkedDigitalObjectType linkedDigitalObjectType,
@@ -77,10 +79,10 @@ public DigitalMediaRequest(
PrimarySpecimenObjectIdType primaryMediaObjectIdType,
String primaryMediaObjectIdName,
DcTermsType dcTermsType,
- String mediaMimeType,
+ String dctermsSubject,
String derivedFromEntity,
String licenseName,
- String license,
+ String licenseUrl,
String rightsholderPid,
String rightsholderName,
PrimarySpecimenObjectIdType rightsholderPidType,
@@ -91,7 +93,7 @@ public DigitalMediaRequest(
referentName, FdoType.DIGITAL_MEDIA.getDigitalObjectName(), primaryReferentType);
this.mediaHost = mediaHost;
this.mediaHostName = mediaHostName;
- this.mediaFormat = mediaFormat;
+ this.dctermsFormat = dctermsFormat;
this.isDerivedFromSpecimen = isDerivedFromSpecimen;
this.linkedDigitalObjectPid = linkedDigitalObjectPid;
this.linkedDigitalObjectType = linkedDigitalObjectType;
@@ -100,10 +102,10 @@ public DigitalMediaRequest(
this.primaryMediaObjectIdType = primaryMediaObjectIdType;
this.primaryMediaObjectIdName = primaryMediaObjectIdName;
this.dcTermsType = dcTermsType;
- this.mediaMimeType = mediaMimeType;
+ this.dctermsSubject = dctermsSubject;
this.derivedFromEntity = derivedFromEntity;
this.licenseName = licenseName;
- this.license = license;
+ this.licenseUrl = licenseUrl;
this.rightsholderPid = rightsholderPid == null ? mediaHost : rightsholderPid;
this.rightsholderName = rightsholderName;
this.rightsholderPidType = rightsholderPidType;
diff --git a/src/main/java/eu/dissco/core/handlemanager/domain/fdo/DigitalSpecimenRequest.java b/src/main/java/eu/dissco/core/handlemanager/domain/fdo/DigitalSpecimenRequest.java
index 1c3fccdc..de6e3032 100644
--- a/src/main/java/eu/dissco/core/handlemanager/domain/fdo/DigitalSpecimenRequest.java
+++ b/src/main/java/eu/dissco/core/handlemanager/domain/fdo/DigitalSpecimenRequest.java
@@ -43,7 +43,7 @@ public class DigitalSpecimenRequest extends DoiRecordRequest {
@JsonProperty(required = true)
private final String normalisedPrimarySpecimenObjectId;
@Nullable
- private final String primarySpecimenObjectIdAbsenceReason;
+ private final String specimenObjectIdAbsenceReason;
@Nullable
private final List otherSpecimenIds;
@Nullable
@@ -86,7 +86,7 @@ public DigitalSpecimenRequest(
PrimarySpecimenObjectIdType primarySpecimenObjectIdType,
String primarySpecimenObjectIdName,
String normalisedPrimarySpecimenObjetId,
- String primarySpecimenObjectIdAbsenceReason,
+ String specimenObjectIdAbsenceReason,
List otherSpecimenIds,
TopicOrigin topicOrigin,
TopicDomain topicDomain,
@@ -109,7 +109,7 @@ public DigitalSpecimenRequest(
primarySpecimenObjectIdType == null ? LOCAL : primarySpecimenObjectIdType;
this.primarySpecimenObjectIdName = primarySpecimenObjectIdName;
this.normalisedPrimarySpecimenObjectId = normalisedPrimarySpecimenObjetId;
- this.primarySpecimenObjectIdAbsenceReason = primarySpecimenObjectIdAbsenceReason;
+ this.specimenObjectIdAbsenceReason = specimenObjectIdAbsenceReason;
this.otherSpecimenIds = otherSpecimenIds;
this.topicOrigin = topicOrigin;
this.topicDomain = topicDomain;
@@ -130,7 +130,7 @@ public DigitalSpecimenRequest(
}
private void idXorAbsence() throws InvalidRequestException {
- if ((this.primarySpecimenObjectId == null) == (this.primarySpecimenObjectIdAbsenceReason
+ if ((this.primarySpecimenObjectId == null) == (this.specimenObjectIdAbsenceReason
== null)) {
throw new InvalidRequestException(
"Request must contain exactly one of: [primarySpecimenObjectId, primarySpecimenObjectIdAbsenceReason]");
diff --git a/src/main/java/eu/dissco/core/handlemanager/domain/fdo/DoiRecordRequest.java b/src/main/java/eu/dissco/core/handlemanager/domain/fdo/DoiRecordRequest.java
index 28ecbec8..1ef5e92b 100644
--- a/src/main/java/eu/dissco/core/handlemanager/domain/fdo/DoiRecordRequest.java
+++ b/src/main/java/eu/dissco/core/handlemanager/domain/fdo/DoiRecordRequest.java
@@ -11,8 +11,6 @@
@EqualsAndHashCode(callSuper = true)
public class DoiRecordRequest extends HandleRecordRequest {
- private static final String PLACEHOLDER = "{This value is a placeholder}";
-
private final String referentType;
@JsonPropertyDescription("Local name of the object (human-readable)")
diff --git a/src/main/java/eu/dissco/core/handlemanager/domain/fdo/FdoProfile.java b/src/main/java/eu/dissco/core/handlemanager/domain/fdo/FdoProfile.java
index 667d94d3..f389c9da 100644
--- a/src/main/java/eu/dissco/core/handlemanager/domain/fdo/FdoProfile.java
+++ b/src/main/java/eu/dissco/core/handlemanager/domain/fdo/FdoProfile.java
@@ -1,6 +1,5 @@
package eu.dissco.core.handlemanager.domain.fdo;
-import java.util.Arrays;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@@ -21,8 +20,9 @@ public enum FdoProfile {
PID_STATUS("pidStatus", 13),
// Tombstone
- TOMBSTONE_TEXT("tombstoneText", 30),
- TOMBSTONE_PIDS("tombstonePids", 31),
+ TOMBSTONED_TEXT("ods:tombstonedText", 30),
+ HAS_RELATED_PID("hasRelatedPID", 31),
+ TOMBSTONED_DATE("tombstonedDate", 32),
// DOI
REFERENT_TYPE("referentType", 40),
@@ -55,7 +55,6 @@ public enum FdoProfile {
// Media
MEDIA_HOST("mediaHost", 400),
MEDIA_HOST_NAME("mediaHostName", 401),
- MEDIA_FORMAT("mediaFormat", 402),
IS_DERIVED_FROM_SPECIMEN("isDerivedFromSpecimen", 403),
LINKED_DO_PID("linkedDigitalObjectPid", 404),
LINKED_DO_TYPE("linkedDigitalObjectType", 405),
@@ -63,8 +62,9 @@ public enum FdoProfile {
PRIMARY_MEDIA_ID("primaryMediaId", 407),
PRIMARY_MO_ID_TYPE("primaryMediaObjectIdType", 408),
PRIMARY_MO_ID_NAME("primaryMediaObjectIdName", 409),
- DCTERMS_TYPE("dcterms:type", 411),
- MEDIA_MIME_TYPE("mediaMimeType", 412),
+ DCTERMS_TYPE("dcterms:type", 410),
+ DCTERMS_SUBJECT("dcterms:subject", 411),
+ DCTERMS_FORMAT("dcterms:format", 412),
DERIVED_FROM_ENTITY("derivedFromEntity", 413),
LICENSE_NAME("licenseName", 414),
LICENSE_URL("licenseUrl", 415),
@@ -111,15 +111,4 @@ public int index() {
return this.index;
}
- public static int retrieveIndex(String searchAttribute) {
- var fdoProfile = Arrays.stream(FdoProfile.values())
- .filter(fdoRow -> fdoRow.attribute.equals(searchAttribute))
- .findFirst();
- if (fdoProfile.isPresent()) {
- return fdoProfile.get().index;
- }
- log.error("Unable to locate index for requested attribute {}", searchAttribute);
- throw new IllegalStateException(searchAttribute + " not valid fdo attribute");
- }
-
}
diff --git a/src/main/java/eu/dissco/core/handlemanager/domain/fdo/FdoType.java b/src/main/java/eu/dissco/core/handlemanager/domain/fdo/FdoType.java
index 3f75b5b1..d821850a 100644
--- a/src/main/java/eu/dissco/core/handlemanager/domain/fdo/FdoType.java
+++ b/src/main/java/eu/dissco/core/handlemanager/domain/fdo/FdoType.java
@@ -1,5 +1,8 @@
package eu.dissco.core.handlemanager.domain.fdo;
+import static eu.dissco.core.handlemanager.service.FdoRecordService.DOI_DOMAIN;
+import static eu.dissco.core.handlemanager.service.FdoRecordService.HANDLE_DOMAIN;
+
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
@@ -10,53 +13,65 @@ public enum FdoType {
@JsonProperty("https://hdl.handle.net/21.T11148/532ce6796e2828dd2be6") HANDLE(
"Handle Kernel",
"https://hdl.handle.net/21.T11148/532ce6796e2828dd2be6",
- "https://hdl.handle.net/21.T11148/532ce6796e2828dd2be6"),
+ "https://hdl.handle.net/21.T11148/532ce6796e2828dd2be6",
+ HANDLE_DOMAIN),
@JsonProperty("https://hdl.handle.net/21.T11148/527856fd709ec8c5bc8c") DOI(
"DOI Kernel",
"https://hdl.handle.net/21.T11148/527856fd709ec8c5bc8c",
- "https://hdl.handle.net/21.T11148/527856fd709ec8c5bc8c"),
+ "https://hdl.handle.net/21.T11148/527856fd709ec8c5bc8c",
+ DOI_DOMAIN),
@JsonProperty("https://hdl.handle.net/21.T11148/894b1e6cad57e921764e") DIGITAL_SPECIMEN(
"DigitalSpecimen",
"https://hdl.handle.net/21.T11148/894b1e6cad57e921764e",
- "https://hdl.handle.net/21.T11148/894b1e6cad57e921764e"),
+ "https://hdl.handle.net/21.T11148/894b1e6cad57e921764e",
+ DOI_DOMAIN),
@JsonProperty("https://hdl.handle.net/21.T11148/bbad8c4e101e8af01115") DIGITAL_MEDIA(
- "DigitalMedia",
+ "MediaObject",
+ "https://hdl.handle.net/21.T11148/bbad8c4e101e8af01115",
"https://hdl.handle.net/21.T11148/bbad8c4e101e8af01115",
- "https://hdl.handle.net/21.T11148/bbad8c4e101e8af01115"),
+ DOI_DOMAIN),
@JsonProperty("https://hdl.handle.net/21.T11148/cf458ca9ee1d44a5608f") ANNOTATION(
"Annotation",
"https://hdl.handle.net/21.T11148/cf458ca9ee1d44a5608f",
- "https://hdl.handle.net/21.T11148/cf458ca9ee1d44a5608f"),
+ "https://hdl.handle.net/21.T11148/cf458ca9ee1d44a5608f",
+ HANDLE_DOMAIN),
@JsonProperty("https://hdl.handle.net/21.T11148/417a4f472f60f7974c12") SOURCE_SYSTEM(
"sourceSystem",
"https://hdl.handle.net/21.T11148/417a4f472f60f7974c12",
- "https://hdl.handle.net/21.T11148/417a4f472f60f7974c12"),
+ "https://hdl.handle.net/21.T11148/417a4f472f60f7974c12",
+ HANDLE_DOMAIN),
@JsonProperty("https://hdl.handle.net/21.T11148/ce794a6f4df42eb7e77e") DATA_MAPPING(
- "Data Mapping",
+ "Mapping",
+ "https://hdl.handle.net/21.T11148/ce794a6f4df42eb7e77e",
"https://hdl.handle.net/21.T11148/ce794a6f4df42eb7e77e",
- "https://hdl.handle.net/21.T11148/ce794a6f4df42eb7e77e"),
+ HANDLE_DOMAIN),
@JsonProperty("https://hdl.handle.net/21.T11148/413c00cbd83ae33d1ac0") ORGANISATION(
"Organisation",
"https://hdl.handle.net/21.T11148/413c00cbd83ae33d1ac0",
- "https://hdl.handle.net/21.T11148/413c00cbd83ae33d1ac0"),
+ "https://hdl.handle.net/21.T11148/413c00cbd83ae33d1ac0",
+ HANDLE_DOMAIN),
@JsonProperty("https://hdl.handle.net/21.T11148/d7570227982f70256af3") TOMBSTONE(
"Tombstone",
"https://hdl.handle.net/21.T11148/d7570227982f70256af3",
- "https://hdl.handle.net/21.T11148/d7570227982f70256af3"),
+ "https://hdl.handle.net/21.T11148/d7570227982f70256af3",
+ HANDLE_DOMAIN),
@JsonProperty("https://hdl.handle.net/21.T11148/22e71a0015cbcfba8ffa") MAS(
"Machine Annotation Service",
"https://hdl.handle.net/21.T11148/22e71a0015cbcfba8ffa",
- "https://hdl.handle.net/21.T11148/22e71a0015cbcfba8ffa");
+ "https://hdl.handle.net/21.T11148/22e71a0015cbcfba8ffa",
+ HANDLE_DOMAIN);
private final String digitalObjectName;
private final String digitalObjectType;
private final String fdoProfile;
+ private final String domain;
FdoType(@JsonProperty("type") String digitalObjectName, String digitalObjectType,
- String fdoProfile) {
+ String fdoProfile, String domain) {
this.digitalObjectName = digitalObjectName;
this.digitalObjectType = digitalObjectType;
this.fdoProfile = fdoProfile;
+ this.domain = domain;
}
@Override
diff --git a/src/main/java/eu/dissco/core/handlemanager/domain/fdo/TombstoneRecordRequest.java b/src/main/java/eu/dissco/core/handlemanager/domain/fdo/TombstoneRecordRequest.java
index 5d23044f..6340d9e4 100644
--- a/src/main/java/eu/dissco/core/handlemanager/domain/fdo/TombstoneRecordRequest.java
+++ b/src/main/java/eu/dissco/core/handlemanager/domain/fdo/TombstoneRecordRequest.java
@@ -1,6 +1,8 @@
package eu.dissco.core.handlemanager.domain.fdo;
import com.fasterxml.jackson.annotation.JsonProperty;
+import eu.dissco.core.handlemanager.domain.fdo.vocabulary.tombstone.HasRelatedPid;
+import java.util.List;
import lombok.Getter;
import lombok.ToString;
import org.springframework.lang.Nullable;
@@ -9,20 +11,15 @@
@ToString
public class TombstoneRecordRequest {
- @JsonProperty(required = true)
- private final String tombstoneText;
-
+ @JsonProperty(required = true, value = "ods:tombstonedText")
+ private final String tombstonedText;
@Nullable
- private final String[] tombstonePids;
-
- public TombstoneRecordRequest(String tombstoneText) {
- this.tombstoneText = tombstoneText;
- this.tombstonePids = new String[]{};
- }
+ @JsonProperty("ods:hasRelatedPID")
+ private final List hasRelatedPID;
- public TombstoneRecordRequest(String tombstoneText, String[] tombstonePids) {
- this.tombstoneText = tombstoneText;
- this.tombstonePids = tombstonePids;
+ public TombstoneRecordRequest(String tombstoneText, List hasRelatedPID) {
+ this.tombstonedText = tombstoneText;
+ this.hasRelatedPID = hasRelatedPID;
}
}
diff --git a/src/main/java/eu/dissco/core/handlemanager/domain/fdo/vocabulary/PidStatus.java b/src/main/java/eu/dissco/core/handlemanager/domain/fdo/vocabulary/PidStatus.java
new file mode 100644
index 00000000..5404ee99
--- /dev/null
+++ b/src/main/java/eu/dissco/core/handlemanager/domain/fdo/vocabulary/PidStatus.java
@@ -0,0 +1,9 @@
+package eu.dissco.core.handlemanager.domain.fdo.vocabulary;
+
+public enum PidStatus {
+ TOMBSTONED,
+ ACTIVE,
+ DRAFT,
+ FAILED,
+ TEST
+}
diff --git a/src/main/java/eu/dissco/core/handlemanager/domain/fdo/vocabulary/specimen/StructuralType.java b/src/main/java/eu/dissco/core/handlemanager/domain/fdo/vocabulary/specimen/StructuralType.java
index 4be772fd..2f4d8036 100644
--- a/src/main/java/eu/dissco/core/handlemanager/domain/fdo/vocabulary/specimen/StructuralType.java
+++ b/src/main/java/eu/dissco/core/handlemanager/domain/fdo/vocabulary/specimen/StructuralType.java
@@ -7,11 +7,11 @@ public enum StructuralType {
@JsonProperty("digital") DIGITAL("digital"),
@JsonProperty("physical") PHYSICAL("physical"),
@JsonProperty("performance") PERFORM("performance"),
- @JsonProperty("performance") ABSTRACT("abstraction");
+ @JsonProperty("abstraction") ABSTRACT("abstraction");
private final String state;
- private StructuralType(String state) {
+ StructuralType(String state) {
this.state = state;
}
diff --git a/src/main/java/eu/dissco/core/handlemanager/domain/fdo/vocabulary/tombstone/HasRelatedPid.java b/src/main/java/eu/dissco/core/handlemanager/domain/fdo/vocabulary/tombstone/HasRelatedPid.java
new file mode 100644
index 00000000..9018d6f4
--- /dev/null
+++ b/src/main/java/eu/dissco/core/handlemanager/domain/fdo/vocabulary/tombstone/HasRelatedPid.java
@@ -0,0 +1,12 @@
+package eu.dissco.core.handlemanager.domain.fdo.vocabulary.tombstone;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+public record HasRelatedPid(
+ @JsonProperty("ods:ID")
+ String odsId,
+ @JsonProperty("ods:relationshipType")
+ String odsRelationshipType
+) {
+
+}
diff --git a/src/main/java/eu/dissco/core/handlemanager/domain/repsitoryobjects/AdminHandleData.java b/src/main/java/eu/dissco/core/handlemanager/domain/repsitoryobjects/AdminHandleData.java
new file mode 100644
index 00000000..9f1ed05e
--- /dev/null
+++ b/src/main/java/eu/dissco/core/handlemanager/domain/repsitoryobjects/AdminHandleData.java
@@ -0,0 +1,23 @@
+package eu.dissco.core.handlemanager.domain.repsitoryobjects;
+
+import lombok.Value;
+
+@Value
+public class AdminHandleData implements HandleData {
+
+ String format = "admin";
+ AdminValue value;
+
+ public AdminHandleData(String prefix) {
+ this.value = new AdminValue("0.NA/" + prefix);
+ }
+
+ @Value
+ protected static class AdminValue {
+
+ String handle;
+ int index = 200;
+ String permissions = "011111110011";
+ }
+
+}
diff --git a/src/main/java/eu/dissco/core/handlemanager/domain/repsitoryobjects/FdoAttribute.java b/src/main/java/eu/dissco/core/handlemanager/domain/repsitoryobjects/FdoAttribute.java
new file mode 100644
index 00000000..18655358
--- /dev/null
+++ b/src/main/java/eu/dissco/core/handlemanager/domain/repsitoryobjects/FdoAttribute.java
@@ -0,0 +1,66 @@
+package eu.dissco.core.handlemanager.domain.repsitoryobjects;
+
+import static eu.dissco.core.handlemanager.domain.fdo.FdoProfile.HS_ADMIN;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import eu.dissco.core.handlemanager.domain.fdo.FdoProfile;
+import java.time.Instant;
+import java.util.LinkedHashMap;
+import lombok.Value;
+import org.bson.Document;
+
+@Value
+public class FdoAttribute {
+
+ int index;
+ String type;
+ HandleData data;
+ int ttl;
+ Instant timestamp;
+
+ public FdoAttribute(FdoProfile fdoAttribute, Instant timestamp, Object value) {
+ this.index = fdoAttribute.index();
+ this.type = fdoAttribute.get();
+ this.timestamp = timestamp;
+ value = value == null ? "" : value;
+ this.data = new StringHandleData(value.toString());
+ this.ttl = 86400;
+ }
+
+ public FdoAttribute(Instant timestamp, String prefix) {
+ this.index = HS_ADMIN.index();
+ this.type = HS_ADMIN.get();
+ this.data = new AdminHandleData(prefix);
+ this.timestamp = timestamp;
+ this.ttl = 86400;
+ }
+
+ @JsonCreator
+ public FdoAttribute(Integer index, String type, Integer ttl, Instant timestamp, Document data) {
+ this.index = index;
+ this.type = type;
+ var value = data.get("value", Object.class);
+ if (value instanceof String valueString) {
+ this.data = new StringHandleData(valueString);
+ } else if (value == null) {
+ this.data = new StringHandleData(null);
+ } else {
+ var map = data.get("value", LinkedHashMap.class);
+ var prefix = map.get("handle").toString().replace("0.NA/", "");
+ this.data = new AdminHandleData(prefix);
+ }
+ this.ttl = ttl;
+ this.timestamp = timestamp;
+ }
+
+ @JsonIgnore
+ public String getValue() {
+ if (data instanceof StringHandleData d) {
+ return (d.getValue());
+ } else {
+ return "HS_ADMIN";
+ }
+ }
+
+}
diff --git a/src/main/java/eu/dissco/core/handlemanager/domain/repsitoryobjects/FdoRecord.java b/src/main/java/eu/dissco/core/handlemanager/domain/repsitoryobjects/FdoRecord.java
new file mode 100644
index 00000000..c6b5a55f
--- /dev/null
+++ b/src/main/java/eu/dissco/core/handlemanager/domain/repsitoryobjects/FdoRecord.java
@@ -0,0 +1,18 @@
+package eu.dissco.core.handlemanager.domain.repsitoryobjects;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import eu.dissco.core.handlemanager.domain.fdo.FdoType;
+import java.util.List;
+
+public record FdoRecord(
+ @JsonProperty("_id")
+ String handle,
+ @JsonIgnore
+ FdoType fdoType,
+ @JsonProperty("values")
+ List attributes,
+ @JsonIgnore
+ String primaryLocalId) {
+
+}
diff --git a/src/main/java/eu/dissco/core/handlemanager/domain/repsitoryobjects/HandleAttribute.java b/src/main/java/eu/dissco/core/handlemanager/domain/repsitoryobjects/HandleAttribute.java
deleted file mode 100644
index dffc52e4..00000000
--- a/src/main/java/eu/dissco/core/handlemanager/domain/repsitoryobjects/HandleAttribute.java
+++ /dev/null
@@ -1,61 +0,0 @@
-package eu.dissco.core.handlemanager.domain.repsitoryobjects;
-
-import eu.dissco.core.handlemanager.domain.fdo.FdoProfile;
-import java.nio.charset.StandardCharsets;
-import java.util.Arrays;
-import java.util.Objects;
-import lombok.Data;
-
-@Data
-public class HandleAttribute {
-
- private final int index;
- private final byte[] handle;
- private final String type;
- private final byte[] data;
-
- public HandleAttribute(int index, byte[] handle, String type, byte[] data) {
- this.index = index;
- this.handle = handle;
- this.type = type;
- this.data = data;
- }
-
- public HandleAttribute(FdoProfile fdoAttribute, byte[] handle, String data) {
- this.index = fdoAttribute.index();
- this.handle = handle;
- this.data = data.getBytes(StandardCharsets.UTF_8);
- this.type = fdoAttribute.get();
- }
-
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (o == null || getClass() != o.getClass()) {
- return false;
- }
- HandleAttribute that = (HandleAttribute) o;
- return index == that.index && Objects.equals(type, that.type)
- && Arrays.equals(data, that.data);
- }
-
- @Override
- public int hashCode() {
- int result = Objects.hash(index, type);
- result = 31 * result + Arrays.hashCode(data);
- return result;
- }
-
- @Override
- public String toString() {
- return "HandleAttribute{" +
- "handle=" + new String(handle, StandardCharsets.UTF_8) +
- ", index=" + index +
- ", type='" + type + '\'' +
- ", data=" + new String(data, StandardCharsets.UTF_8) +
- '}';
- }
-}
\ No newline at end of file
diff --git a/src/main/java/eu/dissco/core/handlemanager/domain/repsitoryobjects/HandleData.java b/src/main/java/eu/dissco/core/handlemanager/domain/repsitoryobjects/HandleData.java
new file mode 100644
index 00000000..655fb0e3
--- /dev/null
+++ b/src/main/java/eu/dissco/core/handlemanager/domain/repsitoryobjects/HandleData.java
@@ -0,0 +1,5 @@
+package eu.dissco.core.handlemanager.domain.repsitoryobjects;
+
+public interface HandleData {
+
+}
diff --git a/src/main/java/eu/dissco/core/handlemanager/domain/repsitoryobjects/StringHandleData.java b/src/main/java/eu/dissco/core/handlemanager/domain/repsitoryobjects/StringHandleData.java
new file mode 100644
index 00000000..fa07a9eb
--- /dev/null
+++ b/src/main/java/eu/dissco/core/handlemanager/domain/repsitoryobjects/StringHandleData.java
@@ -0,0 +1,10 @@
+package eu.dissco.core.handlemanager.domain.repsitoryobjects;
+
+import lombok.Value;
+
+@Value
+public class StringHandleData implements HandleData {
+
+ String format = "string";
+ String value;
+}
diff --git a/src/main/java/eu/dissco/core/handlemanager/domain/requests/PatchRequest.java b/src/main/java/eu/dissco/core/handlemanager/domain/requests/PatchRequest.java
index a7e6b876..081dc237 100644
--- a/src/main/java/eu/dissco/core/handlemanager/domain/requests/PatchRequest.java
+++ b/src/main/java/eu/dissco/core/handlemanager/domain/requests/PatchRequest.java
@@ -2,9 +2,6 @@
import com.fasterxml.jackson.annotation.JsonProperty;
-public record PatchRequest(
- @JsonProperty(required = true)
- PatchRequestData data
-) {
+public record PatchRequest(@JsonProperty(required = true) PutRequestData data) {
}
diff --git a/src/main/java/eu/dissco/core/handlemanager/domain/requests/PatchRequestData.java b/src/main/java/eu/dissco/core/handlemanager/domain/requests/PatchRequestData.java
deleted file mode 100644
index 7801dfb4..00000000
--- a/src/main/java/eu/dissco/core/handlemanager/domain/requests/PatchRequestData.java
+++ /dev/null
@@ -1,19 +0,0 @@
-package eu.dissco.core.handlemanager.domain.requests;
-
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.fasterxml.jackson.annotation.JsonPropertyDescription;
-import com.fasterxml.jackson.databind.JsonNode;
-import eu.dissco.core.handlemanager.domain.fdo.FdoType;
-
-public record PatchRequestData(
- @JsonProperty(required = true)
- @JsonPropertyDescription("Type of object")
- FdoType type,
- @JsonProperty(required = true)
- @JsonPropertyDescription("DiSSCo Identifier of object")
- String id,
- @JsonProperty(required = true)
- JsonNode attributes
-) {
-
-}
diff --git a/src/main/java/eu/dissco/core/handlemanager/domain/requests/PostRequestData.java b/src/main/java/eu/dissco/core/handlemanager/domain/requests/PostRequestData.java
index bfd85bf6..ecafde3e 100644
--- a/src/main/java/eu/dissco/core/handlemanager/domain/requests/PostRequestData.java
+++ b/src/main/java/eu/dissco/core/handlemanager/domain/requests/PostRequestData.java
@@ -6,7 +6,6 @@
import eu.dissco.core.handlemanager.domain.fdo.FdoType;
public record PostRequestData(
- @JsonProperty(required = true)
@JsonPropertyDescription("type of object")
FdoType type,
@JsonProperty(required = true)
diff --git a/src/main/java/eu/dissco/core/handlemanager/domain/requests/PutRequest.java b/src/main/java/eu/dissco/core/handlemanager/domain/requests/PutRequest.java
deleted file mode 100644
index 0b51d4f2..00000000
--- a/src/main/java/eu/dissco/core/handlemanager/domain/requests/PutRequest.java
+++ /dev/null
@@ -1,7 +0,0 @@
-package eu.dissco.core.handlemanager.domain.requests;
-
-import com.fasterxml.jackson.annotation.JsonProperty;
-
-public record PutRequest(@JsonProperty(required = true) PutRequestData data) {
-
-}
diff --git a/src/main/java/eu/dissco/core/handlemanager/domain/requests/PutRequestData.java b/src/main/java/eu/dissco/core/handlemanager/domain/requests/PutRequestData.java
index 100e2296..1fca81a3 100644
--- a/src/main/java/eu/dissco/core/handlemanager/domain/requests/PutRequestData.java
+++ b/src/main/java/eu/dissco/core/handlemanager/domain/requests/PutRequestData.java
@@ -3,9 +3,11 @@
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyDescription;
import com.fasterxml.jackson.databind.JsonNode;
+import eu.dissco.core.handlemanager.domain.fdo.FdoType;
public record PutRequestData(
@JsonProperty(required = true) @JsonPropertyDescription("DiSSCo Identifier of object") String id,
- @JsonProperty(required = true) JsonNode attributes) {
+ @JsonProperty(required = true) JsonNode attributes,
+ FdoType type) {
}
diff --git a/src/main/java/eu/dissco/core/handlemanager/domain/requests/TombstoneRequest.java b/src/main/java/eu/dissco/core/handlemanager/domain/requests/TombstoneRequest.java
new file mode 100644
index 00000000..2eb6de11
--- /dev/null
+++ b/src/main/java/eu/dissco/core/handlemanager/domain/requests/TombstoneRequest.java
@@ -0,0 +1,5 @@
+package eu.dissco.core.handlemanager.domain.requests;
+
+public record TombstoneRequest(TombstoneRequestData data) {
+
+}
diff --git a/src/main/java/eu/dissco/core/handlemanager/domain/requests/TombstoneRequestData.java b/src/main/java/eu/dissco/core/handlemanager/domain/requests/TombstoneRequestData.java
new file mode 100644
index 00000000..5bc52403
--- /dev/null
+++ b/src/main/java/eu/dissco/core/handlemanager/domain/requests/TombstoneRequestData.java
@@ -0,0 +1,12 @@
+package eu.dissco.core.handlemanager.domain.requests;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonPropertyDescription;
+import com.fasterxml.jackson.databind.JsonNode;
+
+public record TombstoneRequestData(
+ @JsonProperty(required = true) @JsonPropertyDescription("DiSSCo Identifier of object") String id,
+ @JsonProperty(required = true) JsonNode attributes
+) {
+
+}
diff --git a/src/main/java/eu/dissco/core/handlemanager/domain/validation/JsonSchemaValidator.java b/src/main/java/eu/dissco/core/handlemanager/domain/validation/JsonSchemaValidator.java
index a04c3fc7..bafbf895 100644
--- a/src/main/java/eu/dissco/core/handlemanager/domain/validation/JsonSchemaValidator.java
+++ b/src/main/java/eu/dissco/core/handlemanager/domain/validation/JsonSchemaValidator.java
@@ -1,5 +1,6 @@
package eu.dissco.core.handlemanager.domain.validation;
+import static eu.dissco.core.handlemanager.domain.fdo.FdoType.TOMBSTONE;
import static eu.dissco.core.handlemanager.domain.jsonapi.JsonApiFields.NODE_ATTRIBUTES;
import static eu.dissco.core.handlemanager.domain.jsonapi.JsonApiFields.NODE_DATA;
import static eu.dissco.core.handlemanager.domain.jsonapi.JsonApiFields.NODE_TYPE;
@@ -30,7 +31,7 @@
import eu.dissco.core.handlemanager.domain.fdo.TombstoneRecordRequest;
import eu.dissco.core.handlemanager.domain.requests.PatchRequest;
import eu.dissco.core.handlemanager.domain.requests.PostRequest;
-import eu.dissco.core.handlemanager.domain.requests.PutRequest;
+import eu.dissco.core.handlemanager.domain.requests.TombstoneRequest;
import eu.dissco.core.handlemanager.exceptions.InvalidRequestException;
import jakarta.validation.constraints.NotEmpty;
import java.util.Arrays;
@@ -49,69 +50,50 @@ public class JsonSchemaValidator {
private JsonNode postReqJsonNode;
private JsonNode patchReqJsonNode;
private JsonNode putReqJsonNode;
- private JsonNode handlePostReqJsonNode;
- private JsonNode handlePatchReqJsonNode;
- private JsonNode doiPostReqJsonNode;
- private JsonNode doiPatchReqJsonNode;
- private JsonNode digitalSpecimenPostReqJsonNode;
- private JsonNode digitalSpecimenPatchReqJsonNode;
- private JsonNode digitalMediaPostReqJsonNode;
- private JsonNode digitalMediaPatchReqJsonNode;
+ private JsonNode handleJsonNode;
+ private JsonNode doiJsonNode;
+ private JsonNode digitalSpecimenJsonNode;
+ private JsonNode digitalMediaJsonNode;
private JsonNode tombstoneReqJsonNode;
- private JsonNode annotationPostReqJsonNode;
- private JsonNode annotationPatchReqJsonNode;
- private JsonNode mappingPostReqJsonNode;
- private JsonNode mappingPatchReqJsonNode;
- private JsonNode sourceSystemPostReqJsonNode;
- private JsonNode sourceSystemPatchReqJsonNode;
- private JsonNode organisationPostReqJsonNode;
- private JsonNode organisationPatchReqJsonNode;
- private JsonNode masPostReqJsonNode;
- private JsonNode masPatchReqJsonNode;
+ private JsonNode annotationJsonNode;
+ private JsonNode mappingJsonNode;
+ private JsonNode sourceSystemJsonNode;
+ private JsonNode organisationJsonNode;
+ private JsonNode masJsonNode;
// Schemas
private JsonSchema postReqSchema;
private JsonSchema patchReqSchema;
private JsonSchema putReqSchema;
- private JsonSchema handlePostReqSchema;
- private JsonSchema handlePatchReqSchema;
- private JsonSchema doiPostReqSchema;
- private JsonSchema doiPatchReqSchema;
- private JsonSchema digitalSpecimenPostReqSchema;
- private JsonSchema digitalSpecimenPatchReqSchema;
- private JsonSchema digitalMediaPostReqSchema;
- private JsonSchema digitalMediaPatchReqSchema;
+ private JsonSchema handleSchema;
+ private JsonSchema doiSchema;
+ private JsonSchema digitalSpecimenSchema;
+ private JsonSchema digitalMediaSchema;
private JsonSchema tombstoneReqSchema;
- private JsonSchema annotationPostReqSchema;
- private JsonSchema annotationPatchReqSchema;
- private JsonSchema mappingPostReqSchema;
- private JsonSchema mappingPatchReqSchema;
- private JsonSchema sourceSystemPostReqSchema;
- private JsonSchema sourceSystemPatchReqSchema;
- private JsonSchema organisationPostReqSchema;
- private JsonSchema organisationPatchReqSchema;
- private JsonSchema masPostReqSchema;
- private JsonSchema masPatchReqSchema;
+ private JsonSchema annotationSchema;
+ private JsonSchema dataMappingSchema;
+ private JsonSchema sourceSystemSchema;
+ private JsonSchema organisationSchema;
+ private JsonSchema masSchema;
public JsonSchemaValidator() {
setPostRequestAttributesJsonNodes();
- setPatchRequestAttributesJsonNodes();
setRequestJsonNodes();
setJsonSchemas();
}
private void setPostRequestAttributesJsonNodes() {
var schemaGenerator = new SchemaGenerator(jacksonModuleSchemaConfig());
- handlePostReqJsonNode = schemaGenerator.generateSchema(HandleRecordRequest.class);
- doiPostReqJsonNode = schemaGenerator.generateSchema(DoiRecordRequest.class);
- digitalSpecimenPostReqJsonNode = schemaGenerator.generateSchema(DigitalSpecimenRequest.class);
- digitalMediaPostReqJsonNode = schemaGenerator.generateSchema(DigitalMediaRequest.class);
+ handleJsonNode = schemaGenerator.generateSchema(HandleRecordRequest.class);
+ doiJsonNode = schemaGenerator.generateSchema(DoiRecordRequest.class);
+ digitalSpecimenJsonNode = schemaGenerator.generateSchema(DigitalSpecimenRequest.class);
+ digitalMediaJsonNode = schemaGenerator.generateSchema(DigitalMediaRequest.class);
tombstoneReqJsonNode = schemaGenerator.generateSchema(TombstoneRecordRequest.class);
- annotationPostReqJsonNode = schemaGenerator.generateSchema(AnnotationRequest.class);
- mappingPostReqJsonNode = schemaGenerator.generateSchema(DataMappingRequest.class);
- sourceSystemPostReqJsonNode = schemaGenerator.generateSchema(SourceSystemRequest.class);
- organisationPostReqJsonNode = schemaGenerator.generateSchema(OrganisationRequest.class);
- masPostReqJsonNode = schemaGenerator.generateSchema(MasRequest.class);
+ annotationJsonNode = schemaGenerator.generateSchema(AnnotationRequest.class);
+ mappingJsonNode = schemaGenerator.generateSchema(DataMappingRequest.class);
+ sourceSystemJsonNode = schemaGenerator.generateSchema(SourceSystemRequest.class);
+ organisationJsonNode = schemaGenerator.generateSchema(OrganisationRequest.class);
+ masJsonNode = schemaGenerator.generateSchema(MasRequest.class);
}
private SchemaGeneratorConfig jacksonModuleSchemaConfig() {
@@ -151,49 +133,11 @@ private SchemaGeneratorConfig jacksonModuleSchemaConfig() {
return configBuilder.build();
}
- private void setPatchRequestAttributesJsonNodes() {
- var schemaGenerator = new SchemaGenerator(attributesSchemaConfig());
- handlePatchReqJsonNode = schemaGenerator.generateSchema(HandleRecordRequest.class);
- doiPatchReqJsonNode = schemaGenerator.generateSchema(DoiRecordRequest.class);
- digitalSpecimenPatchReqJsonNode = schemaGenerator.generateSchema(DigitalSpecimenRequest.class);
- digitalMediaPatchReqJsonNode = schemaGenerator.generateSchema(DigitalMediaRequest.class);
- annotationPatchReqJsonNode = schemaGenerator.generateSchema(AnnotationRequest.class);
- mappingPatchReqJsonNode = schemaGenerator.generateSchema(DataMappingRequest.class);
- sourceSystemPatchReqJsonNode = schemaGenerator.generateSchema(SourceSystemRequest.class);
- organisationPatchReqJsonNode = schemaGenerator.generateSchema(OrganisationRequest.class);
- masPatchReqJsonNode = schemaGenerator.generateSchema(MasRequest.class);
- }
-
- private SchemaGeneratorConfig attributesSchemaConfig() {
- // Secondary Configuration for schemas of Request Objects
- // In these schemas not every field is required, but no unknown properties are allowed
- // e.g. PATCH update attributes
-
- SchemaGeneratorConfigBuilder configBuilder = new SchemaGeneratorConfigBuilder(
- SchemaVersion.DRAFT_2020_12, OptionPreset.PLAIN_JSON)
- .with(Option.FORBIDDEN_ADDITIONAL_PROPERTIES_BY_DEFAULT)
- .with(
- Option.FLATTENED_ENUMS_FROM_TOSTRING); // Uses the output of toString() as the enum vocabulary
-
- configBuilder.forTypesInGeneral()
- .withEnumResolver(scope -> scope.getType().getErasedType().isEnum()
- ? Stream.of(scope.getType().getErasedType().getEnumConstants())
- .map(v -> ((Enum) v).name()).toList()
- : null);
-
- // Min
- configBuilder.forFields()
- .withArrayMinItemsResolver(field -> field
- .getAnnotationConsideringFieldAndGetterIfSupported(NotEmpty.class) == null ? null : 1);
-
- return configBuilder.build();
- }
-
private void setRequestJsonNodes() {
var schemaGenerator = new SchemaGenerator(requestSchemaConfig());
postReqJsonNode = schemaGenerator.generateSchema(PostRequest.class);
patchReqJsonNode = schemaGenerator.generateSchema(PatchRequest.class);
- putReqJsonNode = schemaGenerator.generateSchema(PutRequest.class);
+ putReqJsonNode = schemaGenerator.generateSchema(TombstoneRequest.class);
}
public SchemaGeneratorConfig requestSchemaConfig() {
@@ -224,110 +168,72 @@ public SchemaGeneratorConfig requestSchemaConfig() {
private void setJsonSchemas() {
JsonSchemaFactory factory = JsonSchemaFactory.getInstance(VersionFlag.V202012);
-
postReqSchema = factory.getSchema(postReqJsonNode);
patchReqSchema = factory.getSchema(patchReqJsonNode);
putReqSchema = factory.getSchema(putReqJsonNode);
-
- handlePostReqSchema = factory.getSchema(handlePostReqJsonNode);
- doiPostReqSchema = factory.getSchema(doiPostReqJsonNode);
- digitalSpecimenPostReqSchema = factory.getSchema(digitalSpecimenPostReqJsonNode);
- digitalMediaPostReqSchema = factory.getSchema(digitalMediaPostReqJsonNode);
- annotationPostReqSchema = factory.getSchema(annotationPostReqJsonNode);
- mappingPostReqSchema = factory.getSchema(mappingPostReqJsonNode);
- sourceSystemPostReqSchema = factory.getSchema(sourceSystemPostReqJsonNode);
- organisationPostReqSchema = factory.getSchema(organisationPostReqJsonNode);
- masPostReqSchema = factory.getSchema(masPostReqJsonNode);
-
- handlePatchReqSchema = factory.getSchema(handlePatchReqJsonNode);
- doiPatchReqSchema = factory.getSchema(doiPatchReqJsonNode);
- digitalSpecimenPatchReqSchema = factory.getSchema(digitalSpecimenPatchReqJsonNode);
- digitalMediaPatchReqSchema = factory.getSchema(digitalMediaPatchReqJsonNode);
- annotationPatchReqSchema = factory.getSchema(annotationPatchReqJsonNode);
- mappingPatchReqSchema = factory.getSchema(mappingPatchReqJsonNode);
- sourceSystemPatchReqSchema = factory.getSchema(sourceSystemPatchReqJsonNode);
- organisationPatchReqSchema = factory.getSchema(organisationPatchReqJsonNode);
- masPatchReqSchema = factory.getSchema(masPatchReqJsonNode);
-
+ handleSchema = factory.getSchema(handleJsonNode);
+ doiSchema = factory.getSchema(doiJsonNode);
+ digitalSpecimenSchema = factory.getSchema(digitalSpecimenJsonNode);
+ digitalMediaSchema = factory.getSchema(digitalMediaJsonNode);
+ annotationSchema = factory.getSchema(annotationJsonNode);
+ dataMappingSchema = factory.getSchema(mappingJsonNode);
+ sourceSystemSchema = factory.getSchema(sourceSystemJsonNode);
+ organisationSchema = factory.getSchema(organisationJsonNode);
+ masSchema = factory.getSchema(masJsonNode);
tombstoneReqSchema = factory.getSchema(tombstoneReqJsonNode);
-
}
public void validatePostRequest(JsonNode requestRoot) throws InvalidRequestException {
var validationErrors = postReqSchema.validate(requestRoot);
if (!validationErrors.isEmpty()) {
- throw new InvalidRequestException(setErrorMessage(validationErrors, "POST"));
- }
-
- FdoType type = FdoType.fromString(requestRoot.get(NODE_DATA).get(NODE_TYPE).asText());
- var attributes = requestRoot.get(NODE_DATA).get(NODE_ATTRIBUTES);
- switch (type) {
- case HANDLE -> validateRequestAttributes(attributes, handlePostReqSchema, type);
- case DOI -> validateRequestAttributes(attributes, doiPostReqSchema, type);
- case DIGITAL_SPECIMEN ->
- validateRequestAttributes(attributes, digitalSpecimenPostReqSchema, type);
- case DIGITAL_MEDIA -> validateRequestAttributes(attributes, digitalMediaPostReqSchema, type);
- case ANNOTATION -> validateRequestAttributes(attributes, annotationPostReqSchema, type);
- case DATA_MAPPING -> validateRequestAttributes(attributes, mappingPostReqSchema, type);
- case SOURCE_SYSTEM -> validateRequestAttributes(attributes, sourceSystemPostReqSchema, type);
- case ORGANISATION -> validateRequestAttributes(attributes, organisationPostReqSchema, type);
- case MAS -> validateRequestAttributes(attributes, masPostReqSchema, type);
- default ->
- throw new InvalidRequestException("Invalid Request. Reason: Invalid type: " + type);
+ throw new InvalidRequestException(setErrorMessage(validationErrors, "CREATE"));
}
+ var fdoType = FdoType.fromString(requestRoot.get(NODE_DATA).get(NODE_TYPE).asText());
+ validateAttributes(requestRoot, fdoType);
}
public void validatePatchRequest(JsonNode requestRoot) throws InvalidRequestException {
var validationErrors = patchReqSchema.validate(requestRoot);
if (!validationErrors.isEmpty()) {
throw new InvalidRequestException(
- setErrorMessage(validationErrors, "PATCH (update)"));
- }
- FdoType type = FdoType.fromString(requestRoot.get(NODE_DATA).get(NODE_TYPE).asText());
- var attributes = requestRoot.get(NODE_DATA).get(NODE_ATTRIBUTES);
- switch (type) {
- case HANDLE -> validateRequestAttributes(attributes, handlePatchReqSchema, type);
- case DOI -> validateRequestAttributes(attributes, doiPatchReqSchema, type);
- case DIGITAL_SPECIMEN ->
- validateRequestAttributes(attributes, digitalSpecimenPatchReqSchema, type);
- case DIGITAL_MEDIA -> validateRequestAttributes(attributes, digitalMediaPatchReqSchema, type);
- case ANNOTATION -> validateRequestAttributes(attributes, annotationPatchReqSchema, type);
- case DATA_MAPPING -> validateRequestAttributes(attributes, mappingPatchReqSchema, type);
- case SOURCE_SYSTEM -> validateRequestAttributes(attributes, sourceSystemPatchReqSchema, type);
- case ORGANISATION -> validateRequestAttributes(attributes, organisationPatchReqSchema, type);
- case MAS -> validateRequestAttributes(attributes, masPatchReqSchema, type);
- default ->
- throw new InvalidRequestException("Invalid Request. Reason: Invalid type: " + type);
+ setErrorMessage(validationErrors, "UPDATE"));
}
+ var fdoType = FdoType.fromString(requestRoot.get(NODE_DATA).get(NODE_TYPE).asText());
+ validateAttributes(requestRoot, fdoType);
}
public void validatePutRequest(JsonNode requestRoot) throws InvalidRequestException {
var validationErrors = putReqSchema.validate(requestRoot);
if (!validationErrors.isEmpty()) {
throw new InvalidRequestException(
- setErrorMessage(validationErrors, "PUT (tombstone)"));
+ setErrorMessage(validationErrors, "TOMBSTONE"));
}
- var attributes = requestRoot.get(NODE_DATA).get(NODE_ATTRIBUTES);
- validateTombstoneRequestAttributes(attributes);
+ validateAttributes(requestRoot, TOMBSTONE);
}
-
- private void validateTombstoneRequestAttributes(JsonNode requestAttributes)
+ private void validateAttributes(JsonNode requestRoot, FdoType fdoType)
throws InvalidRequestException {
- var validationErrors = tombstoneReqSchema.validate(requestAttributes);
- if (!validationErrors.isEmpty()) {
- throw new InvalidRequestException(
- setErrorMessage(validationErrors, FdoType.TOMBSTONE.getDigitalObjectName(),
- requestAttributes));
+ var requestAttributes = requestRoot.get(NODE_DATA).get(NODE_ATTRIBUTES);
+ JsonSchema schema;
+ switch (fdoType) {
+ case HANDLE -> schema = handleSchema;
+ case DOI -> schema = doiSchema;
+ case DIGITAL_SPECIMEN -> schema = digitalSpecimenSchema;
+ case DIGITAL_MEDIA -> schema = digitalMediaSchema;
+ case ANNOTATION -> schema = annotationSchema;
+ case DATA_MAPPING -> schema = dataMappingSchema;
+ case SOURCE_SYSTEM -> schema = sourceSystemSchema;
+ case ORGANISATION -> schema = organisationSchema;
+ case MAS -> schema = masSchema;
+ case TOMBSTONE -> schema = tombstoneReqSchema;
+ default ->
+ throw new InvalidRequestException("Invalid Request. Reason: Invalid type: " + fdoType);
}
- }
-
- private void validateRequestAttributes(JsonNode requestAttributes, JsonSchema schema,
- FdoType type) throws InvalidRequestException {
var validationErrors = schema.validate(requestAttributes);
if (!validationErrors.isEmpty()) {
throw new InvalidRequestException(
- setErrorMessage(validationErrors, type.getDigitalObjectName(), requestAttributes));
+ setErrorMessage(validationErrors, fdoType.getDigitalObjectName(),
+ requestAttributes));
}
}
diff --git a/src/main/java/eu/dissco/core/handlemanager/properties/MongoProperties.java b/src/main/java/eu/dissco/core/handlemanager/properties/MongoProperties.java
new file mode 100644
index 00000000..fcd53cf0
--- /dev/null
+++ b/src/main/java/eu/dissco/core/handlemanager/properties/MongoProperties.java
@@ -0,0 +1,19 @@
+package eu.dissco.core.handlemanager.properties;
+
+import jakarta.validation.constraints.NotBlank;
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.validation.annotation.Validated;
+
+@Data
+@Validated
+@ConfigurationProperties(prefix = "mongo")
+public class MongoProperties {
+
+ @NotBlank
+ private String connectionString;
+
+ @NotBlank
+ private String database;
+
+}
diff --git a/src/main/java/eu/dissco/core/handlemanager/repository/BatchInserter.java b/src/main/java/eu/dissco/core/handlemanager/repository/BatchInserter.java
deleted file mode 100644
index 485590c4..00000000
--- a/src/main/java/eu/dissco/core/handlemanager/repository/BatchInserter.java
+++ /dev/null
@@ -1,51 +0,0 @@
-package eu.dissco.core.handlemanager.repository;
-
-import eu.dissco.core.handlemanager.domain.repsitoryobjects.HandleAttribute;
-import eu.dissco.core.handlemanager.exceptions.DatabaseCopyException;
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.nio.charset.StandardCharsets;
-import java.sql.SQLException;
-import java.util.List;
-import lombok.RequiredArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
-import org.postgresql.copy.CopyManager;
-import org.springframework.stereotype.Component;
-
-@Component
-@RequiredArgsConstructor
-@Slf4j
-public class BatchInserter {
-
- private final CopyManager copyManager;
-
- public void batchCopy(long recordTimestamp, List handleAttributes) {
- try (var outputStream = new ByteArrayOutputStream()) {
- for (var row : handleAttributes) {
- outputStream.write(getCsvRow(recordTimestamp, row));
- }
- var inputStream = new ByteArrayInputStream(outputStream.toByteArray());
- copyManager.copyIn("COPY handles FROM stdin DELIMITER ','", inputStream);
- } catch (IOException | SQLException e) {
- log.error("Sql error: ", e);
- throw new DatabaseCopyException("Unable to insert new handles into database.");
- }
- }
-
- private static byte[] getCsvRow(Long recordTimestamp, HandleAttribute handleAttribute) {
- return (new String(handleAttribute.getHandle(), StandardCharsets.UTF_8) + ","
- + handleAttribute.getIndex() + ","
- + handleAttribute.getType() + ","
- + new String(handleAttribute.getData(), StandardCharsets.UTF_8).replace(",", "\\,")
- + ","
- + "0,"
- + "86400,"
- + recordTimestamp + ","
- + "\\N," // Leave refs null
- + true + ","
- + true + ","
- + true + ","
- + false + "\n").getBytes(StandardCharsets.UTF_8);
- }
-}
diff --git a/src/main/java/eu/dissco/core/handlemanager/repository/MongoRepository.java b/src/main/java/eu/dissco/core/handlemanager/repository/MongoRepository.java
new file mode 100644
index 00000000..701ea37b
--- /dev/null
+++ b/src/main/java/eu/dissco/core/handlemanager/repository/MongoRepository.java
@@ -0,0 +1,118 @@
+package eu.dissco.core.handlemanager.repository;
+
+import static com.mongodb.client.model.Filters.eq;
+import static com.mongodb.client.model.Filters.in;
+import static eu.dissco.core.handlemanager.domain.fdo.FdoProfile.DIGITAL_OBJECT_TYPE;
+import static eu.dissco.core.handlemanager.domain.fdo.FdoProfile.NORMALISED_SPECIMEN_OBJECT_ID;
+import static eu.dissco.core.handlemanager.domain.fdo.FdoProfile.PRIMARY_MEDIA_ID;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.mongodb.client.FindIterable;
+import com.mongodb.client.MongoCollection;
+import com.mongodb.client.model.ReplaceOneModel;
+import eu.dissco.core.handlemanager.domain.fdo.FdoType;
+import eu.dissco.core.handlemanager.domain.repsitoryobjects.FdoAttribute;
+import eu.dissco.core.handlemanager.domain.repsitoryobjects.FdoRecord;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.bson.Document;
+import org.springframework.stereotype.Repository;
+
+@Repository
+@RequiredArgsConstructor
+@Slf4j
+public class MongoRepository {
+
+ private final MongoCollection collection;
+ private final ObjectMapper mapper;
+ private static final String ID = "_id";
+
+ public List getHandleRecords(List ids) throws JsonProcessingException {
+ var results = collection.find(in(ID, ids));
+ return formatResults(results);
+ }
+
+ public List getExistingHandles(List ids) {
+ var results = collection.find(in(ID, ids));
+ if (results.first() == null) {
+ return Collections.emptyList();
+ }
+ var existingHandles = new ArrayList();
+ results.forEach(r -> existingHandles.add(r.get(ID).toString()));
+ return existingHandles;
+ }
+
+ public void postHandleRecords(List handleRecords) {
+ collection.insertMany(handleRecords);
+ }
+
+ public void updateHandleRecords(List handleRecords) {
+ var queryList = handleRecords.stream().map(doc -> {
+ var filter = eq(doc.get(ID));
+ return new ReplaceOneModel<>(filter, doc);
+ }).toList();
+ collection.bulkWrite(queryList);
+ }
+
+ public List searchByPrimaryLocalId(String localIdField, List localIds)
+ throws JsonProcessingException {
+ var results = collection.find(in(localIdField, localIds));
+ return formatResults(results);
+ }
+
+ public void rollbackHandles(List ids) {
+ var filter = in(ID, ids);
+ collection.deleteMany(filter);
+ }
+
+ public void rollbackHandles(String localIdField, List localIds) {
+ var filter = in(localIdField, localIds);
+ collection.deleteMany(filter);
+ }
+
+ private List formatResults(FindIterable results)
+ throws JsonProcessingException {
+ var handleRecords = new ArrayList();
+ for (var result : results) {
+ var jsonRecord = mapper.readValue(result.toJson(), JsonNode.class);
+ if (jsonRecord.get("values") == null) {
+ log.warn("Unable to read handle record values \n {}",
+ mapper.writeValueAsString(jsonRecord));
+ } else {
+ var attributes = mapper.convertValue(jsonRecord.get("values"),
+ new TypeReference>() {
+ });
+ var fdoType = getFdoType(attributes, jsonRecord.get("_id").asText());
+ handleRecords.add(new FdoRecord(jsonRecord.get("_id").asText(),
+ fdoType, attributes, getLocalId(jsonRecord, fdoType)));
+ }
+ }
+ return handleRecords;
+ }
+
+ private FdoType getFdoType(List fdoAttributes, String id) {
+ for (var fdoAttribute : fdoAttributes) {
+ if (DIGITAL_OBJECT_TYPE.index() == fdoAttribute.getIndex()) {
+ return FdoType.fromString(fdoAttribute.getValue());
+ }
+ }
+ log.error("Unable to determine Fdo Type for record of handle {}", id);
+ throw new IllegalStateException();
+ }
+
+ private String getLocalId(JsonNode jsonRecord, FdoType fdoType) {
+ if (FdoType.DIGITAL_SPECIMEN.equals(fdoType)) {
+ return jsonRecord.get(NORMALISED_SPECIMEN_OBJECT_ID.get()).asText();
+ }
+ if (FdoType.DIGITAL_MEDIA.equals(fdoType)) {
+ return jsonRecord.get(PRIMARY_MEDIA_ID.get()).asText();
+ }
+ return null;
+ }
+}
diff --git a/src/main/java/eu/dissco/core/handlemanager/repository/PidRepository.java b/src/main/java/eu/dissco/core/handlemanager/repository/PidRepository.java
deleted file mode 100644
index 96819a70..00000000
--- a/src/main/java/eu/dissco/core/handlemanager/repository/PidRepository.java
+++ /dev/null
@@ -1,268 +0,0 @@
-package eu.dissco.core.handlemanager.repository;
-
-import static eu.dissco.core.handlemanager.database.jooq.tables.Handles.HANDLES;
-import static eu.dissco.core.handlemanager.domain.fdo.FdoProfile.HS_ADMIN;
-import static eu.dissco.core.handlemanager.domain.fdo.FdoProfile.NORMALISED_SPECIMEN_OBJECT_ID;
-import static eu.dissco.core.handlemanager.domain.fdo.FdoProfile.PID_RECORD_ISSUE_NUMBER;
-import static eu.dissco.core.handlemanager.domain.fdo.FdoProfile.PID_STATUS;
-import static eu.dissco.core.handlemanager.domain.fdo.FdoProfile.PRIMARY_SPECIMEN_OBJECT_ID;
-import static org.jooq.impl.DSL.select;
-
-import eu.dissco.core.handlemanager.domain.repsitoryobjects.HandleAttribute;
-import java.nio.charset.StandardCharsets;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.stream.Collectors;
-import lombok.RequiredArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
-import org.jooq.DSLContext;
-import org.jooq.Query;
-import org.jooq.Record4;
-import org.jooq.SelectConditionStep;
-import org.springframework.stereotype.Repository;
-
-@Slf4j
-@Repository
-@RequiredArgsConstructor
-public class PidRepository {
-
- private static final int TTL = 86400;
- private final DSLContext context;
- private final BatchInserter batchInserter;
-
- // For Handle Name Generation
- public List getHandlesExist(List handles) {
- return context.selectDistinct(HANDLES.HANDLE).from(HANDLES).where(HANDLES.HANDLE.in(handles))
- .fetch().getValues(HANDLES.HANDLE, byte[].class);
- }
-
- public List checkHandlesWritable(List handles) {
- return context.selectDistinct(HANDLES.HANDLE).from(HANDLES).where(HANDLES.HANDLE.in(handles))
- .and(HANDLES.TYPE.eq(PID_STATUS.get().getBytes(StandardCharsets.UTF_8)))
- .and(HANDLES.DATA.notEqual("ARCHIVED".getBytes())).fetch()
- .getValues(HANDLES.HANDLE, byte[].class);
- }
-
- public List resolveHandleAttributes(byte[] handle) {
- return context.select(HANDLES.IDX, HANDLES.HANDLE, HANDLES.TYPE, HANDLES.DATA).from(HANDLES)
- .where(HANDLES.HANDLE.eq(handle))
- .and(HANDLES.TYPE.notEqual(HS_ADMIN.get().getBytes(StandardCharsets.UTF_8)))
- .fetch(this::mapToAttribute);
- }
-
- public List resolveHandleAttributes(List handles) {
- return context.select(HANDLES.IDX, HANDLES.HANDLE, HANDLES.TYPE, HANDLES.DATA).from(HANDLES)
- .where(HANDLES.HANDLE.in(handles))
- .and(HANDLES.TYPE.notEqual(HS_ADMIN.get().getBytes(StandardCharsets.UTF_8)))
- .fetch(this::mapToAttribute);
- }
-
- public List searchByNormalisedPhysicalIdentifier(
- List normalisedPhysicalIdentifiers) {
- return context.select(HANDLES.IDX, HANDLES.HANDLE, HANDLES.TYPE, HANDLES.DATA).from(HANDLES)
- .where(HANDLES.HANDLE.in(select(HANDLES.HANDLE).from(HANDLES)
- .where(HANDLES.TYPE.eq(PID_STATUS.get().getBytes(StandardCharsets.UTF_8)))
- .and(HANDLES.DATA.notEqual("ARCHIVED".getBytes(StandardCharsets.UTF_8))).and(
- HANDLES.HANDLE.in(
- select(HANDLES.HANDLE).from(HANDLES).where(HANDLES.TYPE.eq(
- NORMALISED_SPECIMEN_OBJECT_ID.get()
- .getBytes(StandardCharsets.UTF_8)))
- .and(HANDLES.DATA.in(normalisedPhysicalIdentifiers))))))
- .and(HANDLES.TYPE.eq(
- NORMALISED_SPECIMEN_OBJECT_ID.get().getBytes(StandardCharsets.UTF_8)))
- .fetch(this::mapToAttribute);
- }
-
- public List getPrimarySpecimenObjectId(List handles) {
- return context.select(HANDLES.IDX, HANDLES.HANDLE, HANDLES.TYPE, HANDLES.DATA).from(HANDLES)
- .where(HANDLES.HANDLE.in(handles))
- .and(HANDLES.TYPE.eq(PRIMARY_SPECIMEN_OBJECT_ID.get().getBytes(StandardCharsets.UTF_8)))
- .fetch(this::mapToAttribute);
- }
-
- public List searchByNormalisedPhysicalIdentifierFullRecord(
- List normalisedPhysicalIdentifiers) {
- var normalisedPhysicalIdentifierTable = searchByNormalisedPhysicalIdentifierQuery(
- normalisedPhysicalIdentifiers).asTable("normalisedPhysicalIdentifierTable");
-
- return context.select(HANDLES.IDX, HANDLES.HANDLE, HANDLES.TYPE, HANDLES.DATA).from(HANDLES)
- .join(normalisedPhysicalIdentifierTable)
- .on(HANDLES.HANDLE.eq(normalisedPhysicalIdentifierTable.field(HANDLES.HANDLE)))
- .where(HANDLES.TYPE.notEqual(HS_ADMIN.get().getBytes(StandardCharsets.UTF_8)))
- .fetch(this::mapToAttribute);
- }
-
- private SelectConditionStep> searchByNormalisedPhysicalIdentifierQuery(
- List normalisedPhysicalIdentifiers) {
- return context.select(HANDLES.IDX, HANDLES.HANDLE, HANDLES.TYPE, HANDLES.DATA).from(HANDLES)
- .where(
- HANDLES.TYPE.eq(NORMALISED_SPECIMEN_OBJECT_ID.get().getBytes(StandardCharsets.UTF_8)))
- .and((HANDLES.DATA).in(normalisedPhysicalIdentifiers));
- }
-
- // Get List of Pids
- public List getAllHandles(byte[] pidStatus, int pageNum, int pageSize) {
- int offset = getOffset(pageNum, pageSize);
-
- return context.selectDistinct(HANDLES.HANDLE).from(HANDLES)
- .where(HANDLES.TYPE.eq(PID_STATUS.get().getBytes(StandardCharsets.UTF_8)))
- .and(HANDLES.DATA.eq(pidStatus)).limit(pageSize).offset(offset).fetch()
- .getValues(HANDLES.HANDLE, String.class);
- }
-
- public List getAllHandles(int pageNum, int pageSize) {
- int offset = getOffset(pageNum, pageSize);
- return context.selectDistinct(HANDLES.HANDLE).from(HANDLES).limit(pageSize).offset(offset)
- .fetch().getValues(HANDLES.HANDLE, String.class);
- }
-
- private HandleAttribute mapToAttribute(Record4 row) {
- return new HandleAttribute(row.get(HANDLES.IDX), row.get(HANDLES.HANDLE),
- new String(row.get(HANDLES.TYPE), StandardCharsets.UTF_8), row.get(HANDLES.DATA));
- }
-
- // Post
- public void postAttributesToDb(long recordTimestamp, List handleAttributes) {
- batchInserter.batchCopy(recordTimestamp, handleAttributes);
- }
-
- private List prepareBatchPostQuery(long recordTimestamp,
- List handleAttributes) {
- var queryList = new ArrayList();
-
- for (var handleAttribute : handleAttributes) {
- var query = context.insertInto(HANDLES).set(HANDLES.HANDLE, handleAttribute.getHandle())
- .set(HANDLES.IDX, handleAttribute.getIndex())
- .set(HANDLES.TYPE, handleAttribute.getType().getBytes(StandardCharsets.UTF_8))
- .set(HANDLES.DATA, handleAttribute.getData()).set(HANDLES.TTL, TTL)
- .set(HANDLES.TIMESTAMP, recordTimestamp).set(HANDLES.ADMIN_READ, true)
- .set(HANDLES.ADMIN_WRITE, true).set(HANDLES.PUB_READ, true)
- .set(HANDLES.PUB_WRITE, false);
- queryList.add(query);
- }
- return queryList;
- }
-
- // Archive
- public void archiveRecords(long recordTimestamp, List handleAttributes,
- List handles) {
- updateRecord(recordTimestamp, handleAttributes, true);
- deleteNonTombstoneAttributes(handles);
- }
-
- private void deleteNonTombstoneAttributes(List handles) {
- context.delete(HANDLES).where(HANDLES.HANDLE.in(handles)).and(HANDLES.IDX.notBetween(1).and(39))
- .and(HANDLES.IDX.notBetween(100).and(101)).execute();
- }
-
- public void postAndUpdateHandles(long recordTimestamp, List createAttributes,
- List> updateAttributes) {
- var queryList = prepareBatchUpdateQuery(recordTimestamp, updateAttributes, true);
- queryList.addAll(prepareBatchPostQuery(recordTimestamp, createAttributes));
- context.batch(queryList).execute();
- }
-
- // Update
- public void updateRecord(long recordTimestamp, List handleAttributes,
- boolean incrementVersion) {
- var queryList = prepareUpdateQuery(recordTimestamp, handleAttributes);
- if (incrementVersion) {
- queryList.addAll(
- getVersionIncrementQuery(Set.of(handleAttributes.get(0).getHandle()),
- recordTimestamp));
- }
- context.batch(queryList).execute();
- }
-
- public void updateRecordBatch(long recordTimestamp, List> handleRecords,
- boolean incrementVersion) {
- var queryList = prepareBatchUpdateQuery(recordTimestamp, handleRecords, incrementVersion);
- context.batch(queryList).execute();
- }
-
- private List prepareBatchUpdateQuery(long recordTimestamp,
- List> handleRecords, boolean incrementVersion) {
- List queryList = new ArrayList<>();
- for (List handleRecord : handleRecords) {
- queryList.addAll(prepareUpdateQuery(recordTimestamp, handleRecord));
- }
- if (incrementVersion) {
- var handles = handleRecords.stream().map(h -> h.get(0).getHandle())
- .collect(Collectors.toSet());
- queryList.addAll(getVersionIncrementQuery(handles, recordTimestamp));
- }
- return queryList;
- }
-
- private ArrayList prepareUpdateQuery(long recordTimestamp,
- List handleAttributes) {
- var queryList = new ArrayList();
- for (var handleAttribute : handleAttributes) {
- var query = context.insertInto(HANDLES).set(HANDLES.HANDLE, handleAttribute.getHandle())
- .set(HANDLES.IDX, handleAttribute.getIndex())
- .set(HANDLES.TYPE, handleAttribute.getType().getBytes(StandardCharsets.UTF_8))
- .set(HANDLES.DATA, handleAttribute.getData()).set(HANDLES.TTL, TTL)
- .set(HANDLES.TIMESTAMP, recordTimestamp).set(HANDLES.ADMIN_READ, true)
- .set(HANDLES.ADMIN_WRITE, true).set(HANDLES.PUB_READ, true)
- .set(HANDLES.PUB_WRITE, false)
- .onDuplicateKeyUpdate().set(HANDLES.HANDLE, handleAttribute.getHandle())
- .set(HANDLES.IDX, handleAttribute.getIndex())
- .set(HANDLES.TYPE, handleAttribute.getType().getBytes(StandardCharsets.UTF_8))
- .set(HANDLES.DATA, handleAttribute.getData()).set(HANDLES.TTL, TTL)
- .set(HANDLES.TIMESTAMP, recordTimestamp).set(HANDLES.ADMIN_READ, true)
- .set(HANDLES.ADMIN_WRITE, true).set(HANDLES.PUB_READ, true)
- .set(HANDLES.PUB_WRITE, false);
- queryList.add(query);
- }
- return queryList;
- }
-
- private List getVersionIncrementQuery(Set handles, long recordTimestamp) {
- var versions = getIncrementedVersions(handles);
- var handleStr = handles.stream().map(h -> new String(h, StandardCharsets.UTF_8)).toList();
- List queryList = new ArrayList<>();
- for (var handle : handleStr) {
- queryList.add(context.update(HANDLES)
- .set(HANDLES.DATA, versions.get(handle))
- .set(HANDLES.TIMESTAMP, recordTimestamp)
- .where(HANDLES.HANDLE.eq(handle.getBytes(StandardCharsets.UTF_8)))
- .and(HANDLES.TYPE.eq(
- PID_RECORD_ISSUE_NUMBER.get().getBytes(StandardCharsets.UTF_8))));
- }
- return queryList;
- }
-
- private Map getIncrementedVersions(Set handles) {
- var versions = context.select(HANDLES.HANDLE, HANDLES.DATA)
- .from(HANDLES)
- .where(HANDLES.HANDLE.in(handles)
- .and(HANDLES.TYPE.eq(
- PID_RECORD_ISSUE_NUMBER.get().getBytes(StandardCharsets.UTF_8))))
- .fetchMap(HANDLES.HANDLE, HANDLES.DATA);
- return versions.entrySet().stream()
- .collect(Collectors.toMap(
- e -> new String(e.getKey(), StandardCharsets.UTF_8),
- e -> incrementByteArray(e.getValue())
- ));
- }
-
- private static byte[] incrementByteArray(byte[] version) {
- var originalVersion = Integer.parseInt(new String(version, StandardCharsets.UTF_8));
- return String.valueOf(originalVersion + 1).getBytes(StandardCharsets.UTF_8);
- }
-
- public void rollbackHandles(List handles) {
- context.delete(HANDLES).where(HANDLES.HANDLE.in(handles)).execute();
- }
-
- private int getOffset(int pageNum, int pageSize) {
- int offset = 0;
- if (pageNum > 1) {
- offset = offset + (pageSize * (pageNum - 1));
- }
- return offset;
- }
-
-}
diff --git a/src/main/java/eu/dissco/core/handlemanager/security/WebSecurityConfig.java b/src/main/java/eu/dissco/core/handlemanager/security/WebSecurityConfig.java
index b4b3540f..e2488074 100644
--- a/src/main/java/eu/dissco/core/handlemanager/security/WebSecurityConfig.java
+++ b/src/main/java/eu/dissco/core/handlemanager/security/WebSecurityConfig.java
@@ -15,7 +15,7 @@
@RequiredArgsConstructor
@Configuration
@EnableWebSecurity
-public class WebSecurityConfig {
+public class WebSecurityConfig {
private final JwtAuthConverter jwtAuthConverter;
diff --git a/src/main/java/eu/dissco/core/handlemanager/service/DoiService.java b/src/main/java/eu/dissco/core/handlemanager/service/DoiService.java
index 941c6486..731c8477 100644
--- a/src/main/java/eu/dissco/core/handlemanager/service/DoiService.java
+++ b/src/main/java/eu/dissco/core/handlemanager/service/DoiService.java
@@ -1,8 +1,6 @@
package eu.dissco.core.handlemanager.service;
-import static eu.dissco.core.handlemanager.domain.fdo.FdoType.DIGITAL_MEDIA;
-import static eu.dissco.core.handlemanager.domain.fdo.FdoType.DIGITAL_SPECIMEN;
import static eu.dissco.core.handlemanager.domain.jsonapi.JsonApiFields.NODE_ATTRIBUTES;
import static eu.dissco.core.handlemanager.domain.jsonapi.JsonApiFields.NODE_DATA;
@@ -12,20 +10,16 @@
import eu.dissco.core.handlemanager.Profiles;
import eu.dissco.core.handlemanager.domain.datacite.DataCiteEvent;
import eu.dissco.core.handlemanager.domain.datacite.EventType;
-import eu.dissco.core.handlemanager.domain.fdo.FdoProfile;
-import eu.dissco.core.handlemanager.domain.fdo.FdoType;
import eu.dissco.core.handlemanager.domain.jsonapi.JsonApiWrapperWrite;
-import eu.dissco.core.handlemanager.domain.repsitoryobjects.HandleAttribute;
+import eu.dissco.core.handlemanager.domain.repsitoryobjects.FdoRecord;
import eu.dissco.core.handlemanager.exceptions.InvalidRequestException;
import eu.dissco.core.handlemanager.exceptions.PidResolutionException;
import eu.dissco.core.handlemanager.exceptions.UnprocessableEntityException;
import eu.dissco.core.handlemanager.properties.ProfileProperties;
-import eu.dissco.core.handlemanager.repository.PidRepository;
-import java.nio.charset.StandardCharsets;
-import java.time.Instant;
-import java.util.ArrayList;
+import eu.dissco.core.handlemanager.repository.MongoRepository;
import java.util.List;
import lombok.extern.slf4j.Slf4j;
+import org.bson.Document;
import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Service;
@@ -36,11 +30,12 @@ public class DoiService extends PidService {
private final DataCiteService dataCiteService;
- public DoiService(PidRepository pidRepository,
- FdoRecordService fdoRecordService, PidNameGeneratorService pidNameGeneratorService,
+ public DoiService(FdoRecordService fdoRecordService,
+ PidNameGeneratorService pidNameGeneratorService,
ObjectMapper mapper, ProfileProperties profileProperties,
- DataCiteService dataCiteService) {
- super(pidRepository, fdoRecordService, pidNameGeneratorService, mapper, profileProperties);
+ DataCiteService dataCiteService, MongoRepository mongoRepository) {
+ super(fdoRecordService, pidNameGeneratorService, mapper, profileProperties,
+ mongoRepository);
this.dataCiteService = dataCiteService;
}
@@ -49,68 +44,73 @@ public DoiService(PidRepository pidRepository,
@Override
public JsonApiWrapperWrite createRecords(List requests)
throws InvalidRequestException, UnprocessableEntityException {
- var handles = hf.genHandleList(requests.size()).iterator();
+ var handles = hf.generateNewHandles(requests.size()).iterator();
var requestAttributes = requests.stream()
.map(request -> request.get(NODE_DATA).get(NODE_ATTRIBUTES)).toList();
var type = getObjectTypeFromJsonNode(requests);
- List handleAttributes;
+ List fdoDocuments;
+ List fdoRecords;
try {
switch (type) {
- case DIGITAL_SPECIMEN ->
- handleAttributes = createDigitalSpecimen(requestAttributes, handles);
- case DIGITAL_MEDIA -> handleAttributes = createDigitalMedia(requestAttributes, handles);
+ case DIGITAL_SPECIMEN -> fdoRecords = createDigitalSpecimen(requestAttributes, handles);
+ case DIGITAL_MEDIA -> fdoRecords = createDigitalMedia(requestAttributes, handles);
default -> throw new UnsupportedOperationException(
- type + " is not an appropriate Type for DOI endpoint.");
+ String.format(TYPE_ERROR_MESSAGE, type.getDigitalObjectName()));
}
+ fdoDocuments = toMongoDbDocument(fdoRecords);
} catch (JsonProcessingException | PidResolutionException e) {
throw new InvalidRequestException(
"An error has occurred parsing a record in request. More information: "
+ e.getMessage());
}
- log.info("Persisting new dois to db");
- pidRepository.postAttributesToDb(Instant.now().getEpochSecond(), handleAttributes);
+ log.info("Persisting new DOIs to Document Store");
+ mongoRepository.postHandleRecords(fdoDocuments);
log.info("Publishing to DataCite");
- publishToDataCite(handleAttributes, EventType.CREATE, type);
- return new JsonApiWrapperWrite(formatCreateRecords(handleAttributes, type));
+ publishToDataCite(fdoRecords, EventType.CREATE);
+ return new JsonApiWrapperWrite(formatFdoRecord(fdoRecords, type));
}
@Override
public JsonApiWrapperWrite updateRecords(List requests, boolean incrementVersion)
throws InvalidRequestException, UnprocessableEntityException {
- var type = getObjectTypeFromJsonNode(requests);
- if (!DIGITAL_SPECIMEN.equals(type) && !DIGITAL_MEDIA.equals(type)) {
- throw new InvalidRequestException(TYPE_ERROR_MESSAGE);
+ var updateRequests = requests.stream()
+ .map(request -> request.get(NODE_DATA)).toList();
+ var fdoRecordMap = processUpdateRequest(updateRequests);
+ var fdoType = getObjectTypeFromJsonNode(requests);
+ List fdoRecords;
+ List fdoDocuments;
+ try {
+ switch (fdoType) {
+ case DIGITAL_SPECIMEN ->
+ fdoRecords = updateDigitalSpecimen(updateRequests, fdoRecordMap, incrementVersion);
+ case DIGITAL_MEDIA ->
+ fdoRecords = updateDigitalMedia(updateRequests, fdoRecordMap, incrementVersion);
+ default -> throw new UnsupportedOperationException(
+ String.format(TYPE_ERROR_MESSAGE, fdoType.getDigitalObjectName()));
+ }
+ fdoDocuments = toMongoDbDocument(fdoRecords);
+ mongoRepository.updateHandleRecords(fdoDocuments);
+ publishToDataCite(fdoRecords, EventType.UPDATE);
+ return new JsonApiWrapperWrite(formatFdoRecord(fdoRecords, fdoType));
+ } catch (JsonProcessingException e) {
+ log.error("An error has occurred processing JSON data", e);
+ throw new UnprocessableEntityException("Json Processing Error");
}
- var attributesToUpdate = getAttributesToUpdate(requests);
- var response = updateRecords(attributesToUpdate, incrementVersion, type);
- log.info("Publishing to datacite");
- var flatList = attributesToUpdate.stream().flatMap(List::stream).toList();
- publishToDataCite(flatList, EventType.UPDATE, type);
- return response;
}
- private void publishToDataCite(List handleAttributes, EventType eventType,
- FdoType objectType) throws UnprocessableEntityException {
- var handleMap = mapRecords(handleAttributes);
- var eventList = new ArrayList();
- handleMap.forEach(
- (key, value) -> {
- if (eventType.equals(EventType.UPDATE)) {
- value.add(
- new HandleAttribute(FdoProfile.PID, key.getBytes(StandardCharsets.UTF_8), key));
- }
- eventList.add(
- new DataCiteEvent(jsonFormatSingleRecord(value), eventType));
- });
-
+ private void publishToDataCite(List fdoRecords, EventType eventType)
+ throws UnprocessableEntityException {
+ var eventList = fdoRecords.stream()
+ .map(fdoRecord -> new DataCiteEvent(jsonFormatSingleRecord(fdoRecord.attributes()),
+ eventType)).toList();
for (var event : eventList) {
try {
- dataCiteService.publishToDataCite(event, objectType);
+ dataCiteService.publishToDataCite(event, fdoRecords.get(0).fdoType());
} catch (JsonProcessingException e) {
log.error("Critical error: Unable to publish datacite event to queue", e);
- log.info("Rolling back handles");
if (eventType.equals(EventType.CREATE)) {
- rollbackHandles(new ArrayList<>(handleMap.keySet()));
+ log.info("Rolling back handles");
+ rollbackHandles(fdoRecords.stream().map(FdoRecord::handle).toList());
}
throw new UnprocessableEntityException("Unable to publish datacite event to queue");
}
diff --git a/src/main/java/eu/dissco/core/handlemanager/service/FdoRecordService.java b/src/main/java/eu/dissco/core/handlemanager/service/FdoRecordService.java
index 3c533b2f..ebb4c9d1 100644
--- a/src/main/java/eu/dissco/core/handlemanager/service/FdoRecordService.java
+++ b/src/main/java/eu/dissco/core/handlemanager/service/FdoRecordService.java
@@ -1,9 +1,12 @@
package eu.dissco.core.handlemanager.service;
+import static eu.dissco.core.handlemanager.configuration.AppConfig.DATE_STRING;
import static eu.dissco.core.handlemanager.domain.fdo.FdoProfile.ANNOTATION_HASH;
import static eu.dissco.core.handlemanager.domain.fdo.FdoProfile.BASE_TYPE_OF_SPECIMEN;
import static eu.dissco.core.handlemanager.domain.fdo.FdoProfile.CATALOG_IDENTIFIER;
+import static eu.dissco.core.handlemanager.domain.fdo.FdoProfile.DCTERMS_FORMAT;
+import static eu.dissco.core.handlemanager.domain.fdo.FdoProfile.DCTERMS_SUBJECT;
import static eu.dissco.core.handlemanager.domain.fdo.FdoProfile.DCTERMS_TYPE;
import static eu.dissco.core.handlemanager.domain.fdo.FdoProfile.DC_TERMS_CONFORMS;
import static eu.dissco.core.handlemanager.domain.fdo.FdoProfile.DERIVED_FROM_ENTITY;
@@ -11,6 +14,7 @@
import static eu.dissco.core.handlemanager.domain.fdo.FdoProfile.DIGITAL_OBJECT_TYPE;
import static eu.dissco.core.handlemanager.domain.fdo.FdoProfile.FDO_PROFILE;
import static eu.dissco.core.handlemanager.domain.fdo.FdoProfile.FDO_RECORD_LICENSE;
+import static eu.dissco.core.handlemanager.domain.fdo.FdoProfile.HAS_RELATED_PID;
import static eu.dissco.core.handlemanager.domain.fdo.FdoProfile.HS_ADMIN;
import static eu.dissco.core.handlemanager.domain.fdo.FdoProfile.INFORMATION_ARTEFACT_TYPE;
import static eu.dissco.core.handlemanager.domain.fdo.FdoProfile.ISSUED_FOR_AGENT;
@@ -27,10 +31,8 @@
import static eu.dissco.core.handlemanager.domain.fdo.FdoProfile.MAS_NAME;
import static eu.dissco.core.handlemanager.domain.fdo.FdoProfile.MATERIAL_OR_DIGITAL_ENTITY;
import static eu.dissco.core.handlemanager.domain.fdo.FdoProfile.MATERIAL_SAMPLE_TYPE;
-import static eu.dissco.core.handlemanager.domain.fdo.FdoProfile.MEDIA_FORMAT;
import static eu.dissco.core.handlemanager.domain.fdo.FdoProfile.MEDIA_HOST;
import static eu.dissco.core.handlemanager.domain.fdo.FdoProfile.MEDIA_HOST_NAME;
-import static eu.dissco.core.handlemanager.domain.fdo.FdoProfile.MEDIA_MIME_TYPE;
import static eu.dissco.core.handlemanager.domain.fdo.FdoProfile.MOTIVATION;
import static eu.dissco.core.handlemanager.domain.fdo.FdoProfile.NORMALISED_SPECIMEN_OBJECT_ID;
import static eu.dissco.core.handlemanager.domain.fdo.FdoProfile.ORGANISATION_ID;
@@ -64,42 +66,43 @@
import static eu.dissco.core.handlemanager.domain.fdo.FdoProfile.STRUCTURAL_TYPE;
import static eu.dissco.core.handlemanager.domain.fdo.FdoProfile.TARGET_PID;
import static eu.dissco.core.handlemanager.domain.fdo.FdoProfile.TARGET_TYPE;
+import static eu.dissco.core.handlemanager.domain.fdo.FdoProfile.TOMBSTONED_DATE;
+import static eu.dissco.core.handlemanager.domain.fdo.FdoProfile.TOMBSTONED_TEXT;
import static eu.dissco.core.handlemanager.domain.fdo.FdoProfile.TOPIC_CATEGORY;
import static eu.dissco.core.handlemanager.domain.fdo.FdoProfile.TOPIC_DISCIPLINE;
import static eu.dissco.core.handlemanager.domain.fdo.FdoProfile.TOPIC_DOMAIN;
import static eu.dissco.core.handlemanager.domain.fdo.FdoProfile.TOPIC_ORIGIN;
import static eu.dissco.core.handlemanager.domain.fdo.FdoProfile.WAS_DERIVED_FROM_ENTITY;
+import static eu.dissco.core.handlemanager.domain.fdo.FdoType.ANNOTATION;
import static eu.dissco.core.handlemanager.domain.fdo.FdoType.DATA_MAPPING;
+import static eu.dissco.core.handlemanager.domain.fdo.FdoType.DIGITAL_MEDIA;
import static eu.dissco.core.handlemanager.domain.fdo.FdoType.DIGITAL_SPECIMEN;
+import static eu.dissco.core.handlemanager.domain.fdo.FdoType.MAS;
+import static eu.dissco.core.handlemanager.domain.fdo.FdoType.ORGANISATION;
+import static eu.dissco.core.handlemanager.domain.fdo.FdoType.SOURCE_SYSTEM;
+import static eu.dissco.core.handlemanager.service.ServiceUtils.getField;
import com.fasterxml.jackson.core.JsonProcessingException;
-import com.fasterxml.jackson.core.type.TypeReference;
-import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
-import com.fasterxml.jackson.databind.node.BaseJsonNode;
-import com.fasterxml.jackson.databind.node.ObjectNode;
-import com.fasterxml.jackson.databind.node.TextNode;
import eu.dissco.core.handlemanager.domain.fdo.AnnotationRequest;
import eu.dissco.core.handlemanager.domain.fdo.DataMappingRequest;
import eu.dissco.core.handlemanager.domain.fdo.DigitalMediaRequest;
import eu.dissco.core.handlemanager.domain.fdo.DigitalSpecimenRequest;
import eu.dissco.core.handlemanager.domain.fdo.DoiRecordRequest;
-import eu.dissco.core.handlemanager.domain.fdo.FdoProfile;
import eu.dissco.core.handlemanager.domain.fdo.FdoType;
import eu.dissco.core.handlemanager.domain.fdo.HandleRecordRequest;
import eu.dissco.core.handlemanager.domain.fdo.MasRequest;
import eu.dissco.core.handlemanager.domain.fdo.OrganisationRequest;
import eu.dissco.core.handlemanager.domain.fdo.SourceSystemRequest;
-import eu.dissco.core.handlemanager.domain.repsitoryobjects.HandleAttribute;
+import eu.dissco.core.handlemanager.domain.fdo.TombstoneRecordRequest;
+import eu.dissco.core.handlemanager.domain.fdo.vocabulary.PidStatus;
+import eu.dissco.core.handlemanager.domain.repsitoryobjects.FdoAttribute;
+import eu.dissco.core.handlemanager.domain.repsitoryobjects.FdoRecord;
import eu.dissco.core.handlemanager.exceptions.InvalidRequestException;
-import eu.dissco.core.handlemanager.exceptions.InvalidRequestRuntimeException;
-import eu.dissco.core.handlemanager.exceptions.PidResolutionException;
import eu.dissco.core.handlemanager.properties.ApplicationProperties;
-import eu.dissco.core.handlemanager.properties.ProfileProperties;
import eu.dissco.core.handlemanager.web.PidResolver;
-import java.io.IOException;
+import jakarta.annotation.Nullable;
import java.io.StringWriter;
-import java.nio.charset.StandardCharsets;
import java.time.Instant;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
@@ -108,7 +111,6 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
-import java.util.stream.Collectors;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
@@ -120,7 +122,7 @@
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
-import org.w3c.dom.Document;
+
@RequiredArgsConstructor
@Service
@@ -131,20 +133,30 @@ public class FdoRecordService {
private final DocumentBuilderFactory dbf;
private final PidResolver pidResolver;
private final ObjectMapper mapper;
- private final ApplicationProperties appProperties;
- private final ProfileProperties profileProperties;
- private static final String HANDLE_DOMAIN = "https://hdl.handle.net/";
- private static final String DOI_DOMAIN = "https://doi.org/";
+ private final ApplicationProperties applicationProperties;
+ public static final String HANDLE_DOMAIN = "https://hdl.handle.net/";
+ public static final String DOI_DOMAIN = "https://doi.org/";
private static final String ROR_API_DOMAIN = "https://api.ror.org/organizations/";
private static final String ROR_DOMAIN = "https://ror.org/";
private static final String WIKIDATA_DOMAIN = "https://www.wikidata.org/wiki/";
private static final String WIKIDATA_API = "https://wikidata.org/w/rest.php/wikibase/v0/entities/items/";
private static final String PROXY_ERROR = "Invalid attribute: %s must contain proxy: %s";
private static final String PID_KERNEL_METADATA_LICENSE = "https://creativecommons.org/publicdomain/zero/1.0/";
- private static final byte[] ADMIN_HEX = "\\\\x0FFF000000153330303A302E4E412F32302E353030302E31303235000000C8".getBytes(
- StandardCharsets.UTF_8);
private static final String LOC_REQUEST = "locations";
public static final Map RESOLVABLE_KEYS;
+ public static final List GENERATED_KEYS;
+ public static final List TOMBSTONE_KEYS;
+
+ static {
+ GENERATED_KEYS = List.of(FDO_RECORD_LICENSE.index(), PID.index(), PID_RECORD_ISSUE_DATE.index(),
+ PID_STATUS.index(), HS_ADMIN.index());
+ }
+
+ static {
+ TOMBSTONE_KEYS = List.of(FDO_RECORD_LICENSE.index(), PID.index(), PID_RECORD_ISSUE_DATE.index(),
+ PID_ISSUER.index(), PID_ISSUER_NAME.index(), ISSUED_FOR_AGENT.index(),
+ ISSUED_FOR_AGENT_NAME.index(), STRUCTURAL_TYPE.index(), HS_ADMIN.index());
+ }
static {
HashMap hashMap = new HashMap<>();
@@ -155,510 +167,620 @@ public class FdoRecordService {
RESOLVABLE_KEYS = Collections.unmodifiableMap(hashMap);
}
- private final DateTimeFormatter dt = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSXXX")
+ private final DateTimeFormatter dt = DateTimeFormatter.ofPattern(DATE_STRING)
.withZone(ZoneId.of("UTC"));
- public HandleAttribute genHsAdmin(byte[] handle) {
- return new HandleAttribute(HS_ADMIN.index(), handle, HS_ADMIN.get(), ADMIN_HEX);
+ /* Handle Record Creation */
+ public FdoRecord prepareNewHandleRecord(HandleRecordRequest request, String handle,
+ FdoType fdoType, Instant timestamp) throws InvalidRequestException {
+ var fdoAttributes = prepareNewHandleAttributes(request, handle, fdoType, timestamp);
+ return new FdoRecord(handle, fdoType, fdoAttributes, null);
}
- public List prepareHandleRecordAttributes(HandleRecordRequest request,
- byte[] handle, FdoType type) throws InvalidRequestException {
- List fdoRecord = new ArrayList<>();
-
- // 100: Admin Handle
- fdoRecord.add(genHsAdmin(handle));
-
- // 101: 10320/loc
- if (type != FdoType.ORGANISATION) {
- byte[] loc = setLocations(request.getLocations(), new String(handle, StandardCharsets.UTF_8),
- type);
- fdoRecord.add(new HandleAttribute(LOC.index(), handle, LOC.get(), loc));
- }
-
- // 1: FDO Profile
- fdoRecord.add(new HandleAttribute(FDO_PROFILE, handle, type.getFdoProfile()));
-
- // 2: FDO Record License
- fdoRecord.add(new HandleAttribute(FDO_RECORD_LICENSE, handle, PID_KERNEL_METADATA_LICENSE));
-
- // 3: DigitalObjectType
- fdoRecord.add(new HandleAttribute(DIGITAL_OBJECT_TYPE, handle, type.getDigitalObjectType()));
-
- // 4: DigitalObjectName
- fdoRecord.add(new HandleAttribute(DIGITAL_OBJECT_NAME, handle, type.getDigitalObjectName()));
-
- // 5: Pid
- var pid = profileProperties.getDomain() + new String(handle, StandardCharsets.UTF_8);
- fdoRecord.add(new HandleAttribute(PID, handle, pid));
-
- // 6: PidIssuer
- fdoRecord.add(new HandleAttribute(PID_ISSUER, handle, request.getPidIssuer()));
-
- // 7: pidIssuerName
- String pidIssuerName = getObjectName(request.getPidIssuer());
- fdoRecord.add(new HandleAttribute(PID_ISSUER_NAME, handle, pidIssuerName));
-
- // 8: issuedForAgent
- fdoRecord.add(new HandleAttribute(ISSUED_FOR_AGENT, handle, request.getIssuedForAgent()));
-
- // 9: issuedForAgentName
- var agentNameRor = getRor(request.getIssuedForAgent());
- var issuedForAgentName = pidResolver.getObjectName(agentNameRor);
- fdoRecord.add(new HandleAttribute(ISSUED_FOR_AGENT_NAME, handle, issuedForAgentName));
-
- // 10: pidRecordIssueDate
- fdoRecord.add(new HandleAttribute(PID_RECORD_ISSUE_DATE, handle, getDate()));
-
- // 11: pidRecordIssueNumber
- fdoRecord.add(new HandleAttribute(PID_RECORD_ISSUE_NUMBER, handle, "1"));
-
- // 12: structuralType
- fdoRecord.add(
- new HandleAttribute(STRUCTURAL_TYPE, handle, request.getStructuralType().toString()));
-
- // 13: PidStatus
- fdoRecord.add(new HandleAttribute(PID_STATUS, handle, "TEST"));
-
- return fdoRecord;
+ public FdoRecord prepareUpdatedHandleRecord(HandleRecordRequest recordRequest,
+ FdoType fdoType, Instant timestamp, FdoRecord previousVersion, boolean incrementVersion)
+ throws InvalidRequestException {
+ var fdoAttributes = prepareUpdatedHandleAttributes(recordRequest,
+ previousVersion.handle(), fdoType,
+ timestamp, previousVersion, incrementVersion);
+ return new FdoRecord(previousVersion.handle(), fdoType, fdoAttributes, null);
}
- private String getObjectName(String url) throws InvalidRequestException {
- if (url.contains(ROR_DOMAIN)) {
- return pidResolver.getObjectName(getRor(url));
- } else if (url.contains(HANDLE_DOMAIN) || url.contains(DOI_DOMAIN)) {
- return pidResolver.getObjectName(url);
- }
- throw new InvalidRequestException(String.format(PROXY_ERROR, url,
- (ROR_DOMAIN + ", " + HANDLE_DOMAIN + ", or " + DOI_DOMAIN)));
+ private List prepareNewHandleAttributes(HandleRecordRequest request,
+ String handle,
+ FdoType fdoType, Instant timestamp) throws InvalidRequestException {
+ var handleAttributes = prepareHandleAttributesFromRequest(request, handle, fdoType, timestamp);
+ handleAttributes.addAll(prepareHandleAttributesGenerated(handle, fdoType, timestamp));
+ return handleAttributes;
}
- private static String getRor(String url) throws InvalidRequestException {
- if (!url.contains(ROR_DOMAIN)) {
- throw new InvalidRequestException(String.format(PROXY_ERROR, url, ROR_DOMAIN));
+ private List prepareUpdatedHandleAttributes(HandleRecordRequest request,
+ String handle, FdoType fdoType, Instant timestamp, FdoRecord previousVersion,
+ boolean incrementVersion)
+ throws InvalidRequestException {
+ var previousAttributes = new ArrayList<>(previousVersion.attributes());
+ var updatedAttributes = prepareHandleAttributesFromRequest(request, handle, fdoType, timestamp);
+ updatedAttributes.addAll(previousAttributes.stream()
+ .filter(previousAttribute -> GENERATED_KEYS.contains(previousAttribute.getIndex()))
+ .toList());
+ var previousIssueNumber = getField(previousVersion.attributes(), PID_RECORD_ISSUE_NUMBER);
+ if (incrementVersion) {
+ updatedAttributes.add(incrementIssueNumber(previousIssueNumber, timestamp));
+ } else {
+ updatedAttributes.add(previousIssueNumber);
}
- return url.replace(ROR_DOMAIN, ROR_API_DOMAIN);
+ return updatedAttributes;
}
- public List prepareDoiRecordAttributes(DoiRecordRequest request, byte[] handle,
- FdoType type) throws InvalidRequestException {
- var fdoRecord = prepareHandleRecordAttributes(request, handle, type);
-
- // 40: referentType
- fdoRecord.add(new HandleAttribute(REFERENT_TYPE, handle, request.getReferentType()));
-
- // 41: referentDoiName
- fdoRecord.add(
- new HandleAttribute(REFERENT_DOI_NAME.index(), handle, REFERENT_DOI_NAME.get(), handle));
-
- // 42: referentName
- if (request.getReferentName() != null) {
- fdoRecord.add(new HandleAttribute(REFERENT_NAME, handle, request.getReferentName()));
- }
- // 43: primaryReferentType
- fdoRecord.add(
- new HandleAttribute(PRIMARY_REFERENT_TYPE, handle, request.getPrimaryReferentType()));
-
- return fdoRecord;
+ private FdoAttribute incrementIssueNumber(FdoAttribute previousVersion, Instant timestamp) {
+ var previousIssueNumber = previousVersion.getValue();
+ var incrementedIssueNumber = String.valueOf(Integer.parseInt(previousIssueNumber) + 1);
+ return new FdoAttribute(PID_RECORD_ISSUE_NUMBER, timestamp, incrementedIssueNumber);
}
- public List prepareDigitalMediaAttributes(DigitalMediaRequest request,
- byte[] handle) throws InvalidRequestException {
- var fdoRecord = prepareDoiRecordAttributes(request, handle, FdoType.DIGITAL_MEDIA);
-
- fdoRecord.add(new HandleAttribute(MEDIA_HOST, handle, request.getMediaHost()));
- var mediaHostName = setHostName(request.getMediaHostName(), request.getMediaHost(), handle,
- MEDIA_HOST_NAME);
- fdoRecord.add(mediaHostName);
- if (request.getMediaFormat() != null) {
- fdoRecord.add(new HandleAttribute(MEDIA_FORMAT, handle, request.getMediaFormat().toString()));
- }
- fdoRecord.add(new HandleAttribute(IS_DERIVED_FROM_SPECIMEN, handle,
- request.getIsDerivedFromSpecimen().toString()));
- fdoRecord.add(new HandleAttribute(LINKED_DO_PID, handle, request.getLinkedDigitalObjectPid()));
- fdoRecord.add(new HandleAttribute(LINKED_DO_TYPE, handle,
- request.getLinkedDigitalObjectType().toString()));
- if (request.getLinkedAttribute() != null) {
- fdoRecord.add(new HandleAttribute(LINKED_ATTRIBUTE, handle, request.getLinkedAttribute()));
- }
- fdoRecord.add(new HandleAttribute(PRIMARY_MEDIA_ID, handle, request.getPrimaryMediaId()));
-
- if (request.getDcTermsType() != null) {
- fdoRecord.add(new HandleAttribute(DCTERMS_TYPE, handle, request.getDcTermsType().toString()));
- }
- if (request.getPrimaryMediaObjectIdName() != null) {
- fdoRecord.add(
- new HandleAttribute(PRIMARY_MO_ID_NAME, handle, request.getPrimaryMediaObjectIdName()));
- }
- if (request.getPrimaryMediaObjectIdType() != null) {
- fdoRecord.add(new HandleAttribute(PRIMARY_MO_ID_TYPE, handle,
- request.getPrimaryMediaObjectIdType().toString()));
- }
- if (request.getMediaMimeType() != null) {
- fdoRecord.add(new HandleAttribute(MEDIA_MIME_TYPE, handle, request.getMediaMimeType()));
- }
- if (request.getDerivedFromEntity() != null) {
- fdoRecord.add(
- new HandleAttribute(DERIVED_FROM_ENTITY, handle, request.getDerivedFromEntity()));
- }
- if (request.getLicenseName() != null) {
- fdoRecord.add(new HandleAttribute(LICENSE_NAME, handle, request.getLicenseName()));
- }
- if (request.getLicense() != null) {
- fdoRecord.add(new HandleAttribute(LICENSE_URL, handle, request.getLicense()));
- }
- var rightsholderName = setHostName(request.getRightsholderName(), request.getRightsholderPid(),
- handle, RIGHTSHOLDER_NAME);
- fdoRecord.add(rightsholderName);
- if (request.getRightsholderPid() != null) {
- fdoRecord.add(new HandleAttribute(RIGHTSHOLDER_PID, handle, request.getRightsholderPid()));
- }
- if (request.getRightsholderPidType() != null) {
- fdoRecord.add(new HandleAttribute(RIGHTSHOLDER_PID_TYPE, handle,
- request.getRightsholderPidType().toString()));
- }
- if (request.getDctermsConformsTo() != null) {
- fdoRecord.add(new HandleAttribute(DC_TERMS_CONFORMS, handle, request.getDctermsConformsTo()));
+ // These attributes may change on an update
+ private ArrayList prepareHandleAttributesFromRequest(
+ HandleRecordRequest request,
+ String handle,
+ FdoType fdoType, Instant timestamp)
+ throws InvalidRequestException {
+ var handleAttributeList = new ArrayList();
+ // 101: 10320/Loc
+ if (!fdoType.equals(ORGANISATION)) {
+ handleAttributeList.add(new FdoAttribute(LOC, timestamp,
+ setLocations(request.getLocations(), handle, fdoType)));
}
- return fdoRecord;
+ // 1: FDO Profile
+ handleAttributeList.add(
+ new FdoAttribute(FDO_PROFILE, timestamp, fdoType.getFdoProfile()));
+ // 3: Digital Object Type
+ handleAttributeList.add(
+ new FdoAttribute(DIGITAL_OBJECT_TYPE, timestamp, fdoType.getDigitalObjectType()));
+ // 4: Digital ObjectName
+ handleAttributeList.add(
+ new FdoAttribute(DIGITAL_OBJECT_NAME, timestamp, fdoType.getDigitalObjectName()));
+ // 6: PID Issuer
+ handleAttributeList.add(new FdoAttribute(PID_ISSUER, timestamp, request.getPidIssuer()));
+ // 7: PID Issuer Name
+ handleAttributeList.add(new FdoAttribute(PID_ISSUER_NAME, timestamp,
+ getObjectName(request.getPidIssuer(), null)));
+ // 8: Issued For Agent
+ handleAttributeList.add(
+ new FdoAttribute(ISSUED_FOR_AGENT, timestamp, request.getIssuedForAgent()));
+ // 9: Issued for Agent Name
+ handleAttributeList.add(new FdoAttribute(ISSUED_FOR_AGENT_NAME, timestamp,
+ getObjectName(request.getIssuedForAgent(), null)));
+ // 12: Structural Type
+ handleAttributeList.add(
+ new FdoAttribute(STRUCTURAL_TYPE, timestamp, request.getStructuralType()));
+ return handleAttributeList;
}
- public List prepareAnnotationAttributes(AnnotationRequest request,
- byte[] handle) throws InvalidRequestException {
- var fdoRecord = prepareHandleRecordAttributes(request, handle, FdoType.ANNOTATION);
-
- // 500 TargetPid
- fdoRecord.add(new HandleAttribute(TARGET_PID, handle, request.getTargetPid()));
-
- // 501 TargetType
- fdoRecord.add(new HandleAttribute(TARGET_TYPE, handle, request.getTargetType()));
-
- // 502 motivation
- fdoRecord.add(new HandleAttribute(MOTIVATION, handle, request.getMotivation().toString()));
+ // These attributes do not depend on the request and do not change on an update (except issue number)
+ private List prepareHandleAttributesGenerated(String handle, FdoType fdoType,
+ Instant timestamp) {
+ var handleAttributeList = new ArrayList();
+ // 2: FDO Record License
+ handleAttributeList.add(
+ new FdoAttribute(FDO_RECORD_LICENSE, timestamp, PID_KERNEL_METADATA_LICENSE));
+ // 5: PID
+ handleAttributeList.add(new FdoAttribute(PID, timestamp, fdoType.getDomain() + handle));
+ // 10: PID Record Issue Date
+ handleAttributeList.add(
+ new FdoAttribute(PID_RECORD_ISSUE_DATE, timestamp, getDate(timestamp)));
+ // 11: Pid Record Issue Number
+ handleAttributeList.add(
+ new FdoAttribute(PID_RECORD_ISSUE_NUMBER, timestamp,
+ "1")); // This gets replaced on an update
+ // 13: Pid Status
+ handleAttributeList.add(new FdoAttribute(PID_STATUS, timestamp, PidStatus.ACTIVE.name()));
+ // 100 HS Admin
+ handleAttributeList.add(new FdoAttribute(timestamp, applicationProperties.getPrefix()));
+ return handleAttributeList;
+ }
- // 503 AnnotationHash
- if (request.getAnnotationHash() != null) {
- fdoRecord.add(
- new HandleAttribute(ANNOTATION_HASH, handle, request.getAnnotationHash().toString()));
- }
- return fdoRecord;
+ /* DOI Record Creation */
+ public FdoRecord prepareNewDoiRecord(DoiRecordRequest request, String handle,
+ FdoType fdoType, Instant timestamp) throws InvalidRequestException {
+ var fdoAttributes = prepareNewDoiAttributes(request, handle, fdoType, timestamp);
+ return new FdoRecord(handle, fdoType, fdoAttributes, null);
}
- public List prepareMasRecordAttributes(MasRequest request, byte[] handle)
+ public FdoRecord prepareUpdatedDoiRecord(DoiRecordRequest request,
+ FdoType fdoType, Instant timestamp, FdoRecord previousVersion, boolean incrementVersion)
throws InvalidRequestException {
- var fdoRecord = prepareHandleRecordAttributes(request, handle, FdoType.MAS);
- fdoRecord.add(new HandleAttribute(MAS_NAME, handle, request.getMachineAnnotationServiceName()));
- return fdoRecord;
+ var fdoAttributes = prepareUpdatedDoiAttributes(request, previousVersion.handle(), fdoType,
+ timestamp,
+ previousVersion, incrementVersion);
+ return new FdoRecord(previousVersion.handle(), fdoType, fdoAttributes, null);
}
-
- public List prepareSourceSystemAttributes(SourceSystemRequest request,
- byte[] handle) throws InvalidRequestException {
- var fdoRecord = prepareHandleRecordAttributes(request, handle, FdoType.SOURCE_SYSTEM);
-
- // 600 sourceSystemName
- fdoRecord.add(new HandleAttribute(SOURCE_SYSTEM_NAME, handle, request.getSourceSystemName()));
-
- return fdoRecord;
+ private List prepareNewDoiAttributes(DoiRecordRequest request,
+ String handle,
+ FdoType fdoType, Instant timestamp) throws InvalidRequestException {
+ var fdoAttributes = prepareNewHandleAttributes(request, handle, fdoType, timestamp);
+ fdoAttributes.addAll(prepareDoiAttributesFromRequest(request, handle, timestamp));
+ return fdoAttributes;
}
- public List prepareOrganisationAttributes(OrganisationRequest request,
- byte[] handle) throws InvalidRequestException {
- var fdoRecord = prepareDoiRecordAttributes(request, handle, FdoType.ORGANISATION);
-
- //101 10320/loc -> must contain ROR
- var objectLocations = new ArrayList<>(List.of(request.getOrganisationIdentifier()));
- if (request.getLocations() != null) {
- objectLocations.addAll(List.of(request.getLocations()));
- }
- byte[] loc = setLocations(objectLocations.toArray(new String[0]),
- new String(handle, StandardCharsets.UTF_8), FdoType.ORGANISATION);
- fdoRecord.add(new HandleAttribute(LOC.index(), handle, LOC.get(), loc));
-
- // 601 OrganisationIdentifier
- fdoRecord.add(
- new HandleAttribute(ORGANISATION_ID, handle, request.getOrganisationIdentifier()));
-
- // 602 OrganisationIdentifierType
- fdoRecord.add(
- new HandleAttribute(ORGANISATION_ID_TYPE, handle, request.getOrganisationIdentifierType()));
+ private List prepareUpdatedDoiAttributes(DoiRecordRequest request,
+ String handle,
+ FdoType fdoType, Instant timestamp, FdoRecord previousVersion, boolean incrementVersion)
+ throws InvalidRequestException {
+ var fdoAttributes = prepareUpdatedHandleAttributes(request, handle, fdoType, timestamp,
+ previousVersion,
+ incrementVersion);
+ fdoAttributes.addAll(prepareDoiAttributesFromRequest(request, handle, timestamp));
+ return fdoAttributes;
+ }
- // 603 OrganisationName
- var organisationName = pidResolver.getObjectName(getRor(request.getOrganisationIdentifier()));
- fdoRecord.add(new HandleAttribute(ORGANISATION_NAME, handle, organisationName));
+ private List prepareDoiAttributesFromRequest(DoiRecordRequest request,
+ String handle,
+ Instant timestamp) {
+ var handleAttributeList = new ArrayList();
+ // 40: Referent Type
+ handleAttributeList.add(
+ new FdoAttribute(REFERENT_TYPE, timestamp, request.getReferentType()));
+ // 41: Referent DOI Name
+ handleAttributeList.add(new FdoAttribute(REFERENT_DOI_NAME, timestamp, handle));
+ // 42: Referent Name
+ handleAttributeList.add(
+ new FdoAttribute(REFERENT_NAME, timestamp, request.getReferentName()));
+ // 43: Primary Referent Type
+ handleAttributeList.add(new FdoAttribute(PRIMARY_REFERENT_TYPE, timestamp,
+ request.getPrimaryReferentType()));
+ return handleAttributeList;
+ }
- return fdoRecord;
+ /* Annotation Record Creation */
+ public FdoRecord prepareNewAnnotationRecord(AnnotationRequest request, String handle,
+ Instant timestamp) throws InvalidRequestException {
+ var fdoAttributes = prepareNewHandleAttributes(request, handle, ANNOTATION,
+ timestamp);
+ fdoAttributes.addAll(prepareAnnotationAttributesFromRequest(request, timestamp));
+ var localId =
+ request.getAnnotationHash() != null ? request.getAnnotationHash().toString() : null;
+ return new FdoRecord(handle, ANNOTATION, fdoAttributes, localId);
}
- public List prepareDataMappingAttributes(DataMappingRequest request,
- byte[] handle)
+ public FdoRecord prepareUpdatedAnnotationRecord(AnnotationRequest request,
+ Instant timestamp, FdoRecord previousVersion, boolean incrementVersion)
throws InvalidRequestException {
- var fdoRecord = prepareHandleRecordAttributes(request, handle, DATA_MAPPING);
+ var fdoAttributes = prepareUpdatedHandleAttributes(request, previousVersion.handle(),
+ ANNOTATION,
+ timestamp, previousVersion, incrementVersion);
+ fdoAttributes.addAll(prepareAnnotationAttributesFromRequest(request, timestamp));
+ var localId =
+ request.getAnnotationHash() == null ? null : request.getAnnotationHash().toString();
+ return new FdoRecord(previousVersion.handle(), ANNOTATION, fdoAttributes, localId);
+ }
- // 700 Source Data Standard
- fdoRecord.add(
- new HandleAttribute(SOURCE_DATA_STANDARD, handle, request.getSourceDataStandard()));
+ private List prepareAnnotationAttributesFromRequest(
+ AnnotationRequest request,
+ Instant timestamp) {
+ var handleAttributeList = new ArrayList();
+ // 500 Target PID
+ handleAttributeList.add(new FdoAttribute(TARGET_PID, timestamp, request.getTargetPid()));
+ // 501 Target Type
+ handleAttributeList.add(
+ new FdoAttribute(TARGET_TYPE, timestamp, request.getTargetType()));
+ // 502 Motivation
+ handleAttributeList.add(new FdoAttribute(MOTIVATION, timestamp, request.getMotivation()));
+ // 503 Annotation Hash
+ handleAttributeList.add(
+ new FdoAttribute(ANNOTATION_HASH, timestamp, request.getAnnotationHash()));
+ return handleAttributeList;
+ }
- return fdoRecord;
+ /* Data Mapping Record Creation */
+ public FdoRecord prepareNewDataMappingRecord(DataMappingRequest request, String handle,
+ Instant timestamp) throws InvalidRequestException {
+ var fdoAttributes = prepareNewHandleAttributes(request, handle, DATA_MAPPING, timestamp);
+ fdoAttributes.addAll(prepareDataMappingAttributesFromRequest(request, timestamp));
+ return new FdoRecord(handle, DATA_MAPPING, fdoAttributes, null);
}
- public List prepareDigitalSpecimenRecordAttributes(
- DigitalSpecimenRequest request, byte[] handle)
+ public FdoRecord prepareUpdatedDataMappingRecord(DataMappingRequest request,
+ Instant timestamp, FdoRecord previousVersion, boolean incrementVersion)
throws InvalidRequestException {
- var fdoRecord = prepareDoiRecordAttributes(request, handle, DIGITAL_SPECIMEN);
-
- // 200: Specimen Host
- fdoRecord.add(new HandleAttribute(SPECIMEN_HOST, handle, request.getSpecimenHost()));
-
- // 201: Specimen Host name
- var specimenHostName = setHostName(request.getSpecimenHostName(), request.getSpecimenHost(),
- handle, SPECIMEN_HOST_NAME);
- fdoRecord.add(specimenHostName);
-
- // 202: primarySpecimenObjectId
- fdoRecord.add(new HandleAttribute(PRIMARY_SPECIMEN_OBJECT_ID, handle,
- request.getPrimarySpecimenObjectId()));
+ var fdoAttributes = prepareUpdatedHandleAttributes(request, previousVersion.handle(),
+ DATA_MAPPING, timestamp,
+ previousVersion, incrementVersion);
+ fdoAttributes.addAll(prepareDataMappingAttributesFromRequest(request, timestamp));
+ return new FdoRecord(previousVersion.handle(), DATA_MAPPING, fdoAttributes, null);
+ }
- // 203: primarySpecimenObjectIdType
- fdoRecord.add(new HandleAttribute(PRIMARY_SPECIMEN_OBJECT_ID_TYPE, handle,
- request.getPrimarySpecimenObjectIdType().toString()));
+ private List prepareDataMappingAttributesFromRequest(DataMappingRequest request,
+ Instant timestamp) {
+ return List.of(
+ new FdoAttribute(SOURCE_DATA_STANDARD, timestamp, request.getSourceDataStandard()));
+ }
- // 204-217 are optional
+ /* Digital Specimen Record Creation */
+ public FdoRecord prepareNewDigitalSpecimenRecord(DigitalSpecimenRequest request,
+ String handle, Instant timestamp)
+ throws InvalidRequestException, JsonProcessingException {
+ var fdoAttributes = prepareNewDoiAttributes(request, handle, DIGITAL_SPECIMEN, timestamp);
+ fdoAttributes.addAll(prepareDigitalSpecimenAttributesFromRequest(request, timestamp));
+ return new FdoRecord(handle, DIGITAL_SPECIMEN, fdoAttributes,
+ request.getNormalisedPrimarySpecimenObjectId());
+ }
- // 204: primarySpecimenObjectIdName
- if (request.getPrimarySpecimenObjectIdName() != null) {
- fdoRecord.add(new HandleAttribute(PRIMARY_SPECIMEN_OBJECT_ID_NAME, handle,
- request.getPrimarySpecimenObjectIdName()));
- }
+ public FdoRecord prepareUpdatedDigitalSpecimenRecord(
+ DigitalSpecimenRequest request, Instant timestamp, FdoRecord previousVersion,
+ boolean incrementVersion)
+ throws InvalidRequestException, JsonProcessingException {
+ var fdoAttributes = prepareUpdatedDoiAttributes(request, previousVersion.handle(),
+ DIGITAL_SPECIMEN, timestamp, previousVersion, incrementVersion);
+ fdoAttributes.addAll(prepareDigitalSpecimenAttributesFromRequest(request, timestamp));
+ return new FdoRecord(previousVersion.handle(), DIGITAL_SPECIMEN, fdoAttributes,
+ request.getNormalisedPrimarySpecimenObjectId());
+ }
- // 205 normalisedSpecimenObjectId
- fdoRecord.add(new HandleAttribute(NORMALISED_SPECIMEN_OBJECT_ID, handle,
+ private List prepareDigitalSpecimenAttributesFromRequest(
+ DigitalSpecimenRequest request, Instant timestamp)
+ throws InvalidRequestException, JsonProcessingException {
+ var handleAttributeList = new ArrayList();
+ // 200 Specimen Host
+ handleAttributeList.add(
+ new FdoAttribute(SPECIMEN_HOST, timestamp, request.getSpecimenHost()));
+ // 201 Specimen Host Name
+ handleAttributeList.add(new FdoAttribute(SPECIMEN_HOST_NAME, timestamp,
+ getObjectName(request.getSpecimenHost(), request.getSpecimenHostName())));
+ // 202 Primary Specimen Object ID
+ handleAttributeList.add(new FdoAttribute(PRIMARY_SPECIMEN_OBJECT_ID, timestamp,
+ getObjectName(request.getSpecimenHost(), request.getPrimarySpecimenObjectId())));
+ // 203 Primary Specimen Object ID Type
+ handleAttributeList.add(new FdoAttribute(PRIMARY_SPECIMEN_OBJECT_ID_TYPE, timestamp,
+ getObjectName(request.getSpecimenHost(),
+ request.getPrimarySpecimenObjectIdType().toString())));
+ // 204 Primary Specimen Object ID Name
+ handleAttributeList.add(new FdoAttribute(PRIMARY_SPECIMEN_OBJECT_ID_NAME, timestamp,
+ request.getPrimarySpecimenObjectIdName()));
+ // 205 Normalised Specimen Object Id
+ handleAttributeList.add(new FdoAttribute(NORMALISED_SPECIMEN_OBJECT_ID, timestamp,
request.getNormalisedPrimarySpecimenObjectId()));
+ // 206 Specimen Object Id Absence Reason
+ handleAttributeList.add(new FdoAttribute(SPECIMEN_OBJECT_ID_ABSENCE_REASON, timestamp,
+ request.getSpecimenObjectIdAbsenceReason()));
+ // 206 Specimen Object Id Absence Reason
+ handleAttributeList.add(new FdoAttribute(SPECIMEN_OBJECT_ID_ABSENCE_REASON, timestamp,
+ request.getSpecimenObjectIdAbsenceReason()));
+ // 207 Other Specimen Ids
+ if (request.getOtherSpecimenIds() != null && !request.getOtherSpecimenIds().isEmpty()) {
+ handleAttributeList.add(new FdoAttribute(OTHER_SPECIMEN_IDS, timestamp,
+ mapper.writeValueAsString(request.getOtherSpecimenIds())));
+ } else {
+ handleAttributeList.add(new FdoAttribute(OTHER_SPECIMEN_IDS, timestamp,
+ null));
+ }
+ // 208 Topic Origin
+ handleAttributeList.add(new FdoAttribute(TOPIC_ORIGIN, timestamp, request.getTopicOrigin()));
+ // 209 Topic Domain
+ handleAttributeList.add(
+ new FdoAttribute(TOPIC_DOMAIN, timestamp, request.getTopicDomain()));
+ // 210 Topic Discipline
+ handleAttributeList.add(new FdoAttribute(TOPIC_DISCIPLINE, timestamp,
+ request.getTopicDiscipline()));
+ // 211 Topic Category
+ handleAttributeList.add(new FdoAttribute(TOPIC_CATEGORY, timestamp,
+ request.getTopicCategory()));
+ // 212 Living or Preserved
+ handleAttributeList.add(new FdoAttribute(LIVING_OR_PRESERVED, timestamp,
+ request.getLivingOrPreserved()));
+ // 213 Base Type of Specimen
+ handleAttributeList.add(new FdoAttribute(BASE_TYPE_OF_SPECIMEN, timestamp,
+ request.getBaseTypeOfSpecimen()));
+ // 214 Information Artefact Type
+ handleAttributeList.add(new FdoAttribute(INFORMATION_ARTEFACT_TYPE, timestamp,
+ request.getInformationArtefactType()));
+ // 215 Material Sample Type
+ handleAttributeList.add(new FdoAttribute(MATERIAL_SAMPLE_TYPE, timestamp,
+ request.getMaterialSampleType()));
+ // 216 Material or Digital Entity
+ handleAttributeList.add(new FdoAttribute(MATERIAL_OR_DIGITAL_ENTITY, timestamp,
+ request.getMaterialOrDigitalEntity()));
+ // 217 Marked as Type
+ handleAttributeList.add(new FdoAttribute(MARKED_AS_TYPE, timestamp, request.getMarkedAsType()));
+ // 218 Was Derived From Entity
+ handleAttributeList.add(
+ new FdoAttribute(WAS_DERIVED_FROM_ENTITY, timestamp,
+ String.valueOf(request.getDerivedFromEntity() != null)));
+ // 219 Catalog ID
+ handleAttributeList.add(
+ new FdoAttribute(CATALOG_IDENTIFIER, timestamp, request.getCatalogIdentifier()));
+ return handleAttributeList;
+ }
- // 206: specimenObjectIdAbsenceReason
- if (request.getPrimarySpecimenObjectIdAbsenceReason() != null) {
- fdoRecord.add(new HandleAttribute(SPECIMEN_OBJECT_ID_ABSENCE_REASON, handle,
- request.getPrimarySpecimenObjectIdAbsenceReason()));
- }
-
- // 207: otherSpecimenIds
- if (request.getOtherSpecimenIds() != null) {
- try {
- var otherSpecimenIds = mapper.writeValueAsString(request.getOtherSpecimenIds());
- fdoRecord.add(new HandleAttribute(OTHER_SPECIMEN_IDS, handle, otherSpecimenIds));
- } catch (JsonProcessingException e) {
- log.warn("Unable to parse otherSpecimenIds {} to string", request.getOtherSpecimenIds(), e);
- }
- }
-
- // 208: topicOrigin
- if (request.getTopicOrigin() != null) {
- fdoRecord.add(new HandleAttribute(TOPIC_ORIGIN, handle, request.getTopicOrigin().toString()));
- }
-
- // 209: topicDomain
- var topicDomain = request.getTopicDomain();
- if (topicDomain != null) {
- fdoRecord.add(new HandleAttribute(TOPIC_DOMAIN, handle, topicDomain.toString()));
- }
-
- // 210: topicDiscipline
- var topicDisc = request.getTopicDiscipline();
- if (topicDisc != null) {
- fdoRecord.add(new HandleAttribute(TOPIC_DISCIPLINE, handle, topicDisc.toString()));
- }
+ /* MAS Record Creation */
+ public FdoRecord prepareNewMasRecord(MasRequest request, String handle,
+ Instant timestamp)
+ throws InvalidRequestException {
+ var fdoAttributes = prepareNewHandleAttributes(request, handle, MAS, timestamp);
+ fdoAttributes.addAll(prepareMasAttributesFromRequest(request, timestamp));
+ return new FdoRecord(handle, MAS, fdoAttributes, null);
+ }
- // 211 topicCategory
- var topicCategory = request.getTopicCategory();
- if (topicCategory != null) {
- fdoRecord.add(new HandleAttribute(TOPIC_CATEGORY, handle, topicCategory.toString()));
- }
+ public FdoRecord prepareUpdatedMasRecord(MasRequest request,
+ Instant timestamp, FdoRecord previousVersion, boolean incrementVersion)
+ throws InvalidRequestException {
+ var fdoAttributes = prepareUpdatedHandleAttributes(request, previousVersion.handle(), MAS,
+ timestamp,
+ previousVersion, incrementVersion);
+ fdoAttributes.addAll(prepareMasAttributesFromRequest(request, timestamp));
+ return new FdoRecord(previousVersion.handle(), MAS, fdoAttributes, null);
+ }
- // 212: livingOrPreserved
- var livingOrPres = request.getLivingOrPreserved();
- if (livingOrPres != null) {
- fdoRecord.add(new HandleAttribute(LIVING_OR_PRESERVED, handle, livingOrPres.toString()));
- }
+ private List prepareMasAttributesFromRequest(MasRequest request,
+ Instant timestamp) {
+ return List.of(
+ new FdoAttribute(MAS_NAME, timestamp, request.getMachineAnnotationServiceName()));
+ }
- // 213 baseTypeOfSpecimen
- var baseType = request.getBaseTypeOfSpecimen();
- if (baseType != null) {
- fdoRecord.add(new HandleAttribute(BASE_TYPE_OF_SPECIMEN, handle, baseType.toString()));
- }
+ /* Media Object Record Creation */
+ public FdoRecord prepareNewDigitalMediaRecord(DigitalMediaRequest request,
+ String handle, Instant timestamp) throws InvalidRequestException {
+ var fdoAttributes = prepareNewDoiAttributes(request, handle, DIGITAL_MEDIA, timestamp);
+ fdoAttributes.addAll(prepareDigitalMediaAttributesFromRequest(request, timestamp));
+ return new FdoRecord(handle, DIGITAL_MEDIA, fdoAttributes, request.getPrimaryMediaId());
+ }
- // 214: informationArtefactType
- var artType = request.getInformationArtefactType();
- if (artType != null) {
- fdoRecord.add(new HandleAttribute(INFORMATION_ARTEFACT_TYPE, handle, artType.toString()));
- }
+ public FdoRecord prepareUpdatedDigitalMediaRecord(DigitalMediaRequest request,
+ Instant timestamp, FdoRecord previousVersion, boolean incrementVersion)
+ throws InvalidRequestException {
+ var fdoAttributes = prepareUpdatedDoiAttributes(request, previousVersion.handle(),
+ DIGITAL_MEDIA, timestamp,
+ previousVersion, incrementVersion);
+ fdoAttributes.addAll(prepareDigitalMediaAttributesFromRequest(request, timestamp));
+ return new FdoRecord(previousVersion.handle(), DIGITAL_MEDIA, fdoAttributes,
+ request.getPrimaryMediaId());
+ }
- // 215: materialSampleType
- var matSamp = request.getMaterialSampleType();
- if (matSamp != null) {
- fdoRecord.add(new HandleAttribute(MATERIAL_SAMPLE_TYPE, handle, matSamp.toString()));
- }
+ private List prepareDigitalMediaAttributesFromRequest(
+ DigitalMediaRequest request, Instant timestamp)
+ throws InvalidRequestException {
+ var handleAttributeList = new ArrayList();
+ // 400 Media Host
+ handleAttributeList.add(
+ new FdoAttribute(MEDIA_HOST, timestamp, request.getMediaHost()));
+ // 401 MediaHostName
+ handleAttributeList.add(
+ new FdoAttribute(MEDIA_HOST_NAME, timestamp,
+ getObjectName(request.getMediaHost(), request.getMediaHostName())));
+ // 403 Is Derived From Specimen
+ handleAttributeList.add(
+ new FdoAttribute(IS_DERIVED_FROM_SPECIMEN, timestamp,
+ String.valueOf(request.getIsDerivedFromSpecimen())));
+ // 404 Linked Digital Object PID
+ handleAttributeList.add(
+ new FdoAttribute(LINKED_DO_PID, timestamp, request.getLinkedDigitalObjectPid()));
+ // 405 Linked Digital Object Type
+ handleAttributeList.add(
+ new FdoAttribute(LINKED_DO_TYPE, timestamp, request.getLinkedDigitalObjectType()));
+ // 406 Linked Attribute
+ handleAttributeList.add(
+ new FdoAttribute(LINKED_ATTRIBUTE, timestamp, request.getLinkedAttribute()));
+ // 407 Primary Media ID
+ handleAttributeList.add(
+ new FdoAttribute(PRIMARY_MEDIA_ID, timestamp, request.getPrimaryMediaId()));
+ // 408 Primary Media Object Id Type
+ handleAttributeList.add(
+ new FdoAttribute(PRIMARY_MO_ID_TYPE, timestamp,
+ request.getPrimaryMediaObjectIdType()));
+ // 409 Primary Media Object Id Name
+ handleAttributeList.add(
+ new FdoAttribute(PRIMARY_MO_ID_NAME, timestamp,
+ request.getPrimaryMediaObjectIdName()));
+ // 410 dcterms:type
+ handleAttributeList.add(
+ new FdoAttribute(DCTERMS_TYPE, timestamp, request.getDcTermsType()));
+ // 411 dcterms:subject
+ handleAttributeList.add(
+ new FdoAttribute(DCTERMS_SUBJECT, timestamp, request.getDctermsSubject()));
+ // 412 dcterms:format
+ handleAttributeList.add(
+ new FdoAttribute(DCTERMS_FORMAT, timestamp,
+ request.getDctermsFormat()));
+ // 413 Derived from Entity
+ handleAttributeList.add(
+ new FdoAttribute(DERIVED_FROM_ENTITY, timestamp, request.getDerivedFromEntity()));
+ // 414 License Name
+ handleAttributeList.add(
+ new FdoAttribute(LICENSE_NAME, timestamp, request.getLicenseName()));
+ // 415 License URL
+ handleAttributeList.add(new FdoAttribute(LICENSE_URL, timestamp, request.getLicenseName()));
+ // 416 RightsholderName
+ handleAttributeList.add(
+ new FdoAttribute(RIGHTSHOLDER_NAME, timestamp, request.getRightsholderName()));
+ // 417 Rightsholder PID
+ handleAttributeList.add(
+ new FdoAttribute(RIGHTSHOLDER_PID, timestamp, request.getRightsholderPid()));
+ // 418 RightsholderPidType
+ handleAttributeList.add(new FdoAttribute(RIGHTSHOLDER_PID_TYPE, timestamp,
+ request.getRightsholderPidType()));
+ // 419 dcterms:conformsTo
+ handleAttributeList.add(
+ new FdoAttribute(DC_TERMS_CONFORMS, timestamp, request.getDctermsConformsTo()));
+ return handleAttributeList;
+ }
- // 216: materialOrDigitalEntity
- if (request.getMaterialOrDigitalEntity() != null) {
- fdoRecord.add(new HandleAttribute(MATERIAL_OR_DIGITAL_ENTITY, handle,
- request.getMaterialOrDigitalEntity().toString()));
- }
+ /* Organisation Record Creation */
+ public FdoRecord prepareNewOrganisationRecord(OrganisationRequest request, String handle,
+ Instant timestamp) throws InvalidRequestException {
+ var fdoAttributes = prepareNewDoiAttributes(request, handle, ORGANISATION, timestamp);
+ fdoAttributes.addAll(prepareOrganisationAttributesFromRequest(request, handle, timestamp));
+ return new FdoRecord(handle, ORGANISATION, fdoAttributes, null);
+ }
- // 217: markedAsType
- var markedAsType = request.getMarkedAsType();
- if (markedAsType != null) {
- fdoRecord.add(new HandleAttribute(MARKED_AS_TYPE, handle, markedAsType.toString()));
- }
+ public FdoRecord prepareUpdatedOrganisationRecord(OrganisationRequest request,
+ Instant timestamp, FdoRecord previousVersion, boolean incrementVersion)
+ throws InvalidRequestException {
+ var fdoAttributes = prepareUpdatedDoiAttributes(request, previousVersion.handle(),
+ ORGANISATION, timestamp, previousVersion, incrementVersion);
+ fdoAttributes.addAll(
+ prepareOrganisationAttributesFromRequest(request, previousVersion.handle(), timestamp));
+ return new FdoRecord(previousVersion.handle(), ORGANISATION, fdoAttributes, null);
+ }
- // 218: wasDerivedFromEntity
- var wasDerivedFrom = request.getDerivedFromEntity();
- if (wasDerivedFrom != null) {
- fdoRecord.add(new HandleAttribute(WAS_DERIVED_FROM_ENTITY, handle, wasDerivedFrom));
- }
+ private List prepareOrganisationAttributesFromRequest(
+ OrganisationRequest request,
+ String handle,
+ Instant timestamp) throws InvalidRequestException {
+ var handleAttributeList = new ArrayList();
+ // 101 10320/loc -> includes organisation ROR
+ var userLocations = concatLocations(request.getLocations(),
+ List.of(request.getOrganisationIdentifier()));
+ handleAttributeList.add(
+ new FdoAttribute(LOC, timestamp, setLocations(userLocations, handle, ORGANISATION)));
+ // 601 Organisation Identifier
+ handleAttributeList.add(
+ new FdoAttribute(ORGANISATION_ID, timestamp, request.getOrganisationIdentifier()));
+ // 602 Organisation Identifier type
+ handleAttributeList.add(new FdoAttribute(ORGANISATION_ID_TYPE, timestamp,
+ request.getOrganisationIdentifierType()));
+ // 603 Organisation Name
+ handleAttributeList.add(new FdoAttribute(ORGANISATION_NAME, timestamp,
+ getObjectName(request.getOrganisationIdentifier(), null)));
+ return handleAttributeList;
+ }
- // 219 catalogId
- var catId = request.getCatalogIdentifier();
- if (catId != null) {
- fdoRecord.add(new HandleAttribute(CATALOG_IDENTIFIER, handle, catId));
- }
+ /* Source System Record Creation */
+ public FdoRecord prepareNewSourceSystemRecord(SourceSystemRequest request, String handle,
+ Instant timestamp) throws InvalidRequestException {
+ var fdoAttributes = prepareNewHandleAttributes(request, handle, SOURCE_SYSTEM, timestamp);
+ fdoAttributes.addAll(prepareSourceSystemAttributesFromRequest(request, timestamp));
+ return new FdoRecord(handle, SOURCE_SYSTEM, fdoAttributes, null);
+ }
- return fdoRecord;
+ public FdoRecord prepareUpdatedSourceSystemRecord(SourceSystemRequest request, Instant timestamp,
+ FdoRecord previousVersion, boolean incrementVersion) throws InvalidRequestException {
+ var fdoAttributes = prepareUpdatedHandleAttributes(request, previousVersion.handle(),
+ SOURCE_SYSTEM,
+ timestamp, previousVersion, incrementVersion);
+ fdoAttributes.addAll(prepareSourceSystemAttributesFromRequest(request, timestamp));
+ return new FdoRecord(previousVersion.handle(), SOURCE_SYSTEM, fdoAttributes, null);
}
- private HandleAttribute setHostName(String hostName, String hostId, byte[] handle,
- FdoProfile targetAttribute) throws PidResolutionException {
- if (hostName != null) {
- return new HandleAttribute(targetAttribute, handle, hostName);
- } else {
- String hostNameResolved;
- if (hostId.contains(ROR_DOMAIN)) {
- hostNameResolved = pidResolver.getObjectName(hostId.replace(ROR_DOMAIN, ROR_API_DOMAIN));
- return new HandleAttribute(targetAttribute, handle, hostNameResolved);
- } else if (hostId.contains(WIKIDATA_DOMAIN)) {
- hostNameResolved = pidResolver.resolveQid(hostId.replace(WIKIDATA_DOMAIN, WIKIDATA_API));
- } else {
- log.error("Specimen host ID {} is neither QID nor ROR.", hostId);
- throw new PidResolutionException("Invalid host id: " + hostId);
- }
- return new HandleAttribute(targetAttribute, handle, hostNameResolved);
- }
+ /* Tombstone Record Creation */
+ public FdoRecord prepareTombstoneRecord(TombstoneRecordRequest recordRequest, Instant timestamp,
+ FdoRecord previousVersion) throws JsonProcessingException {
+ var fdoAttributes = prepareTombstoneAttributes(recordRequest, timestamp, previousVersion);
+ return new FdoRecord(previousVersion.handle(), previousVersion.fdoType(), fdoAttributes, null);
}
- public List prepareUpdateAttributes(byte[] handle, JsonNode requestAttributes,
- FdoType type) throws InvalidRequestException {
- requestAttributes = setLocationXmlFromJson(requestAttributes,
- new String(handle, StandardCharsets.UTF_8), type);
- Map updateRequestMap = mapper.convertValue(requestAttributes,
- new TypeReference