Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GlobalExceptionHandler extends EuropeanaGlobalExceptionHandler #384

Open
wants to merge 3 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,17 +1,15 @@
package eu.europeana.annotation.tests.web;

import static eu.europeana.annotation.definitions.model.vocabulary.WebAnnotationFields.BATCH_TOTAL_FIELD;
import static eu.europeana.annotation.definitions.model.vocabulary.WebAnnotationFields.RESP_OPERATION_REPORT_ERRORS_FIELD;
import static eu.europeana.annotation.definitions.model.vocabulary.WebAnnotationFields.RESP_OPERATION_REPORT_FAILURECOUNT_FIELD;
import static eu.europeana.annotation.definitions.model.vocabulary.WebAnnotationFields.RESP_OPERATION_REPORT_FIELD;
import static eu.europeana.annotation.definitions.model.vocabulary.WebAnnotationFields.RESP_OPERATION_REPORT_SUCCESSCOUNT_FIELD;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

import org.apache.commons.lang3.StringUtils;
import org.codehaus.jettison.json.JSONObject;
import org.junit.jupiter.api.BeforeEach;
Expand All @@ -21,13 +19,16 @@
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonElement;
import com.google.gson.JsonParser;

import eu.europeana.annotation.definitions.model.Annotation;
import eu.europeana.annotation.tests.AbstractIntegrationTest;
import eu.europeana.annotation.tests.utils.AnnotationTestUtils;
import eu.europeana.annotation.web.model.BatchProcessingStatus;

