add more errors and handle change

main
Julius Sula 2023-05-22 15:45:46 +02:00
parent 4a06622e62
commit a2a1368518
8 changed files with 136 additions and 83 deletions

View File

@ -12,7 +12,6 @@ import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import com.bmc.arsys.api.ARException; import com.bmc.arsys.api.ARException;
import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.JsonProcessingException;
import com.nttdata.calender.approval.Approval; import com.nttdata.calender.approval.Approval;
@ -23,6 +22,8 @@ import com.nttdata.calender.changes.ChangeResponse;
import com.nttdata.calender.changes.ChangeUpdateRequest; import com.nttdata.calender.changes.ChangeUpdateRequest;
import com.nttdata.calender.contracts.Contract; import com.nttdata.calender.contracts.Contract;
import com.nttdata.calender.contracts.ContractGetResponse; import com.nttdata.calender.contracts.ContractGetResponse;
import com.nttdata.calender.errorhandling.ErrorTypes.NotFoundError;
import com.nttdata.calender.errorhandling.ErrorTypes.ValidationError;
import com.nttdata.calender.implementer.Implementer; import com.nttdata.calender.implementer.Implementer;
import com.nttdata.calender.implementer.ImplementerGetRequest; import com.nttdata.calender.implementer.ImplementerGetRequest;
import com.nttdata.calender.implementer.ImplementerGetResponse; import com.nttdata.calender.implementer.ImplementerGetResponse;
@ -176,7 +177,7 @@ public class KalenderRestController {
@PostMapping("/api/getChanges") @PostMapping("/api/getChanges")
@ResponseBody @ResponseBody
public ChangeResponse getChanges(@RequestBody ChangeRequest request) public ChangeResponse getChanges(@RequestBody ChangeRequest request)
throws ARException { throws ARException, NotFoundError, ValidationError {
return change.get(request); return change.get(request);
} }

View File

@ -6,11 +6,11 @@ import java.util.ArrayList;
import java.util.Date; import java.util.Date;
import java.util.Optional; import java.util.Optional;
import java.util.TimeZone; import java.util.TimeZone;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import com.bmc.arsys.api.ARException; import com.bmc.arsys.api.ARException;
import com.bmc.arsys.api.Entry; import com.bmc.arsys.api.Entry;
import com.bmc.arsys.api.Timestamp; import com.bmc.arsys.api.Timestamp;
@ -18,7 +18,8 @@ import com.bmc.arsys.api.Value;
import com.nttdata.calender.api.Query; import com.nttdata.calender.api.Query;
import com.nttdata.calender.api.RemedyJavaAPI; import com.nttdata.calender.api.RemedyJavaAPI;
import com.nttdata.calender.changes.query.Filter; import com.nttdata.calender.changes.query.Filter;
import com.nttdata.calender.errorhandling.NotFoundError; import com.nttdata.calender.errorhandling.ErrorTypes.NotFoundError;
import com.nttdata.calender.errorhandling.ErrorTypes.ValidationError;
/** /**
* Class representing the change with all of the change specific attributes. * Class representing the change with all of the change specific attributes.
@ -39,7 +40,6 @@ public class Change {
@Autowired @Autowired
public Change(RemedyJavaAPI api) { public Change(RemedyJavaAPI api) {
this.api = api; this.api = api;
// TODO: Contract
this.queryChange = new Query.QueryBuilder(formName) this.queryChange = new Query.QueryBuilder(formName)
.addFieldId("ChangeNr", 1000000182) .addFieldId("ChangeNr", 1000000182)
.addFieldId("SupportGroup", 1000000015) .addFieldId("SupportGroup", 1000000015)
@ -74,7 +74,7 @@ public class Change {
* @return a List of {@link Change} for every entry found * @return a List of {@link Change} for every entry found
* @throws ARException if an error occurs during the retrieval process * @throws ARException if an error occurs during the retrieval process
*/ */
public ChangeResponse get(ChangeRequest request) throws ARException { public ChangeResponse get(ChangeRequest request) throws ARException, NotFoundError, ValidationError {
api.impersonateUser("ext_StanzPa"); api.impersonateUser("ext_StanzPa");
var peopleFullName = processPeopleInfo(request); var peopleFullName = processPeopleInfo(request);
@ -127,7 +127,7 @@ public class Change {
return new ChangeResponse(entriesSize, changes); return new ChangeResponse(entriesSize, changes);
} }
private String processPeopleInfo(ChangeRequest request) throws ARException { private String processPeopleInfo(ChangeRequest request) throws ARException, NotFoundError {
// Queries for SupportGroup of impersonated User // Queries for SupportGroup of impersonated User
var queryPerson = new Query.QueryBuilder("CTM:Support Group Association") var queryPerson = new Query.QueryBuilder("CTM:Support Group Association")
.addFieldId("FullName", 1000000017) .addFieldId("FullName", 1000000017)

View File

@ -2,6 +2,7 @@ package com.nttdata.calender.changes;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.ArrayList; import java.util.ArrayList;
import com.bmc.arsys.api.ARException; import com.bmc.arsys.api.ARException;
@ -9,6 +10,7 @@ import com.nttdata.calender.api.Query;
import com.nttdata.calender.api.RemedyJavaAPI; import com.nttdata.calender.api.RemedyJavaAPI;
import com.nttdata.calender.changes.query.Filter; import com.nttdata.calender.changes.query.Filter;
import com.nttdata.calender.changes.query.Sort; import com.nttdata.calender.changes.query.Sort;
import com.nttdata.calender.errorhandling.ErrorTypes.ValidationError;
/** /**
* Represents a change request object that stores information about slice start, * Represents a change request object that stores information about slice start,
@ -113,76 +115,97 @@ public class ChangeRequest {
* invalid filter is provided. * invalid filter is provided.
*/ */
// TODO: Exception handling (unsuppoprted qualifier) // TODO: Exception handling (unsuppoprted qualifier)
public String constructQualifier(Query query, RemedyJavaAPI api) throws ARException { public String constructQualifier(Query query, RemedyJavaAPI api) throws ARException, ValidationError {
var qualifier = ""; var qualifier = "";
for (int i = 0; i < this.filter.size(); i++) { for (int i = 0; i < this.filter.size(); i++) {
var column = this.filter.get(i).getColumn(); var current_filter = this.filter.get(i);
if (!column.isEmpty()) { var column = current_filter.getColumn();
var inner_qualifier = ""; var criteria = current_filter.getCriteria();
if (column.equals("D2")) { if (column.isEmpty() || criteria.length <= 0) {
var startFrom = filter.get(i).getCriteria()[0]; throw new ValidationError("Fields inside filter empty");
var startTo = filter.get(i).getCriteria()[1];
String inputFormat = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'";
String outputFormat = "dd/MM/yyyy";
LocalDateTime dateTimeFrom = LocalDateTime.parse(startFrom, DateTimeFormatter.ofPattern(inputFormat));
LocalDateTime dateTimeTo = LocalDateTime.parse(startTo, DateTimeFormatter.ofPattern(inputFormat));
String startFromFormatted = dateTimeFrom.format(DateTimeFormatter.ofPattern(outputFormat));
String startToFormatted = dateTimeTo.format(DateTimeFormatter.ofPattern(outputFormat));
if (!startFromFormatted.isEmpty() && !startToFormatted.isEmpty()) {
var dateColumn = api.getFieldDatabaseName(query.getFormName(), query.getFieldId(column));
// Same day changes need to startFrom=day and startTo=day+24h 60m 60s
if (startFromFormatted.equals(startToFormatted)) {
startToFormatted = "\' < (\"" + startToFormatted + "\"" + " + (24 * (60 * 60)))";
} else
startToFormatted = "\' <= \"" + startToFormatted + "\"";
qualifier += "\'" + dateColumn + "\' >= \"" + startFromFormatted + "\" AND ";
qualifier += "\'" + dateColumn + startToFormatted;
}
qualifier = "(" + qualifier + ")";
} else {
column = api.getFieldDatabaseName(query.getFormName(), query.getFieldId(column));
var inner_filter = "\'" + column + "\' ";
var criterias = filter.get(i).getCriteria();
var inner_concat = " OR ";
var inner_criteria_prefix = "";
switch (filter.get(i).getFilter()) {
case "equals":
inner_filter += "= ";
break;
case "contains":
inner_filter += "LIKE ";
inner_concat = " AND ";
inner_criteria_prefix = "%";
break;
default:
throw new ARException();
}
for (int j = 0; j < criterias.length; j++) {
criterias[j] = inner_criteria_prefix + criterias[j] + inner_criteria_prefix;
inner_qualifier += "(" + inner_filter + "\"" + criterias[j] + "\")";
if (j < criterias.length - 1) {
inner_qualifier += inner_concat;
}
}
qualifier += "(" + inner_qualifier + ")";
}
if (i < filter.size() - 1) {
qualifier += " AND ";
}
} }
var inner_qualifier = "";
if (column.equals("D2")) {
var dateQualifier = constructDateQualifier(current_filter, column, query, api);
qualifier = "(" + dateQualifier + ")";
} else {
column = api.getFieldDatabaseName(query.getFormName(), query.getFieldId(column));
var inner_filter = "\'" + column + "\' ";
var criterias = current_filter.getCriteria();
var inner_concat = " OR ";
var inner_criteria_prefix = "";
switch (current_filter.getFilter()) {
case "equals":
inner_filter += "= ";
break;
case "contains":
inner_filter += "LIKE ";
inner_concat = " AND ";
inner_criteria_prefix = "%";
break;
default:
throw new ARException();
}
for (int j = 0; j < criterias.length; j++) {
criterias[j] = inner_criteria_prefix + criterias[j] + inner_criteria_prefix;
inner_qualifier += "(" + inner_filter + "\"" + criterias[j] + "\")";
if (j < criterias.length - 1) {
inner_qualifier += inner_concat;
}
}
qualifier += "(" + inner_qualifier + ")";
}
if (i < filter.size() - 1) {
qualifier += " AND ";
}
} }
return qualifier; return qualifier;
} }
private String constructDateQualifier(Filter current_filter, String column, Query query, RemedyJavaAPI api)
throws ValidationError, ARException {
if (current_filter.getCriteria().length != 2) {
throw new ValidationError("Date Filter does not contain 2 date elements");
}
var startFrom = current_filter.getCriteria()[0];
var startTo = current_filter.getCriteria()[1];
var startFromFormatted = convertDate(startFrom);
var startToFormatted = convertDate(startTo);
var qualifier = "";
var dateColumn = api.getFieldDatabaseName(query.getFormName(), query.getFieldId(column));
// Same day changes need to startFrom=day and startTo=day+24h 60m 60s
if (startFromFormatted.equals(startToFormatted)) {
startToFormatted = "\' < (\"" + startToFormatted + "\"" + " + (24 * (60 * 60)))";
} else
startToFormatted = "\' <= \"" + startToFormatted + "\"";
qualifier += "\'" + dateColumn + "\' >= \"" + startFromFormatted + "\" AND ";
qualifier += "\'" + dateColumn + startToFormatted;
return qualifier;
}
private String convertDate(String date) throws ValidationError {
String inputFormat = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'";
String outputFormat = "dd/MM/yyyy";
LocalDateTime parser = LocalDateTime.parse(date, DateTimeFormatter.ofPattern(inputFormat));
var parsed = "";
try {
parsed = parser.format(DateTimeFormatter.ofPattern(outputFormat));
} catch (DateTimeParseException e) {
throw new ValidationError("Provided date format cannot be parsed into Remedy specific date format");
}
return parsed;
}
} }

View File

@ -4,6 +4,7 @@ import com.bmc.arsys.api.Constants;
import com.bmc.arsys.api.SortInfo; import com.bmc.arsys.api.SortInfo;
import com.nttdata.calender.api.Query; import com.nttdata.calender.api.Query;
import com.nttdata.calender.changes.Change; import com.nttdata.calender.changes.Change;
import com.nttdata.calender.errorhandling.ErrorTypes.ValidationError;
/** /**
* Defines the sort object needed for the retrieval of {@link Change}. * Defines the sort object needed for the retrieval of {@link Change}.
@ -58,7 +59,7 @@ public class Sort {
* the column * the column
* @return the constructed SortInfo object * @return the constructed SortInfo object
*/ */
public SortInfo getSortInfo(Query changeQuery) { public SortInfo getSortInfo(Query changeQuery) throws ValidationError {
var column = changeQuery.getFieldId(this.column); var column = changeQuery.getFieldId(this.column);
// TODO: handle default of sortOrder // TODO: handle default of sortOrder
int sortOrder = 0; int sortOrder = 0;
@ -70,6 +71,8 @@ public class Sort {
case "dsc": case "dsc":
sortOrder = Constants.AR_SORT_DESCENDING; sortOrder = Constants.AR_SORT_DESCENDING;
break; break;
default:
throw new ValidationError("Unknown sort order specified");
} }
return new SortInfo(column, sortOrder); return new SortInfo(column, sortOrder);

View File

@ -1,19 +1,17 @@
package com.nttdata.calender.errorhandling; package com.nttdata.calender.errorhandling.ErrorTypes;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
public class NotFoundError extends RuntimeException { public abstract class BackendError extends Exception {
private int errorCode; private int errorCode;
private HttpStatus httpStatus; private HttpStatus httpStatus;
public NotFoundError(String message) { public BackendError(String message, int errorCode, HttpStatus httpStatus) {
super(message); super(message);
this.errorCode = 404; this.errorCode = errorCode;
this.httpStatus = HttpStatus.NOT_FOUND; this.httpStatus = httpStatus;
} }
// Include getters for errorCode and httpStatus
public int getErrorCode() { public int getErrorCode() {
return errorCode; return errorCode;
} }

View File

@ -0,0 +1,9 @@
package com.nttdata.calender.errorhandling.ErrorTypes;
import org.springframework.http.HttpStatus;
public class NotFoundError extends BackendError {
public NotFoundError(String message) {
super(message, 404, HttpStatus.NOT_FOUND);
}
}

View File

@ -0,0 +1,11 @@
package com.nttdata.calender.errorhandling.ErrorTypes;
import org.springframework.http.HttpStatus;
public class ValidationError extends BackendError {
public ValidationError(String message) {
super(message, 400, HttpStatus.BAD_REQUEST);
}
}

View File

@ -10,6 +10,7 @@ import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ExceptionHandler;
import com.bmc.arsys.api.ARException; import com.bmc.arsys.api.ARException;
import com.nttdata.calender.errorhandling.ErrorTypes.BackendError;
@ControllerAdvice @ControllerAdvice
public class GlobalExceptionHandler { public class GlobalExceptionHandler {
@ -18,17 +19,24 @@ public class GlobalExceptionHandler {
@ExceptionHandler(ARException.class) @ExceptionHandler(ARException.class)
public ResponseEntity<ErrorResponse> handleARException(ARException e, HttpServletRequest request) { public ResponseEntity<ErrorResponse> handleARException(ARException e, HttpServletRequest request) {
var errorMessage = "Remedy server error: \n" + e.getMessage(); var errorMessage = "Remedy server error: \n" + e.getMessage();
var errorResponse = new ErrorResponse(errorMessage, e.getClass().getSimpleName()); return entityResponse(errorMessage, e, HttpStatus.INTERNAL_SERVER_ERROR);
errorLogger.error(errorMessage, e);
return new ResponseEntity<>(errorResponse, HttpStatus.INTERNAL_SERVER_ERROR);
} }
@ExceptionHandler(Exception.class) @ExceptionHandler(Exception.class)
public ResponseEntity<ErrorResponse> handleGenericException(Exception e, HttpServletRequest request) { public ResponseEntity<ErrorResponse> handleGenericException(Exception e, HttpServletRequest request) {
var errorMessage = "Backend internal server error: \n" + e.getMessage(); var errorMessage = "Backend internal server error: \n" + e.getMessage();
return entityResponse(errorMessage, e, HttpStatus.INTERNAL_SERVER_ERROR);
}
@ExceptionHandler(BackendError.class)
public ResponseEntity<ErrorResponse> handleBackendErrorException(BackendError e, HttpServletRequest request) {
var errorMessage = "Backend internal server error: \n" + e.getMessage();
return entityResponse(errorMessage, e, e.getHttpStatus());
}
private ResponseEntity<ErrorResponse> entityResponse(String errorMessage, Exception e, HttpStatus status) {
var errorResponse = new ErrorResponse(errorMessage, e.getClass().getSimpleName()); var errorResponse = new ErrorResponse(errorMessage, e.getClass().getSimpleName());
errorLogger.error(errorMessage, e); errorLogger.error(errorMessage, e);
return new ResponseEntity<>(errorResponse, HttpStatus.INTERNAL_SERVER_ERROR); return new ResponseEntity<>(errorResponse, status);
} }
} }