partial refactoring

This commit is contained in:
Michele Artini 2024-11-07 10:21:51 +01:00
parent a125798e1a
commit 6fc507f056
11 changed files with 171 additions and 282 deletions

View File

@ -1,2 +1,6 @@
# dnet-directindex-application
### SWORD Deposit Protocol v.3
* *[Main site](https://sword.cottagelabs.com/swordv3/)*
* *[Protocol Specification](https://swordapp.github.io/swordv3/swordv3.html)*
* *[Protocol Behaviours](https://swordapp.github.io/swordv3/swordv3-behaviours.html)*

View File

@ -2,6 +2,8 @@ package eu.dnetlib.app.directindex.service;
import org.springframework.stereotype.Service;
import eu.dnetlib.app.directindex.sword.model.SwordMetadataDocument;
@Service
public class DirectIndexService {
@ -15,4 +17,9 @@ public class DirectIndexService {
}
public void prepareMetadataInsertion(final SwordMetadataDocument body) {
// TODO Auto-generated method stub
}
}

View File

@ -0,0 +1,23 @@
package eu.dnetlib.app.directindex.sword;
public class SwordException extends Exception {
private static final long serialVersionUID = -6401402258941503950L;
private final int httpCode;
private final String httpMessage;
public SwordException(final int httpCode, final String httpMessage) {
this.httpCode = httpCode;
this.httpMessage = httpMessage;
}
public int getHttpCode() {
return httpCode;
}
public String getHttpMessage() {
return httpMessage;
}
}

View File

@ -1,34 +0,0 @@
package eu.dnetlib.app.directindex.sword;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
@RestController("/api/directindex/file")
public class SwordFileSetUrlController {
@PutMapping("/")
public @ResponseBody Object replaceFileSet(
@RequestHeader("Authorization") final String authorization,
@RequestHeader("Content-Disposition") final String contentDisposition,
@RequestHeader("Content-Length") final String contentLength,
@RequestHeader("Content-Type") final String contentType,
@RequestHeader("Digest") final String digest,
@RequestHeader("If-Match") final boolean ifMatch,
@RequestHeader("On-Behalf-Of") final String onBehalfOf,
@RequestHeader(value = "Packaging", defaultValue = "http://purl.org/net/sword/3.0/package/Binary") final String packaging) {
// TODO
return null;
}
@DeleteMapping("/")
public @ResponseBody Object deleteFileSet(
@RequestHeader("Authorization") final String authorization,
@RequestHeader("If-Match") final boolean ifMatch,
@RequestHeader("On-Behalf-Of") final String onBehalfOf) {
// TODO
return null;
}
}

View File

@ -1,43 +0,0 @@
package eu.dnetlib.app.directindex.sword;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
@RestController("/api/directindex/files")
public class SwordFileUrlController {
@GetMapping("/")
public @ResponseBody Object getFile(
@RequestHeader("Authorization") final String authorization,
@RequestHeader("On-Behalf-Of") final String onBehalfOf) {
// TODO
return null;
}
@PutMapping("/")
public @ResponseBody Object replaceFile(
@RequestHeader("Authorization") final String authorization,
@RequestHeader("Content-Disposition") final String contentDisposition,
@RequestHeader("Content-Length") final String contentLength,
@RequestHeader("Content-Type") final String contentType,
@RequestHeader("Digest") final String digest,
@RequestHeader("If-Match") final boolean ifMatch,
@RequestHeader("On-Behalf-Of") final String onBehalfOf) {
// TODO
return null;
}
@DeleteMapping("/")
public @ResponseBody Object deleteFile(
@RequestHeader("Authorization") final String authorization,
@RequestHeader("If-Match") final boolean ifMatch,
@RequestHeader("On-Behalf-Of") final String onBehalfOf) {
// TODO
return null;
}
}

View File

@ -1,69 +0,0 @@
package eu.dnetlib.app.directindex.sword;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RestController;
import eu.dnetlib.app.directindex.service.DirectIndexService;
import eu.dnetlib.app.directindex.sword.model.SwordMetadataDocument;
@RestController("/api/directindex/metadata")
public class SwordMetadataUrlController {
@Autowired
private DirectIndexService service;
@GetMapping("/")
public ResponseEntity<SwordMetadataDocument> getMetadata(
@RequestHeader("Authorization") final String authorization,
@RequestHeader("On-Behalf-Of") final String onBehalfOf) {
// TODO
final SwordMetadataDocument metadata = null;
final HttpHeaders responseHeaders = new HttpHeaders();
responseHeaders.set("ETag", null);
return new ResponseEntity<>(metadata, responseHeaders, HttpStatus.OK);
}
@PutMapping("/")
public ResponseEntity<Void> replaceMetadata(@RequestHeader("Authorization") final String authorization,
@RequestHeader("Content-Disposition") final String contentDisposition,
@RequestHeader("Content-Length") final String contentLength,
@RequestHeader("Content-Type") final String contentType,
@RequestHeader("Digest") final String digest,
@RequestHeader("If-Match") final boolean ifMatch,
@RequestHeader("On-Behalf-Of") final String onBehalfOf,
@RequestHeader(value = "Metadata-Format", defaultValue = "http://purl.org/net/sword/3.0/types/Metadata") final String mdFormat,
@RequestBody final SwordMetadataDocument document) {
service.prepareMetadataReplacement();
// TODO
final HttpHeaders responseHeaders = new HttpHeaders();
responseHeaders.set("ETag", null);
return new ResponseEntity<>(responseHeaders, HttpStatus.NO_CONTENT);
}
@DeleteMapping("/")
public ResponseEntity<Void> deleteMetadata(
@RequestHeader("Authorization") final String authorization,
@RequestHeader("If-Match") final boolean ifMatch,
@RequestHeader("On-Behalf-Of") final String onBehalfOf) {
service.prepareMetadataDeletion();
return new ResponseEntity<>(HttpStatus.ACCEPTED);
}
}

View File

@ -1,62 +0,0 @@
package eu.dnetlib.app.directindex.sword;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
@RestController("/api/directindex/obj")
public class SwordObjectUrlController {
@GetMapping("/")
public @ResponseBody Object getObjectStatus(
@RequestHeader("Authorization") final String authorization,
@RequestHeader("On-Behalf-Of") final String onBehalfOf) {
// TODO
return null;
}
@PostMapping("/")
public @ResponseBody Object appendObjectData(
@RequestHeader("Authorization") final String authorization,
@RequestHeader("Content-Disposition") final String contentDisposition,
@RequestHeader("Content-Length") final String contentLength,
@RequestHeader("Content-Type") final String contentType,
@RequestHeader("Digest") final String digest,
@RequestHeader("If-Match") final boolean ifMatch,
@RequestHeader(value = "In-Progress", defaultValue = "false") final boolean inProgress,
@RequestHeader("On-Behalf-Of") final String onBehalfOf,
@RequestHeader(value = "Packaging", defaultValue = "http://purl.org/net/sword/3.0/package/Binary") final String packaging,
@RequestHeader(value = "Metadata-Format", defaultValue = "http://purl.org/net/sword/3.0/types/Metadata") final String mdFormat) {
// TODO
return null;
}
@PutMapping("/")
public @ResponseBody Object replaceObject(
@RequestHeader("Authorization") final String authorization,
@RequestHeader("Content-Disposition") final String contentDisposition,
@RequestHeader("Content-Length") final String contentLength,
@RequestHeader("Content-Type") final String contentType,
@RequestHeader("Digest") final String digest,
@RequestHeader("If-Match") final boolean ifMatch,
@RequestHeader(value = "In-Progress", defaultValue = "false") final boolean inProgress,
@RequestHeader("On-Behalf-Of") final String onBehalfOf,
@RequestHeader(value = "Packaging", defaultValue = "http://purl.org/net/sword/3.0/package/Binary") final String packaging,
@RequestHeader(value = "Metadata-Format", defaultValue = "http://purl.org/net/sword/3.0/types/Metadata") final String mdFormat) {
// TODO
return null;
}
@DeleteMapping("/")
public @ResponseBody Object deleteObject(
@RequestHeader("Authorization") final String authorization,
@RequestHeader("If-Match") final boolean ifMatch,
@RequestHeader("On-Behalf-Of") final String onBehalfOf) {
// TODO
return null;
}
}

View File

@ -1,44 +1,62 @@
package eu.dnetlib.app.directindex.sword;
import java.io.IOException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RestController;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import eu.dnetlib.app.directindex.service.DirectIndexService;
import eu.dnetlib.app.directindex.sword.model.SwordError;
import eu.dnetlib.app.directindex.sword.model.SwordMetadataDocument;
import eu.dnetlib.app.directindex.sword.model.SwordService;
import eu.dnetlib.app.directindex.sword.model.SwordStatusDocument;
import jakarta.servlet.http.HttpServletResponse;
@RestController("/api/directindex/")
@RestController("/api/directindex/sword/3.0")
public class SwordServiceUrlController {
@Autowired
private DirectIndexService service;
@GetMapping("/")
public SwordService getServiceDocument(
@RequestHeader("Authorization") final String authorization,
@RequestHeader("On-Behalf-Of") final String onBehalfOf) {
public SwordService getServiceDocument() {
// TODO
return null;
}
@PostMapping("/")
public ResponseEntity<SwordStatusDocument> makeNewObject(
@RequestHeader("Authorization") final String authorization,
@RequestHeader("Content-Disposition") final String contentDisposition,
@RequestHeader("Content-Length") final String contentLength,
public ResponseEntity<SwordStatusDocument> addMetadata(
@RequestHeader("Content-Type") final String contentType,
@RequestHeader("Content-Disposition") final String contentDisposition,
@RequestHeader("Digest") final String digest,
@RequestHeader(value = "In-Progress", defaultValue = "false") final boolean inProgress,
@RequestHeader(value = "Metadata-Format", defaultValue = "http://purl.org/net/sword/3.0/types/Metadata") final String mdFormat,
@RequestHeader("On-Behalf-Of") final String onBehalfOf,
@RequestHeader(value = "Packaging", defaultValue = "http://purl.org/net/sword/3.0/package/Binary") final String packaging,
@RequestHeader("Slug") final String slug,
@RequestBody final String json) {
// Content used to create new Object. This can be one of: Metadata, By-Reference, Metadata+By-Reference, Binary File, Packaged
// Content, Empty Body
@RequestBody final Object content) {
// TODO: DIGEST Evaluate if the digest (md5) of the json string
if (!MediaType.APPLICATION_JSON_VALUE.equals(contentType)) { return new ResponseEntity<>(HttpStatus.UNSUPPORTED_MEDIA_TYPE); }
if (!"attachment; metadata=true".equals(contentDisposition) || inProgress) { return new ResponseEntity<>(HttpStatus.METHOD_NOT_ALLOWED); }
if (!"OAF".equals(mdFormat)) { return new ResponseEntity<>(HttpStatus.UNSUPPORTED_MEDIA_TYPE); }
// TODO
final SwordStatusDocument status = null;
@ -47,12 +65,75 @@ public class SwordServiceUrlController {
responseHeaders.setLocation(null);
responseHeaders.set("ETag", null);
return new ResponseEntity<>(status, responseHeaders, isCreated() ? HttpStatus.CREATED : HttpStatus.ACCEPTED);
try {
service.prepareMetadataInsertion(parseMetadata(json));
} catch (final JsonProcessingException e) {
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
}
return new ResponseEntity<>(status, responseHeaders, HttpStatus.ACCEPTED);
}
private boolean isCreated() {
// TODO Auto-generated method stub
return false;
@GetMapping("/metadata")
public ResponseEntity<SwordMetadataDocument> getMetadata() {
// TODO
final SwordMetadataDocument metadata = null;
final HttpHeaders responseHeaders = new HttpHeaders();
responseHeaders.set("ETag", null);
return new ResponseEntity<>(metadata, responseHeaders, HttpStatus.OK);
}
@PutMapping("/metadata")
public ResponseEntity<Void> replaceMetadata(
@RequestHeader("Content-Disposition") final String contentDisposition,
@RequestHeader("Content-Length") final String contentLength,
@RequestHeader("Content-Type") final String contentType,
@RequestHeader("Digest") final String digest,
@RequestHeader("If-Match") final boolean ifMatch,
@RequestHeader(value = "Metadata-Format", defaultValue = "http://purl.org/net/sword/3.0/types/Metadata") final String mdFormat,
@RequestBody final SwordMetadataDocument document) {
service.prepareMetadataReplacement();
// TODO
final HttpHeaders responseHeaders = new HttpHeaders();
responseHeaders.set("ETag", null);
return new ResponseEntity<>(responseHeaders, HttpStatus.NO_CONTENT);
}
@DeleteMapping("/metadata")
public ResponseEntity<Void> deleteMetadata(
@RequestHeader("Authorization") final String authorization,
@RequestHeader("If-Match") final boolean ifMatch,
@RequestHeader("On-Behalf-Of") final String onBehalfOf) {
service.prepareMetadataDeletion();
return new ResponseEntity<>(HttpStatus.ACCEPTED);
}
private SwordMetadataDocument parseMetadata(final String json) throws JsonProcessingException, JsonMappingException {
return new ObjectMapper().readValue(json, SwordMetadataDocument.class);
}
@ExceptionHandler(Throwable.class)
public SwordError handleException(final HttpServletResponse req, final HttpServletResponse res, final Throwable e) throws IOException {
if (e instanceof SwordException) {
final SwordException swe = (SwordException) e;
res.sendError(swe.getHttpCode(), swe.getHttpMessage());
} else {
res.sendError(HttpStatus.INTERNAL_SERVER_ERROR.value());
}
return new SwordError(req, e);
}
}

View File

@ -1,58 +0,0 @@
package eu.dnetlib.app.directindex.sword;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
@RestController("/api/directindex/staging")
public class SwordTemporaryUrlController {
@Value("${dnet.directindex.baseurl}")
public String baseUrl;
@PostMapping("/")
// Create a Temporary-URL for Segmented File Upload
public @ResponseBody Object createTempUrl(
@RequestHeader("Authorization") final String authorization,
@RequestHeader("Content-Disposition") final String contentDisposition,
@RequestHeader("On-Behalf-Of") final String onBehalfOf) {
// TODO
return null;
}
@GetMapping("/{tempfile}")
public @ResponseBody Object getUploadInfo(
@RequestHeader("Authorization") final String authorization,
@RequestHeader("On-Behalf-Of") final String onBehalfOf,
@PathVariable final String tempfile) {
// TODO
return null;
}
@PostMapping("/{tempfile}")
public @ResponseBody Object uploadSegment(
@RequestHeader("Authorization") final String authorization,
@RequestHeader("Content-Disposition") final String contentDisposition,
@RequestHeader("Content-Length") final String contentLength,
@RequestHeader("Digest") final String digest,
@RequestHeader("On-Behalf-Of") final String onBehalfOf,
@PathVariable final String tempfile) {
// TODO
return null;
}
@DeleteMapping("/{tempfile}")
public @ResponseBody Object abortUplodad(
@RequestHeader("Authorization") final String authorization,
@RequestHeader("On-Behalf-Of") final String onBehalfOf,
@PathVariable final String tempfile) {
// TODO
return null;
}
}

View File

@ -0,0 +1,24 @@
package eu.dnetlib.app.directindex.sword.model;
import jakarta.servlet.http.HttpServletResponse;
public class SwordError {
public SwordError(final HttpServletResponse req, final Throwable e) {
// TODO Auto-generated constructor stub
}
// @formatter:off
/*
{
"@context" : "https://swordapp.github.io/swordv3/swordv3.jsonld",
"@type" : "BadRequest",
"timestamp" : "[timestamp]",
"error" : "error summary",
"log" : "text log of any debug information for the client"
}
*/
}

View File

@ -0,0 +1,16 @@
package eu.dnetlib.app.directindex.sword;
import static org.junit.jupiter.api.Assertions.assertTrue;
import org.junit.jupiter.api.Test;
import org.springframework.http.ContentDisposition;
class CommonTest {
@Test
public void testContentDisposition() {
final ContentDisposition cd = ContentDisposition.parse("attachment; metadata=true");
assertTrue(cd.isAttachment());
}
}