Improved logging and exception handling
This commit is contained in:
parent
b0f329c102
commit
7da06bd659
3 changed files with 220 additions and 136 deletions
|
|
@ -20,6 +20,7 @@ import java.io.File;
|
|||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
|
|
@ -39,98 +40,58 @@ public class ApiController {
|
|||
private ValidationService validationService;
|
||||
|
||||
@PostMapping("/block")
|
||||
public ResponseEntity<?> block(@RequestBody List<String> ids) {
|
||||
try {
|
||||
validationService.validateAll(ids);
|
||||
public ResponseEntity<?> block(@RequestBody List<String> ids) throws SQLException, FileNotFoundException {
|
||||
validationService.validateAll(ids);
|
||||
|
||||
logger.debug("Starting block process for ids: {}", ids);
|
||||
apiService.process(ConfigType.BLOCK, ids);
|
||||
logger.debug("Finished block process for ids: {}", ids);
|
||||
return ResponseEntity.ok("Операция \"Блокировка\" завершена успешно.");
|
||||
} catch (ValidationException e) {
|
||||
logger.error("Validation failed for IDs: {}", ids, e);
|
||||
return ResponseEntity.badRequest().body(Map.of(
|
||||
"message", "Validation error occurred",
|
||||
"details", e.getValidationDetails()
|
||||
));
|
||||
} catch (Exception e) {
|
||||
logger.error("Unexpected error during processing: {}", e.getMessage(), e);
|
||||
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("Internal error occurred.");
|
||||
}
|
||||
logger.debug("Starting block process for ids: {}", ids);
|
||||
apiService.process(ConfigType.BLOCK, ids);
|
||||
logger.debug("Finished block process for ids: {}", ids);
|
||||
|
||||
return ResponseEntity.ok("Операция \"Блокировка\" завершена успешно.");
|
||||
}
|
||||
|
||||
|
||||
@PostMapping("/unblock")
|
||||
public ResponseEntity<?> unblock(@RequestBody List<String> ids) {
|
||||
try {
|
||||
validationService.validateAll(ids);
|
||||
public ResponseEntity<?> unblock(@RequestBody List<String> ids) throws SQLException, FileNotFoundException {
|
||||
validationService.validateAll(ids);
|
||||
|
||||
logger.debug("Starting unblock process for ids: {}", ids);
|
||||
apiService.process(ConfigType.UNBLOCK, ids);
|
||||
logger.debug("Finished unblock process for ids: {}", ids);
|
||||
return ResponseEntity.ok("Операция \"Разблокировка\" завершена успешно.");
|
||||
} catch (ValidationException e) {
|
||||
logger.error("Validation failed for IDs: {}", ids, e);
|
||||
return ResponseEntity.badRequest().body(Map.of(
|
||||
"message", "Validation error occurred",
|
||||
"details", e.getValidationDetails()
|
||||
));
|
||||
} catch (Exception e) {
|
||||
logger.error("Unexpected error during processing: {}", e.getMessage(), e);
|
||||
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("Internal error occurred.");
|
||||
}
|
||||
logger.debug("Starting unblock process for ids: {}", ids);
|
||||
apiService.process(ConfigType.UNBLOCK, ids);
|
||||
logger.debug("Finished unblock process for ids: {}", ids);
|
||||
|
||||
return ResponseEntity.ok("Операция \"Разблокировка\" завершена успешно.");
|
||||
}
|
||||
|
||||
|
||||
@PostMapping("/removeFromSystem")
|
||||
public ResponseEntity<?> removeFromSystem(@RequestBody List<String> ids) {
|
||||
try {
|
||||
validationService.validateAll(ids);
|
||||
public ResponseEntity<?> removeFromSystem(@RequestBody List<String> ids) throws SQLException, FileNotFoundException {
|
||||
validationService.validateAll(ids);
|
||||
|
||||
logger.debug("Starting removeFromSystem process for ids: {}", ids);
|
||||
apiService.process(ConfigType.REMOVE_FROM_SYSTEM, ids);
|
||||
logger.debug("Finished removeFromSystem process for ids: {}", ids);
|
||||
return ResponseEntity.ok("Операция \"Удаление данных по гражданину\" завершена успешно.");
|
||||
} catch (ValidationException e) {
|
||||
logger.error("Validation failed for IDs: {}", ids, e);
|
||||
return ResponseEntity.badRequest().body(Map.of(
|
||||
"message", "Validation error occurred",
|
||||
"details", e.getValidationDetails()
|
||||
));
|
||||
} catch (Exception e) {
|
||||
logger.error("Unexpected error during processing: {}", e.getMessage(), e);
|
||||
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("Internal error occurred.");
|
||||
}
|
||||
logger.debug("Starting removeFromSystem process for ids: {}", ids);
|
||||
apiService.process(ConfigType.REMOVE_FROM_SYSTEM, ids);
|
||||
logger.debug("Finished removeFromSystem process for ids: {}", ids);
|
||||
|
||||
return ResponseEntity.ok("Операция \"Удаление данных по гражданину\" завершена успешно.");
|
||||
}
|
||||
|
||||
|
||||
@PostMapping("/removeFromCallList")
|
||||
public ResponseEntity<?> removeFromCallList(@RequestBody List<String> ids) {
|
||||
try {
|
||||
validationService.validateAll(ids);
|
||||
public ResponseEntity<?> removeFromCallList(@RequestBody List<String> ids) throws SQLException, FileNotFoundException {
|
||||
validationService.validateAll(ids);
|
||||
|
||||
logger.debug("Starting removeFromCallList process for ids: {}", ids);
|
||||
apiService.process(ConfigType.REMOVE_FROM_CALL_LIST, ids);
|
||||
logger.debug("Finished removeFromCallList process for ids: {}", ids);
|
||||
return ResponseEntity.ok("Операция \"Удаление из списков на вызов\" завершена успешно.");
|
||||
} catch (ValidationException e) {
|
||||
logger.error("Validation failed for IDs: {}", ids, e);
|
||||
return ResponseEntity.badRequest().body(Map.of(
|
||||
"message", "Validation error occurred",
|
||||
"details", e.getValidationDetails()
|
||||
));
|
||||
} catch (Exception e) {
|
||||
logger.error("Unexpected error during processing: {}", e.getMessage(), e);
|
||||
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("Internal error occurred.");
|
||||
}
|
||||
logger.debug("Starting removeFromCallList process for ids: {}", ids);
|
||||
apiService.process(ConfigType.REMOVE_FROM_CALL_LIST, ids);
|
||||
logger.debug("Finished removeFromCallList process for ids: {}", ids);
|
||||
|
||||
return ResponseEntity.ok("Операция \"Удаление из списков на вызов\" завершена успешно.");
|
||||
}
|
||||
|
||||
|
||||
@PostMapping("/downloadCSV")
|
||||
public ResponseEntity<Resource> downloadCSV(@RequestBody DownloadCSVRequest request)
|
||||
throws IOException {
|
||||
public ResponseEntity<Resource> downloadCSV(@RequestBody DownloadCSVRequest request) throws IOException {
|
||||
logger.debug("Starting downloadCSV process for request: {}", request.getType());
|
||||
if (request.getStartDate() != null && request.getEndDate() != null) {
|
||||
if (request.getStartDate().isAfter(request.getEndDate())) {
|
||||
throw new IllegalArgumentException("Start date must be before end date");
|
||||
}
|
||||
}
|
||||
|
||||
validateRequestDates(request);
|
||||
|
||||
File csvFile = apiService.download(ConfigType.DOWNLOAD_CSV, request);
|
||||
InputStreamResource resource = new InputStreamResource(new FileInputStream(csvFile));
|
||||
|
|
@ -144,11 +105,22 @@ public class ApiController {
|
|||
.body(resource);
|
||||
}
|
||||
|
||||
private void validateRequestDates(DownloadCSVRequest request) {
|
||||
if (request.getStartDate() != null && request.getEndDate() != null) {
|
||||
if (request.getStartDate().isAfter(request.getEndDate())) {
|
||||
throw new IllegalArgumentException("Start date must be before end date");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@GetMapping("/listDownloadTypes")
|
||||
public ResponseEntity<?> listDownloadTypes()
|
||||
throws FileNotFoundException {
|
||||
public ResponseEntity<List<String>> listDownloadTypes() throws FileNotFoundException {
|
||||
logger.debug("Fetching list of download types...");
|
||||
|
||||
List<String> downloadCSVTypes = apiService.getDownloadTypes(ConfigType.DOWNLOAD_CSV);
|
||||
|
||||
logger.debug("Successfully retrieved download types");
|
||||
return ResponseEntity.ok(downloadCSVTypes);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,106 @@
|
|||
package org.micord.exceptions;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||
|
||||
import javax.naming.ServiceUnavailableException;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.nio.file.AccessDeniedException;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Map;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
@RestControllerAdvice
|
||||
public class GlobalExceptionHandler {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);
|
||||
|
||||
@ExceptionHandler(SQLException.class)
|
||||
public ResponseEntity<?> handleSQLException(SQLException e) {
|
||||
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(Map.of(
|
||||
"message", "Database error occurred",
|
||||
"details", e.getMessage()
|
||||
));
|
||||
}
|
||||
|
||||
@ExceptionHandler(Exception.class)
|
||||
public ResponseEntity<?> handleGeneralException(Exception e) {
|
||||
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(Map.of(
|
||||
"message", "Unexpected error occurred",
|
||||
"details", e.getMessage()
|
||||
));
|
||||
}
|
||||
|
||||
@ExceptionHandler(ValidationException.class)
|
||||
public ResponseEntity<?> handleValidationException(ValidationException e) {
|
||||
return ResponseEntity.badRequest().body(Map.of(
|
||||
"message", "Validation error occurred",
|
||||
"details", e.getValidationDetails()
|
||||
));
|
||||
}
|
||||
|
||||
@ExceptionHandler(IllegalStateException.class)
|
||||
public ResponseEntity<?> handleIllegalStateException(IllegalStateException e) {
|
||||
return ResponseEntity.status(HttpStatus.CONFLICT).body(Map.of(
|
||||
"message", "Operation cannot be performed due to an invalid state",
|
||||
"details", e.getMessage()
|
||||
));
|
||||
}
|
||||
|
||||
@ExceptionHandler(AccessDeniedException.class)
|
||||
public ResponseEntity<?> handleAccessDeniedException(AccessDeniedException e) {
|
||||
return ResponseEntity.status(HttpStatus.FORBIDDEN).body(Map.of(
|
||||
"message", "Access denied",
|
||||
"details", e.getMessage()
|
||||
));
|
||||
}
|
||||
|
||||
@ExceptionHandler(ServiceUnavailableException.class)
|
||||
public ResponseEntity<?> handleServiceUnavailableException(ServiceUnavailableException e) {
|
||||
return ResponseEntity.status(HttpStatus.SERVICE_UNAVAILABLE).body(Map.of(
|
||||
"message", "Service is temporarily unavailable",
|
||||
"details", e.getMessage()
|
||||
));
|
||||
}
|
||||
|
||||
@ExceptionHandler(FileNotFoundException.class)
|
||||
public ResponseEntity<?> handleFileNotFoundException(FileNotFoundException e) {
|
||||
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(Map.of(
|
||||
"message", "File not found",
|
||||
"details", e.getMessage()
|
||||
));
|
||||
}
|
||||
|
||||
@ExceptionHandler(IllegalArgumentException.class)
|
||||
public ResponseEntity<?> handleIllegalArgumentException(IllegalArgumentException e) {
|
||||
return ResponseEntity.badRequest().body(Map.of(
|
||||
"message", "Invalid input provided",
|
||||
"details", e.getMessage()
|
||||
));
|
||||
}
|
||||
|
||||
@ExceptionHandler(NoSuchElementException.class)
|
||||
public ResponseEntity<?> handleNoSuchElementException(NoSuchElementException e) {
|
||||
logger.error("Resource not found: {}", e.getMessage());
|
||||
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(Map.of(
|
||||
"message", "Requested resource not found",
|
||||
"details", e.getMessage()
|
||||
));
|
||||
}
|
||||
|
||||
@ExceptionHandler(RuntimeException.class)
|
||||
public ResponseEntity<?> handleRuntimeException(RuntimeException e) {
|
||||
logger.error("Unexpected error occurred: {}", e.getMessage(), e);
|
||||
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(Map.of(
|
||||
"message", "Internal server error",
|
||||
"details", e.getMessage()
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -16,7 +16,13 @@ import org.slf4j.LoggerFactory;
|
|||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Element;
|
||||
import org.xml.sax.InputSource;
|
||||
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import java.io.StringReader;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.http.HttpClient;
|
||||
import java.net.http.HttpRequest;
|
||||
|
|
@ -26,7 +32,6 @@ import java.sql.PreparedStatement;
|
|||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
|
|
@ -42,24 +47,9 @@ public class RequestService {
|
|||
|
||||
public void processS3Requests(List<S3Request> s3Requests, List<String> ids) {
|
||||
logger.debug("Starting processing of S3 requests");
|
||||
if (s3Requests != null && !s3Requests.isEmpty()) {
|
||||
List<CompletableFuture<Void>> requestFutures = s3Requests.stream()
|
||||
.map(request -> CompletableFuture.runAsync(() -> {
|
||||
try {
|
||||
processS3Request(request, ids);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Error processing S3 request: " + request, e);
|
||||
}
|
||||
}))
|
||||
.toList();
|
||||
|
||||
CompletableFuture.allOf(requestFutures.toArray(new CompletableFuture[0]))
|
||||
.whenComplete((result, ex) -> {
|
||||
if (ex != null) {
|
||||
logger.error("Error processing S3 requests", ex);
|
||||
throw new RuntimeException("Error processing S3 requests", ex);
|
||||
}
|
||||
});
|
||||
for (S3Request request : s3Requests) {
|
||||
processS3Request(request, ids);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -82,61 +72,75 @@ public class RequestService {
|
|||
}
|
||||
long endExecTime = System.currentTimeMillis();
|
||||
logger.debug("Paths fetched in {} ms", endExecTime - startExecTime);
|
||||
}
|
||||
catch (SQLException e) {
|
||||
logger.error("Failed to execute query for RequestArgument", e);
|
||||
throw new RuntimeException("Error executing database query: " + argument.getRequestArgumentURL(), e);
|
||||
} catch (SQLException e) {
|
||||
logger.error("Failed to execute query for RequestArgument: {}", argument.getRequestArgumentURL(), e);
|
||||
throw new RuntimeException("Database query error for argument: " + argument.getRequestArgumentURL(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (files.isEmpty()) {
|
||||
logger.warn("No files found for S3 request");
|
||||
throw new RuntimeException("No files found for S3 request");
|
||||
throw new NoSuchElementException("No files found for S3 request");
|
||||
}
|
||||
|
||||
files.forEach(file -> {
|
||||
HttpRequest httpRequest;
|
||||
logger.debug("Starting building HTTP request for S3 request");
|
||||
long startExecTime = System.currentTimeMillis();
|
||||
|
||||
if (file == null || file.isBlank()) {
|
||||
logger.warn("Skipping invalid file path: {}", file);
|
||||
throw new RuntimeException("Invalid file path");
|
||||
}
|
||||
for (String file : files) {
|
||||
try {
|
||||
httpRequest = S3HttpConnection.buildHttpRequest(request, file);
|
||||
processFileForS3Request(request, file);
|
||||
} catch (RuntimeException e) {
|
||||
logger.error("Error processing file: {}", file, e);
|
||||
throw e; // Rethrow to propagate for exception handling
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
long endExecTime = System.currentTimeMillis();
|
||||
logger.debug("HTTP request built in {} ms", endExecTime - startExecTime);
|
||||
}
|
||||
|
||||
httpClient.sendAsync(httpRequest, HttpResponse.BodyHandlers.ofString())
|
||||
.thenAccept(response -> {
|
||||
if (response.statusCode() == HttpURLConnection.HTTP_NO_CONTENT
|
||||
|| response.statusCode() == HttpURLConnection.HTTP_OK) {
|
||||
logger.info("Successfully deleted object {}", file);
|
||||
}
|
||||
else {
|
||||
logger.error("Failed to delete object {}. Response code: {}", file,
|
||||
response.statusCode()
|
||||
);
|
||||
}
|
||||
})
|
||||
.exceptionally(ex -> {
|
||||
logger.error("Failed to delete object {}", file, ex);
|
||||
return null;
|
||||
});
|
||||
});
|
||||
|
||||
}
|
||||
catch (Exception e) {
|
||||
} catch (Exception e) {
|
||||
logger.error("Failed to process S3 request: {}", request, e);
|
||||
throw e; // Rethrow exception to propagate to the handler
|
||||
}
|
||||
}
|
||||
|
||||
private void processFileForS3Request(S3Request request, String file) {
|
||||
if (file == null || file.isBlank()) {
|
||||
logger.warn("Skipping invalid file path: {}", file);
|
||||
throw new RuntimeException("Invalid file path");
|
||||
}
|
||||
|
||||
try {
|
||||
logger.debug("Starting building HTTP request for file: {}", file);
|
||||
long startExecTime = System.currentTimeMillis();
|
||||
HttpRequest httpRequest = S3HttpConnection.buildHttpRequest(request, file);
|
||||
long endExecTime = System.currentTimeMillis();
|
||||
logger.debug("HTTP request built in {} ms for file: {}", endExecTime - startExecTime, file);
|
||||
|
||||
HttpResponse<String> response = httpClient.send(httpRequest, HttpResponse.BodyHandlers.ofString());
|
||||
if (response.statusCode() == HttpURLConnection.HTTP_NO_CONTENT || response.statusCode() == HttpURLConnection.HTTP_OK) {
|
||||
logger.info("Successfully deleted object {}", file);
|
||||
} else {
|
||||
handleErrorResponse(response, file);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error("Error sending HTTP request for file: {}", file, e);
|
||||
throw new RuntimeException("HTTP request error for file: " + file, e);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleErrorResponse(HttpResponse<String> response, String file) {
|
||||
try {
|
||||
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
|
||||
DocumentBuilder builder = factory.newDocumentBuilder();
|
||||
InputSource is = new InputSource(new StringReader(response.body()));
|
||||
Document doc = builder.parse(is);
|
||||
Element root = doc.getDocumentElement();
|
||||
String message = root.getElementsByTagName("Message").item(0).getTextContent();
|
||||
logger.error("Failed to delete object {}. Response code: {}. Error message: {}", file, response.statusCode(), message);
|
||||
throw new RuntimeException("Failed to delete object: " + file);
|
||||
} catch (Exception e) {
|
||||
logger.error("Failed to parse error response for file {}", file, e);
|
||||
throw new RuntimeException("Error parsing HTTP response: " + response.body(), e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Transactional
|
||||
public void processSqlAndAqlRequests(Requests config, List<String> ids) {
|
||||
logger.debug("Starting transactional processing of requests");
|
||||
|
|
@ -151,7 +155,9 @@ public class RequestService {
|
|||
processAqlRequests(request, ids);
|
||||
}
|
||||
}
|
||||
processS3Requests(config.getS3Requests(), ids);
|
||||
if (config.getS3Requests() != null && !config.getS3Requests().isEmpty()) {
|
||||
processS3Requests(config.getS3Requests(), ids);
|
||||
}
|
||||
}
|
||||
|
||||
private void processSqlRequests(SqlRequest request, List<String> ids) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue