Skip to content

Commit

Permalink
Merge branch 'refs/heads/development' into lukaskabc/Refactoring-296
Browse files Browse the repository at this point in the history
# Conflicts:
#	src/main/java/cz/cvut/kbss/termit/service/repository/BaseRepositoryService.java
#	src/main/java/cz/cvut/kbss/termit/util/ExceptionUtils.java
  • Loading branch information
lukaskabc committed Sep 23, 2024
2 parents 7db4e19 + 1526072 commit a68b74d
Show file tree
Hide file tree
Showing 6 changed files with 69 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,8 @@ public class InvalidIdentifierException extends TermItException {
public InvalidIdentifierException(String message, String messageId) {
super(message, messageId);
}

public InvalidIdentifierException(String message, Throwable cause, String messageId) {
super(message, cause, messageId);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
import cz.cvut.kbss.termit.exception.WebServiceIntegrationException;
import cz.cvut.kbss.termit.exception.importing.UnsupportedImportMediaTypeException;
import cz.cvut.kbss.termit.exception.importing.VocabularyImportException;
import cz.cvut.kbss.termit.util.ExceptionUtils;
import jakarta.servlet.http.HttpServletRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand All @@ -52,7 +53,10 @@
import org.springframework.web.context.request.async.AsyncRequestNotUsableException;
import org.springframework.web.multipart.MaxUploadSizeExceededException;

import static cz.cvut.kbss.termit.util.ExceptionUtils.isCausedBy;
import java.net.URISyntaxException;
import java.util.Optional;

import static cz.cvut.kbss.termit.util.ExceptionUtils.findCause;

/**
* Exception handlers for REST controllers.
Expand Down Expand Up @@ -85,7 +89,7 @@ private static void logException(Throwable ex, HttpServletRequest request) {

private static void logException(String message, Throwable ex) {
// Prevents exceptions caused by broken connection with a client from logging
if (!isCausedBy(ex, AsyncRequestNotUsableException.class)) {
if (findCause(ex, AsyncRequestNotUsableException.class).isEmpty()) {
LOG.error(message, ex);
}
}
Expand Down Expand Up @@ -175,6 +179,10 @@ public ResponseEntity<ErrorInfo> termItException(HttpServletRequest request, Ter
@ExceptionHandler(JsonLdException.class)
public ResponseEntity<ErrorInfo> jsonLdException(HttpServletRequest request, JsonLdException e) {
logException(e, request);
Optional<URISyntaxException> uriSyntaxException = ExceptionUtils.findCause(e, URISyntaxException.class);
if (uriSyntaxException.isPresent()) {
return uriSyntaxException(request, uriSyntaxException.get());
}
return new ResponseEntity<>(
ErrorInfo.createWithMessage("Error when processing JSON-LD.", request.getRequestURI()),
HttpStatus.INTERNAL_SERVER_ERROR);
Expand Down Expand Up @@ -268,4 +276,18 @@ public ResponseEntity<ErrorInfo> invalidIdentifierException(HttpServletRequest r
logException(e, request);
return new ResponseEntity<>(errorInfo(request, e), HttpStatus.CONFLICT);
}

@ExceptionHandler
public ResponseEntity<ErrorInfo> uriSyntaxException(HttpServletRequest request, URISyntaxException e) {
logException(e, request);
// when the index is less than zero, its unknown, and we will use more general message
final String messageId = e.getIndex() < 0 ? "error.invalidIdentifier" : "error.invalidUriCharacter";
TermItException exception = new InvalidIdentifierException(e.getMessage(), e, messageId)
.addParameter("uri", e.getInput())
.addParameter("reason", e.getReason())
.addParameter("message", e.getMessage())
.addParameter("index", Integer.toString(e.getIndex()))
.addParameter("char", Character.toString(e.getInput().charAt(e.getIndex())));
return new ResponseEntity<>(errorInfo(request, exception), HttpStatus.CONFLICT);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -152,11 +152,17 @@ public URI generateIdentifier(String namespace, String... components) {
} catch (IllegalArgumentException e) {
throw new InvalidIdentifierException(
"Generated identifier " + namespace + localPart + " is not a valid URI.",
e,
"error.identifier.invalidCharacters");
}
}

private static boolean isUri(String value) {
/**
* @param value the URI to check
* @return {@code true} when the URI is prefixed with protocol ({@code http/s, ftp or file}
* and it is a valid {@link URI}. {@code false} otherwise
*/
public static boolean isUri(String value) {
try {
if (!value.matches("^(https?|ftp|file)://.+")) {
return false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,12 @@

import com.fasterxml.classmate.ResolvedType;
import com.fasterxml.classmate.TypeResolver;
import cz.cvut.kbss.termit.exception.InvalidIdentifierException;
import cz.cvut.kbss.termit.exception.NotFoundException;
import cz.cvut.kbss.termit.exception.ValidationException;
import cz.cvut.kbss.termit.model.util.HasIdentifier;
import cz.cvut.kbss.termit.persistence.dao.GenericDao;
import cz.cvut.kbss.termit.service.IdentifierResolver;
import cz.cvut.kbss.termit.validation.ValidationResult;
import jakarta.annotation.Nonnull;
import jakarta.validation.Validator;
Expand Down Expand Up @@ -173,6 +175,7 @@ public void persist(@Nonnull T instance) {
*/
protected void prePersist(@Nonnull T instance) {
validate(instance);
validateUri(instance.getUri());
}

/**
Expand Down Expand Up @@ -208,6 +211,7 @@ public T update(T instance) {
* @param instance The instance to be updated, not {@code null}
*/
protected void preUpdate(@Nonnull T instance) {
validateUri(instance.getUri());
if (!exists(instance.getUri())) {
throw NotFoundException.create(instance.getClass().getSimpleName(), instance.getUri());
}
Expand Down Expand Up @@ -282,4 +286,17 @@ protected void validate(T instance) {
throw new ValidationException(validationResult);
}
}

/**
* Validates the specified uri.
*
* @param uri the uri to validate
* @throws cz.cvut.kbss.termit.exception.InvalidIdentifierException when the URI is invalid
* @see cz.cvut.kbss.termit.service.IdentifierResolver#isUri(String)
*/
protected void validateUri(URI uri) throws InvalidIdentifierException {
if (uri != null && !IdentifierResolver.isUri(uri.toString())) {
throw new InvalidIdentifierException("Invalid URI: '" + uri + "'", "error.invalidIdentifier").addParameter("uri", uri.toString());
}
}
}
10 changes: 6 additions & 4 deletions src/main/java/cz/cvut/kbss/termit/util/ExceptionUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import jakarta.annotation.Nonnull;

import java.util.HashSet;
import java.util.Optional;
import java.util.Set;

public class ExceptionUtils {
Expand All @@ -11,21 +12,22 @@ private ExceptionUtils() {
}

/**
* Resolves all nested causes of the {@code throwable} and returns true if any is matching the {@code cause}
* Resolves all nested causes of the {@code throwable}
* @return any cause of the {@code throwable} matching the {@code cause} class, or empty when not found
*/
public static boolean isCausedBy(final Throwable throwable, @Nonnull final Class<? extends Throwable> cause) {
public static <T extends Throwable> Optional<T> findCause(final Throwable throwable, @Nonnull final Class<T> cause) {
Throwable t = throwable;
final Set<Throwable> visited = new HashSet<>();
while (t != null) {
if(visited.add(t)) {
if (cause.isInstance(t)){
return true;
return Optional.of((T) t);
}
t = t.getCause();
continue;
}
break;
}
return false;
return Optional.empty();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,9 @@
import org.springframework.web.context.request.async.AsyncRequestNotUsableException;
import org.springframework.web.multipart.MaxUploadSizeExceededException;

import static cz.cvut.kbss.termit.util.ExceptionUtils.isCausedBy;
import java.net.URISyntaxException;

import static cz.cvut.kbss.termit.util.ExceptionUtils.findCause;

/**
* @implSpec Should reflect {@link cz.cvut.kbss.termit.rest.handler.RestExceptionHandler}
Expand Down Expand Up @@ -74,8 +76,8 @@ private static void logException(Throwable ex, Message<?> message) {
}

private static void logException(String message, Throwable ex) {
// prevents from logging exceptions caused be broken connection with a client
if (!isCausedBy(ex, AsyncRequestNotUsableException.class)) {
// Prevents exceptions caused by broken connection with a client from logging
if (findCause(ex, AsyncRequestNotUsableException.class).isEmpty()) {
LOG.error(message, ex);
}
}
Expand Down Expand Up @@ -263,4 +265,10 @@ public ErrorInfo invalidIdentifierException(Message<?> message, InvalidIdentifie
logException(e, message);
return errorInfo(message, e);
}

@MessageExceptionHandler
public ErrorInfo uriSyntaxException(Message<?> message, URISyntaxException e) {
logException(e, message);
return errorInfo(message, e);
}
}

0 comments on commit a68b74d

Please sign in to comment.