From 44b7be3ba6ff89a5ae14bf86b548b354f3800529 Mon Sep 17 00:00:00 2001 From: "michele.artini" Date: Thu, 7 Nov 2024 14:10:35 +0100 Subject: [PATCH] error management --- .../app/directindex/sword/SwordException.java | 19 +++--- .../sword/SwordServiceUrlController.java | 19 +++--- .../directindex/sword/model/SwordError.java | 67 ++++++++++++++++++- .../sword/model/SwordErrorType.java | 46 +++++++++++++ 4 files changed, 128 insertions(+), 23 deletions(-) create mode 100644 src/main/java/eu/dnetlib/app/directindex/sword/model/SwordErrorType.java diff --git a/src/main/java/eu/dnetlib/app/directindex/sword/SwordException.java b/src/main/java/eu/dnetlib/app/directindex/sword/SwordException.java index 5a89415..b821085 100644 --- a/src/main/java/eu/dnetlib/app/directindex/sword/SwordException.java +++ b/src/main/java/eu/dnetlib/app/directindex/sword/SwordException.java @@ -1,23 +1,20 @@ package eu.dnetlib.app.directindex.sword; +import eu.dnetlib.app.directindex.sword.model.SwordErrorType; + public class SwordException extends Exception { private static final long serialVersionUID = -6401402258941503950L; - private final int httpCode; - private final String httpMessage; + private final SwordErrorType error; - public SwordException(final int httpCode, final String httpMessage) { - this.httpCode = httpCode; - this.httpMessage = httpMessage; + public SwordErrorType getError() { + return error; } - public int getHttpCode() { - return httpCode; - } - - public String getHttpMessage() { - return httpMessage; + public SwordException(final SwordErrorType error) { + super(); + this.error = error; } } diff --git a/src/main/java/eu/dnetlib/app/directindex/sword/SwordServiceUrlController.java b/src/main/java/eu/dnetlib/app/directindex/sword/SwordServiceUrlController.java index e85797d..76ba590 100644 --- a/src/main/java/eu/dnetlib/app/directindex/sword/SwordServiceUrlController.java +++ b/src/main/java/eu/dnetlib/app/directindex/sword/SwordServiceUrlController.java @@ -22,9 +22,11 @@ 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.SwordErrorType; 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.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; @RestController("/api/directindex/sword/3.0") @@ -48,15 +50,15 @@ public class SwordServiceUrlController { @RequestHeader(value = "Metadata-Format", defaultValue = "http://purl.org/net/sword/3.0/types/Metadata") final String mdFormat, @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) { + @RequestBody final String json) throws SwordException { // 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 (!MediaType.APPLICATION_JSON_VALUE.equals(contentType)) { throw new SwordException(SwordErrorType.ContentTypeNotAcceptable); } - if (!"attachment; metadata=true".equals(contentDisposition) || inProgress) { return new ResponseEntity<>(HttpStatus.METHOD_NOT_ALLOWED); } + if (!"attachment; metadata=true".equals(contentDisposition) || inProgress) { throw new SwordException(SwordErrorType.MethodNotAllowed); } - if (!"OAF".equals(mdFormat)) { return new ResponseEntity<>(HttpStatus.UNSUPPORTED_MEDIA_TYPE); } + if (!"OAF".equals(mdFormat)) { throw new SwordException(SwordErrorType.MetadataFormatNotAcceptable); } // TODO final SwordStatusDocument status = null; @@ -68,7 +70,7 @@ public class SwordServiceUrlController { try { service.prepareMetadataInsertion(parseMetadata(json)); } catch (final JsonProcessingException e) { - return new ResponseEntity<>(HttpStatus.BAD_REQUEST); + throw new SwordException(SwordErrorType.ContentMalformed); } return new ResponseEntity<>(status, responseHeaders, HttpStatus.ACCEPTED); @@ -124,13 +126,12 @@ public class SwordServiceUrlController { } @ExceptionHandler(Throwable.class) - public SwordError handleException(final HttpServletResponse req, final HttpServletResponse res, final Throwable e) throws IOException { + public SwordError handleException(final HttpServletRequest req, final HttpServletResponse res, final Throwable e) throws IOException { if (e instanceof SwordException) { - final SwordException swe = (SwordException) e; - res.sendError(swe.getHttpCode(), swe.getHttpMessage()); + res.setStatus(((SwordException) e).getError().getHttpCode()); } else { - res.sendError(HttpStatus.INTERNAL_SERVER_ERROR.value()); + res.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value()); } return new SwordError(req, e); diff --git a/src/main/java/eu/dnetlib/app/directindex/sword/model/SwordError.java b/src/main/java/eu/dnetlib/app/directindex/sword/model/SwordError.java index c7c3096..bb21e4a 100644 --- a/src/main/java/eu/dnetlib/app/directindex/sword/model/SwordError.java +++ b/src/main/java/eu/dnetlib/app/directindex/sword/model/SwordError.java @@ -1,11 +1,72 @@ package eu.dnetlib.app.directindex.sword.model; -import jakarta.servlet.http.HttpServletResponse; +import java.net.MalformedURLException; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.time.LocalDateTime; + +import org.apache.commons.lang3.exception.ExceptionUtils; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import eu.dnetlib.app.directindex.sword.SwordException; +import jakarta.servlet.http.HttpServletRequest; public class SwordError { - public SwordError(final HttpServletResponse req, final Throwable e) { - // TODO Auto-generated constructor stub + @JsonProperty("@context") + private final URL context; + + @JsonProperty("@type") + private final SwordErrorType type; + + private final LocalDateTime timestamp; + + private final String error; + + private final String log; + + public SwordError(final HttpServletRequest req, final Throwable e) { + + try { + // TODO + context = new URI("http://").toURL(); + } catch (final MalformedURLException | URISyntaxException e1) { + throw new RuntimeException("Invalid URL"); + } + + if (e instanceof SwordException) { + type = ((SwordException) e).getError(); + error = ((SwordException) e).getMessage(); + } else { + type = SwordErrorType.BadRequest; + error = e.getMessage(); + } + + timestamp = LocalDateTime.now(); + log = ExceptionUtils.getStackTrace(e); + + } + + public URL getContext() { + return context; + } + + public SwordErrorType getType() { + return type; + } + + public LocalDateTime getTimestamp() { + return timestamp; + } + + public String getError() { + return error; + } + + public String getLog() { + return log; } // @formatter:off diff --git a/src/main/java/eu/dnetlib/app/directindex/sword/model/SwordErrorType.java b/src/main/java/eu/dnetlib/app/directindex/sword/model/SwordErrorType.java new file mode 100644 index 0000000..0a09947 --- /dev/null +++ b/src/main/java/eu/dnetlib/app/directindex/sword/model/SwordErrorType.java @@ -0,0 +1,46 @@ +package eu.dnetlib.app.directindex.sword.model; + +public enum SwordErrorType { + + // @formatter:off + AuthenticationFailed(403, "The request supplied invalid credentials"), + AuthenticationRequired(401, "The request supplied no credentials, when the server was expecting to authenticate the request."), + BadRequest(400, "The request did not meet the standard specified by the SWORD protocol. This error can be used when no other error is appropriate"), + ByReferenceFileSizeExceeded(400, "The client supplied a By-Reference deposit file, which specified a file size which exceeded the server's limit"), + ByReferenceNotAllowed(412, "The client attempted to carry out a By-Reference deposit on a server which does not support it"), + ContentMalformed(400, "The body content of the request was malformed in some way, such that the server cannot read it correctly."), + ContentTypeNotAcceptable(415 , "The Content-Type header specifies a content type of the request which is in a format that the server cannot accept."), + DigestMismatch(412 , "One or more of the Digests that the server checked did not match the deposited content"), + ETagNotMatched(412 , "The client supplied an If-Match header which did not match the current ETag for the resource being updated."), + ETagRequired(412 , "The client did not supply an If-Match header, when one was required by the server"), + Forbidden(403 , "The client requested an operation that is not permitted by the server in this context."), + FormatHeaderMismatch(415 , "The Metadata-Format or Packaging header does not match what the server found when looking at the Metadata or Packaged Content supplied in a request."), + InvalidSegmentSize(400 , "The client sent a segment that was not the final segment, and was not the size that it indicated segments would be, or during segmented upload initialisation, the client specified a segment size which was not between minSegmentSize and maxSegmentSize."), + MaxAssembledSizeExceeded(400 , "During a segmented upload initialisation, the client specified a total file size which is larger than the maximum assembled file size supported by the server"), + MaxUploadSizeExceeded(413 , "The request supplied body content which is larger than that supported by the server."), + MetadataFormatNotAcceptable(415 , "The Metadata-Format header specifies a metadata format for the request which is in a format that the server cannot accept"), + MethodNotAllowed(405 , "The request is for a method on a resource that is not permitted. This may be permanent, temporary, and may depend on the client’s credentials"), + OnBehalfOfNotAllowed(412 , "The request contained an On-Behalf-Of header, although the server indicates that it does not support this."), + PackagingFormatNotAcceptable(415 , "The Packaging header specifies a packaging format for the request which is in a format that the server cannot accept"), + SegmentedUploadTimedOut(410 , "The client's segmented upload URL has timed out. Servers MAY respond to this with a 404 and no explanation also."), + SegmentLimitExceeded(400 , "During a segmented upload initialisation, the client specified a total number of intended segments which is larger than the limit specified by the server"), + UnexpectedSegment(400 , "The client sent a segment that the server was not expecting; in particular the server may have recieved all the segments it was expecting, and this is an extra one"); + // @formatter:on + + private final int httpCode; + private final String message; + + private SwordErrorType(final int httpCode, final String message) { + this.httpCode = httpCode; + this.message = message; + } + + public int getHttpCode() { + return httpCode; + } + + public String getMessage() { + return message; + } + +}