/**
* Annotation API Batch Upload Test class
Expand Down Expand Up @@ -160,17 +161,12 @@ public void updateNonExistingAnnotationsError() throws Exception {

jsonPrettyPrint(response.getBody());

// get response body properties
JSONObject jsonObj = new JSONObject(response.getBody());
JSONObject opRepJsonObj = jsonObj.getJSONObject(RESP_OPERATION_REPORT_FIELD);
assertEquals(5, opRepJsonObj.get(RESP_OPERATION_REPORT_SUCCESSCOUNT_FIELD));
assertEquals(3, opRepJsonObj.get(RESP_OPERATION_REPORT_FAILURECOUNT_FIELD));
JSONObject errors = opRepJsonObj.getJSONObject(RESP_OPERATION_REPORT_ERRORS_FIELD);

String respBody=response.getBody();
assertTrue(respBody.contains(BatchProcessingStatus.successCountStr + "5"));
assertTrue(respBody.contains(BatchProcessingStatus.failureCountStr + "3"));
// positions 2, 6 and 8 do not exist
assertTrue(((String) errors.get("-1")).startsWith("Annotation does not exist"));
assertTrue(((String) errors.get("-2")).startsWith("Annotation does not exist"));
assertTrue(((String) errors.get("-3")).startsWith("Annotation does not exist"));
int errorsCount = StringUtils.countMatches(respBody, "Annotation does not exist");
assertEquals(3, errorsCount);

long startingId = testAnnotations.get(0).getIdentifier();
for (long i = startingId + TEST_NUM_ANNOTATIONS; i < startingId + 8; i++) {
Expand All @@ -197,18 +193,12 @@ public void validationError() throws Exception {
// response status must be 400 BAD_REQUEST
assertEquals(HttpStatus.BAD_REQUEST, response.getStatusCode());

// get response body properties
JSONObject jsonObj = new JSONObject(response.getBody());
JSONObject opRepJsonObj = jsonObj.getJSONObject(RESP_OPERATION_REPORT_FIELD);
assertEquals(3, opRepJsonObj.get(RESP_OPERATION_REPORT_SUCCESSCOUNT_FIELD));
assertEquals(2, opRepJsonObj.get(RESP_OPERATION_REPORT_FAILURECOUNT_FIELD));
JSONObject errors = opRepJsonObj.getJSONObject(RESP_OPERATION_REPORT_ERRORS_FIELD);

String respBody=response.getBody();
assertTrue(respBody.contains(BatchProcessingStatus.successCountStr + "3"));
assertTrue(respBody.contains(BatchProcessingStatus.failureCountStr + "2"));
// keys 1 and 2 have errors
assertEquals("Invalid tag size. Must be shorter then 64 characters! tag.size: 170",
errors.get("1"));
assertEquals("Invalid tag size. Must be shorter then 64 characters! tag.size: 170",
errors.get("2"));
int errorsCount = StringUtils.countMatches(respBody, "Invalid tag size. Must be shorter then 64 characters! tag.size: 170");
assertEquals(2, errorsCount);

long startingId = testAnnotations.get(0).getIdentifier();
for (long i = startingId + TEST_NUM_ANNOTATIONS; i < startingId + 5; i++) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
package eu.europeana.annotation.web.model;

import java.util.HashMap;
import java.util.Map;

public class BatchProcessingStatus implements BatchReportable {
public static final String successCountStr="Success count: ";
gsergiu marked this conversation as resolved.
Show resolved Hide resolved
public static final String failureCountStr="failure count: ";
public static final String indexingFailureCountStr="indexingFailure count: ";

int failureCount = 0;
int successCount = 0;
int indexingFailureCount = 0;
Expand Down Expand Up @@ -41,9 +46,16 @@ public void incrementSuccessCount() {

@Override
public String toString() {
return "success count: " + successCount
+ ", failure count: " + failureCount
+ ", indexingFailure count: " + indexingFailureCount;
String errorsStr="";
for (Map.Entry<String, String> error : errors.entrySet()) {
errorsStr+=error.getKey() + " = " + error.getValue() + ";";
}
if(!errorsStr.isEmpty()) {
errorsStr=errorsStr.substring(0, errorsStr.length()-1) + ".";
}

return successCountStr + successCount + ", " + failureCountStr + failureCount
+ ", " + indexingFailureCountStr + indexingFailureCount + ". Errors: " + errorsStr + ".";
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,20 @@

public class BatchUploadStatus extends BatchProcessingStatus {

public Integer totalNumberOfAnnotations;
public Integer totalNumberOfAnnotations=0;

public Integer numberOfAnnotationsWithId;
public Integer numberOfAnnotationsWithId=0;

public Integer numberOfAnnotationsWithoutId;
public Integer numberOfAnnotationsWithoutId=0;

public BatchOperationStep step;

@Override
public String toString() {
if(failureCount > 0)
return step + " failed (" + failureCount + " errors).";
else
return step + " succeeded (" + successCount + " successes).";
return step + ". " + "Total number of annotations: " + totalNumberOfAnnotations +
", number of annotations with id: " + numberOfAnnotationsWithId +
", number of annotations without id: " + numberOfAnnotationsWithoutId + ". " +
super.toString();
}

public Integer getTotalNumberOfAnnotations() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,15 @@
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
import eu.europeana.annotation.definitions.model.vocabulary.WebAnnotationFields;

import eu.europeana.annotation.web.exception.response.BatchUploadException;
import eu.europeana.annotation.web.model.AnnotationOperationResponse;
import eu.europeana.api.commons.config.i18n.I18nService;
import eu.europeana.api.commons.error.EuropeanaApiErrorResponse;
import eu.europeana.api.commons.web.controller.exception.AbstractExceptionHandlingController;
import eu.europeana.api.commons.web.model.ApiResponse;
import eu.europeana.api.commons.web.exception.EuropeanaGlobalExceptionHandler;

@ControllerAdvice
@ConditionalOnWebApplication
public class GlobalExceptionHandler extends AbstractExceptionHandlingController {
public class GlobalExceptionHandler extends EuropeanaGlobalExceptionHandler {

@Resource
I18nService i18nService;
Expand All @@ -38,18 +36,21 @@ protected I18nService getI18nService() {
// response.setError(errorMessage);
// return response;
// }

@ExceptionHandler
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please add the catched exception to the annotation (see also parent class)

public ResponseEntity<EuropeanaApiErrorResponse> handleRequestBodyNotParsableError(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please renamed back method to handleBatchUploadException, so that the method name is inline with the purpose

BatchUploadException e, HttpServletRequest httpRequest) {
EuropeanaApiErrorResponse response = (new EuropeanaApiErrorResponse.Builder(httpRequest, e, stackTraceEnabled()))
.setStatus(e.getStatus().value())
.setError(e.getStatus().getReasonPhrase())
.setMessage(e.getMessage())
.setSeeAlso(getSeeAlso())
.build();

@ExceptionHandler(BatchUploadException.class)
public ResponseEntity<AnnotationOperationResponse> handleBatchUploadException(
BatchUploadException ex, HttpServletRequest httpRequest) {
AnnotationOperationResponse response = new AnnotationOperationResponse(
httpRequest.getParameter(WebAnnotationFields.PARAM_WSKEY), "batchUpload");
response.setOperationReport(ex.getOperationReport());
response.success = false;
response.setError(ex.getMessage());

return ResponseEntity.status(ex.getStatus()).contentType(MediaType.APPLICATION_JSON)
.body(response);
return ResponseEntity
.status(e.getStatus())
.headers(createHttpHeaders(httpRequest))
.body(response);
}

/*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,19 @@
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Set;

import javax.servlet.http.HttpServletRequest;

import org.apache.stanbol.commons.exception.JsonParseException;
import org.apache.stanbol.commons.jsonld.JsonLd;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.Authentication;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;

import com.google.gson.Gson;

import eu.europeana.annotation.definitions.exception.AnnotationAttributeInstantiationException;
import eu.europeana.annotation.definitions.exception.AnnotationInstantiationException;
import eu.europeana.annotation.definitions.exception.AnnotationValidationException;
Expand Down Expand Up @@ -173,25 +177,29 @@ protected ResponseEntity<String> storeAnnotations(String annotationPageIn, Authe
AnnotationPage annotationPage = annoPageParser.parseAnnotationPage(annotationPageIn);
List<? extends Annotation> annotations = annotationPage.getAnnotations();

// initialize upload status
BatchUploadStatus uploadStatus = new BatchUploadStatus();
uploadStatus.setTotalNumberOfAnnotations(annotations.size());
// initialize upload status for validation
BatchUploadStatus uploadStatusValidation = new BatchUploadStatus();
uploadStatusValidation.setTotalNumberOfAnnotations(annotations.size());

// validate annotations
uploadStatus.setStep(BatchOperationStep.VALIDATION);
getAnnotationService().validateWebAnnotations(annotations, uploadStatus, authentication);
uploadStatusValidation.setStep(BatchOperationStep.VALIDATION);
getAnnotationService().validateWebAnnotations(annotations, uploadStatusValidation, authentication);

// in case of validation errors, return error report
if (uploadStatus.getFailureCount() > 0)
throw new BatchUploadException(uploadStatus.toString(), uploadStatus);
if (uploadStatusValidation.getFailureCount() > 0) {
throw new BatchUploadException(uploadStatusValidation.toString(), uploadStatusValidation);
}

AnnotationsList webAnnotations = new AnnotationsList(annotationPage.getAnnotations());

// annotations are separated into those with identifier (assumed updates)
// and those without identifier (new annotations which should be created);
// first annotations with identifier (assumed updates)
AnnotationsList annosWithId = webAnnotations.getAnnotationsWithId();
uploadStatus.setNumberOfAnnotationsWithId(annosWithId.size());
// initialize upload status for the non-existing annotations
BatchUploadStatus uploadStatusNonExist = new BatchUploadStatus();
uploadStatusNonExist.setTotalNumberOfAnnotations(annotations.size());
uploadStatusNonExist.setNumberOfAnnotationsWithId(annosWithId.size());

// verify if the annotations with identifiers exist in the database
List<Long> annoIdentifiers = annosWithId.getIdentifiers();
Expand All @@ -205,28 +213,33 @@ protected ResponseEntity<String> storeAnnotations(String annotationPageIn, Authe
}

// consistency (annotations with identifier must match existing annotations)
uploadStatus.setStep(BatchOperationStep.CHECK_UPDATE_ANNOTATIONS_AVAILABLE);
uploadStatusNonExist.setStep(BatchOperationStep.CHECK_UPDATE_ANNOTATIONS_AVAILABLE);
if (annosWithId.size() != existingInDb.size()) {
// remove existing identifiers, the remaining list contains only missing identifiers
annoIdentifiers.removeAll(existingInDb.getIdentifiers());
getAnnotationService().reportNonExisting(annotations, uploadStatus, annoIdentifiers);
throw new BatchUploadException(uploadStatus.toString(), uploadStatus, HttpStatus.NOT_FOUND);
getAnnotationService().reportNonExisting(annotations, uploadStatusNonExist, annoIdentifiers);
throw new BatchUploadException(uploadStatusNonExist.toString(), uploadStatusNonExist, HttpStatus.NOT_FOUND);
}

LinkedHashMap<Annotation, Annotation> webAnnoStoredAnnoAnnoMap = webAnnotations.getAnnotationsMap();

// initialize upload status for the existing annotations
BatchUploadStatus uploadStatusExist = new BatchUploadStatus();
uploadStatusExist.setTotalNumberOfAnnotations(annotations.size());
// update existing annotations
if (annosWithId.getAnnotations().size() > 0) {
uploadStatus.setStep(BatchOperationStep.UPDATE_EXISTING_ANNOTATIONS);
getAnnotationService().updateExistingAnnotations(uploadStatus, existingInDb.getAnnotations(),
annosWithId.getAnnotations(), webAnnoStoredAnnoAnnoMap);
uploadStatusExist.setStep(BatchOperationStep.UPDATE_EXISTING_ANNOTATIONS);
getAnnotationService().updateExistingAnnotations(uploadStatusExist, existingInDb.getAnnotations(),
annosWithId.getAnnotations(), webAnnoStoredAnnoAnnoMap);
}
// annotations are separated into those with identifier (assumed updates)
// and those without identifier (new annotations which should be created);
// second annotations without (assumed inserts)
AnnotationsList annosWithoutId = webAnnotations.getAnnotationsWithoutId();
uploadStatus.setStep(BatchOperationStep.INSERT_NEW_ANNOTATIONS);
uploadStatus.setNumberOfAnnotationsWithoutId(annosWithoutId.size());
// initialize upload status for the inserting annotations
BatchUploadStatus uploadStatusInsert = new BatchUploadStatus();
uploadStatusInsert.setStep(BatchOperationStep.INSERT_NEW_ANNOTATIONS);
uploadStatusInsert.setNumberOfAnnotationsWithoutId(annosWithoutId.size());
// default values
if (annosWithoutId.size() > 0) {
String clientId = ((EuropeanaApiCredentials) authentication.getCredentials()).getClientId();
Expand All @@ -236,7 +249,7 @@ protected ResponseEntity<String> storeAnnotations(String annotationPageIn, Authe
// getAuthorizationService().authorizeUser(userId,authentication, Operations.CREATE);
AnnotationDefaults annoDefaults = new AnnotationDefaults.Builder().setGenerator(buildAgent(generatorId, AgentTypes.SOFTWARE))
.setUser(buildAgent(creatorId, AgentTypes.PERSON)).build();
getAnnotationService().insertNewAnnotations(uploadStatus, annosWithoutId.getAnnotations(), annoDefaults,
getAnnotationService().insertNewAnnotations(uploadStatusInsert, annosWithoutId.getAnnotations(), annoDefaults,
webAnnoStoredAnnoAnnoMap);
}

Expand Down
Loading