This is an automated email from the ASF dual-hosted git repository. arnold pushed a commit to branch develop in repository https://gitbox.apache.org/repos/asf/fineract.git
The following commit(s) were added to refs/heads/develop by this push: new 80bcb27b0 FINERACT-1921: BatchAPI - status code mismatch 80bcb27b0 is described below commit 80bcb27b0acf380bb00cf62053eeb04017fbe128 Author: jmarta <marta.jankov...@dpc.hu> AuthorDate: Mon Sep 25 07:28:32 2023 +0200 FINERACT-1921: BatchAPI - status code mismatch --- .../fineract/batch/exception/ErrorHandler.java | 12 ++++++-- .../batch/service/BatchApiServiceImpl.java | 15 +++++----- .../domain/CommandProcessingResultType.java | 11 ++++++++ .../commands/service/CommandWrapperBuilder.java | 1 - .../SynchronousCommandProcessingService.java | 32 ++++++++++------------ .../core/data/ApiGlobalErrorResponse.java | 5 ++-- .../IdempotentCommandProcessFailedException.java | 15 +++++----- .../IdempotentCommandProcessSucceedException.java | 7 +++-- ...tentCommandProcessUnderProcessingException.java | 4 +-- .../ConcurrencyFailureExceptionMapper.java | 7 +++-- .../IdempotentCommandExceptionMapper.java | 6 ++-- .../OptimisticLockExceptionMapper.java | 7 +++-- ...empotencyCommandProcessFailedExceptionTest.java | 2 +- .../CreateDatatableEntryCommandStrategy.java | 22 ++++----------- .../service/ReadWriteNonCoreDataServiceImpl.java | 16 +++++------ .../SavingsAccountTransactionTest.java | 14 +++++----- 16 files changed, 93 insertions(+), 83 deletions(-) diff --git a/fineract-core/src/main/java/org/apache/fineract/batch/exception/ErrorHandler.java b/fineract-core/src/main/java/org/apache/fineract/batch/exception/ErrorHandler.java index 6bf566fea..0f3491120 100644 --- a/fineract-core/src/main/java/org/apache/fineract/batch/exception/ErrorHandler.java +++ b/fineract-core/src/main/java/org/apache/fineract/batch/exception/ErrorHandler.java @@ -76,10 +76,14 @@ public final class ErrorHandler { Set<String> exceptionMappers = createSet(ctx.getBeanNamesForType(forClassWithGenerics(ExceptionMapper.class, clazz))); Set<String> fineractErrorMappers = createSet(ctx.getBeanNamesForType(FineractExceptionMapper.class)); SetUtils.SetView<String> intersection = SetUtils.intersection(exceptionMappers, fineractErrorMappers); - if (intersection.size() > 0) { + if (!intersection.isEmpty()) { // noinspection unchecked return (ExceptionMapper<T>) ctx.getBean(intersection.iterator().next()); } + if (!exceptionMappers.isEmpty()) { + // noinspection unchecked + return (ExceptionMapper<T>) ctx.getBean(exceptionMappers.iterator().next()); + } clazz = clazz.getSuperclass(); } while (!clazz.equals(Exception.class)); // noinspection unchecked @@ -98,8 +102,10 @@ public final class ErrorHandler { MultivaluedMap<String, Object> headers = response.getHeaders(); Set<Header> batchHeaders = headers == null ? null : headers.keySet().stream().map(e -> new Header(e, response.getHeaderString(e))).collect(Collectors.toSet()); - return new ErrorInfo(response.getStatus(), ((FineractExceptionMapper) exceptionMapper).errorCode(), - JSON_HELPER.toJson(response.getEntity()), batchHeaders); + Integer errorCode = exceptionMapper instanceof FineractExceptionMapper ? ((FineractExceptionMapper) exceptionMapper).errorCode() + : null; + Object msg = response.getEntity(); + return new ErrorInfo(response.getStatus(), errorCode, msg instanceof String ? (String) msg : JSON_HELPER.toJson(msg), batchHeaders); } public RuntimeException getMappable(@NotNull Throwable thr) { diff --git a/fineract-core/src/main/java/org/apache/fineract/batch/service/BatchApiServiceImpl.java b/fineract-core/src/main/java/org/apache/fineract/batch/service/BatchApiServiceImpl.java index c23dce152..834002fe0 100644 --- a/fineract-core/src/main/java/org/apache/fineract/batch/service/BatchApiServiceImpl.java +++ b/fineract-core/src/main/java/org/apache/fineract/batch/service/BatchApiServiceImpl.java @@ -223,7 +223,7 @@ public class BatchApiServiceImpl implements BatchApiService { callRequestRecursive(resolvedChildRequest, childNode, responseList, uriInfo, enclosingTransaction); }); } else { - responseList.addAll(parentRequestFailedRecursive(request, requestNode, response, true)); + responseList.addAll(parentRequestFailedRecursive(request, requestNode, response, null)); } // If the current request fails, then all the child requests are not executed. If we want to write out all the // child requests, here is the place. @@ -296,16 +296,17 @@ public class BatchApiServiceImpl implements BatchApiService { * the current request node * @return {@code BatchResponse} list of the generated batch responses */ - private List<BatchResponse> parentRequestFailedRecursive(BatchRequest request, BatchRequestNode requestNode, BatchResponse response, - boolean root) { + private List<BatchResponse> parentRequestFailedRecursive(@NotNull BatchRequest request, @NotNull BatchRequestNode requestNode, + @NotNull BatchResponse response, Long parentId) { List<BatchResponse> responseList = new ArrayList<>(); - if (root) { + if (parentId == null) { // root BatchRequestContextHolder.getEnclosingTransaction().ifPresent(TransactionExecution::setRollbackOnly); } else { - responseList.add(buildErrorResponse(request.getRequestId(), response.getStatusCode(), response.getBody(), null)); + responseList.add(buildErrorResponse(request.getRequestId(), response.getStatusCode(), + "Parent request with id " + parentId + " was erroneous!", null)); } - requestNode.getChildNodes().forEach( - childNode -> responseList.addAll(parentRequestFailedRecursive(childNode.getRequest(), childNode, response, false))); + requestNode.getChildNodes().forEach(childNode -> responseList + .addAll(parentRequestFailedRecursive(childNode.getRequest(), childNode, response, request.getRequestId()))); return responseList; } diff --git a/fineract-core/src/main/java/org/apache/fineract/commands/domain/CommandProcessingResultType.java b/fineract-core/src/main/java/org/apache/fineract/commands/domain/CommandProcessingResultType.java index 770f579d0..299c1a0e2 100644 --- a/fineract-core/src/main/java/org/apache/fineract/commands/domain/CommandProcessingResultType.java +++ b/fineract-core/src/main/java/org/apache/fineract/commands/domain/CommandProcessingResultType.java @@ -18,6 +18,9 @@ */ package org.apache.fineract.commands.domain; +import java.util.Arrays; +import java.util.Map; +import java.util.stream.Collectors; import lombok.Getter; import lombok.RequiredArgsConstructor; @@ -32,6 +35,14 @@ public enum CommandProcessingResultType { UNDER_PROCESSING(4, "commandProcessingResultType.underProcessing"), // ERROR(5, "commandProcessingResultType.error"); + private static final Map<Integer, CommandProcessingResultType> BY_ID = Arrays.stream(values()) + .collect(Collectors.toMap(CommandProcessingResultType::getValue, v -> v)); + private final Integer value; private final String code; + + public static CommandProcessingResultType fromInt(final Integer value) { + CommandProcessingResultType transactionType = BY_ID.get(value); + return transactionType == null ? INVALID : transactionType; + } } diff --git a/fineract-core/src/main/java/org/apache/fineract/commands/service/CommandWrapperBuilder.java b/fineract-core/src/main/java/org/apache/fineract/commands/service/CommandWrapperBuilder.java index 08af2792f..22fcc7237 100644 --- a/fineract-core/src/main/java/org/apache/fineract/commands/service/CommandWrapperBuilder.java +++ b/fineract-core/src/main/java/org/apache/fineract/commands/service/CommandWrapperBuilder.java @@ -737,7 +737,6 @@ public class CommandWrapperBuilder { } private void commonDatatableSettings(final String datatable, final Long apptableId, final Long datatableId) { - this.entityName = datatable; this.entityId = apptableId; this.subentityId = datatableId; diff --git a/fineract-core/src/main/java/org/apache/fineract/commands/service/SynchronousCommandProcessingService.java b/fineract-core/src/main/java/org/apache/fineract/commands/service/SynchronousCommandProcessingService.java index 3eff8ba55..e45814a91 100644 --- a/fineract-core/src/main/java/org/apache/fineract/commands/service/SynchronousCommandProcessingService.java +++ b/fineract-core/src/main/java/org/apache/fineract/commands/service/SynchronousCommandProcessingService.java @@ -30,7 +30,6 @@ import java.lang.reflect.Type; import java.time.Instant; import java.util.HashMap; import java.util.Map; -import java.util.function.Function; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.fineract.batch.exception.ErrorHandler; @@ -48,7 +47,6 @@ import org.apache.fineract.infrastructure.core.data.CommandProcessingResult; import org.apache.fineract.infrastructure.core.data.CommandProcessingResultBuilder; import org.apache.fineract.infrastructure.core.domain.BatchRequestContextHolder; import org.apache.fineract.infrastructure.core.domain.FineractRequestContextHolder; -import org.apache.fineract.infrastructure.core.exception.AbstractIdempotentCommandException; import org.apache.fineract.infrastructure.core.exception.IdempotentCommandProcessFailedException; import org.apache.fineract.infrastructure.core.exception.IdempotentCommandProcessSucceedException; import org.apache.fineract.infrastructure.core.exception.IdempotentCommandProcessUnderProcessingException; @@ -174,23 +172,21 @@ public class SynchronousCommandProcessingService implements CommandProcessingSer } private void exceptionWhenTheRequestAlreadyProcessed(CommandWrapper wrapper, String idempotencyKey, boolean retry) { - CommandSource existingCommand = commandSourceService.findCommandSource(wrapper, idempotencyKey); - if (existingCommand != null) { - idempotentExceptionByStatus(UNDER_PROCESSING, existingCommand, - command -> new IdempotentCommandProcessUnderProcessingException(wrapper)); - if (!retry) { - idempotentExceptionByStatus(ERROR, existingCommand, - command -> new IdempotentCommandProcessFailedException(wrapper, command)); - } - idempotentExceptionByStatus(PROCESSED, existingCommand, - command -> new IdempotentCommandProcessSucceedException(wrapper, command.getResult(), command.getResultStatusCode())); + CommandSource command = commandSourceService.findCommandSource(wrapper, idempotencyKey); + if (command == null) { + return; } - } - - private void idempotentExceptionByStatus(CommandProcessingResultType status, CommandSource command, - Function<CommandSource, AbstractIdempotentCommandException> exceptionMapper) { - if (status.getValue().equals(command.getStatus())) { - throw exceptionMapper.apply(command); + CommandProcessingResultType status = CommandProcessingResultType.fromInt(command.getStatus()); + switch (status) { + case UNDER_PROCESSING -> throw new IdempotentCommandProcessUnderProcessingException(wrapper, idempotencyKey); + case PROCESSED -> throw new IdempotentCommandProcessSucceedException(wrapper, idempotencyKey, command); + case ERROR -> { + if (!retry) { + throw new IdempotentCommandProcessFailedException(wrapper, idempotencyKey, command); + } + } + default -> { + } } } diff --git a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/data/ApiGlobalErrorResponse.java b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/data/ApiGlobalErrorResponse.java index e2ed84968..259f8dfd4 100644 --- a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/data/ApiGlobalErrorResponse.java +++ b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/data/ApiGlobalErrorResponse.java @@ -23,6 +23,7 @@ import static org.apache.http.HttpStatus.SC_BAD_REQUEST; import static org.apache.http.HttpStatus.SC_CONFLICT; import static org.apache.http.HttpStatus.SC_FORBIDDEN; import static org.apache.http.HttpStatus.SC_INTERNAL_SERVER_ERROR; +import static org.apache.http.HttpStatus.SC_LOCKED; import static org.apache.http.HttpStatus.SC_METHOD_NOT_ALLOWED; import static org.apache.http.HttpStatus.SC_NOT_FOUND; import static org.apache.http.HttpStatus.SC_SERVICE_UNAVAILABLE; @@ -106,7 +107,7 @@ public class ApiGlobalErrorResponse { return create(SC_CONFLICT, "error.msg.loan.locked", msg, msg); } - public static ApiGlobalErrorResponse conflict(String type, String identifier) { + public static ApiGlobalErrorResponse locked(String type, String identifier) { String details = ""; if (type == null) { type = "unknown"; @@ -117,7 +118,7 @@ public class ApiGlobalErrorResponse { details += " [" + identifier + ']'; } String msg = "The server is currently unable to handle the request due to concurrent modification" + details + ", please try again"; - return create(SC_CONFLICT, "error.msg.platform.service." + type + ".conflict", msg, msg); + return create(SC_LOCKED, "error.msg.platform.service." + type + ".conflict", msg, msg); } public static ApiGlobalErrorResponse unAuthorized(final String defaultUserMessage) { diff --git a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/exception/IdempotentCommandProcessFailedException.java b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/exception/IdempotentCommandProcessFailedException.java index a08b2d9b9..0ea52b8fb 100644 --- a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/exception/IdempotentCommandProcessFailedException.java +++ b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/exception/IdempotentCommandProcessFailedException.java @@ -18,6 +18,9 @@ */ package org.apache.fineract.infrastructure.core.exception; +import static org.apache.http.HttpStatus.SC_INTERNAL_SERVER_ERROR; + +import jakarta.validation.constraints.NotNull; import org.apache.fineract.commands.domain.CommandSource; import org.apache.fineract.commands.domain.CommandWrapper; @@ -28,16 +31,14 @@ public class IdempotentCommandProcessFailedException extends AbstractIdempotentC private final Integer statusCode; - public IdempotentCommandProcessFailedException(CommandWrapper wrapper, CommandSource commandSource) { - super(wrapper.actionName(), wrapper.entityName(), wrapper.getIdempotencyKey(), commandSource.getResult()); - this.statusCode = commandSource.getResultStatusCode(); + public IdempotentCommandProcessFailedException(CommandWrapper wrapper, String idempotencyKey, CommandSource command) { + super(wrapper.actionName(), wrapper.actionName(), idempotencyKey, command.getResult()); + this.statusCode = command.getResultStatusCode(); } + @NotNull public Integer getStatusCode() { // If the database inconsistent we return http 500 instead of null pointer exception - if (statusCode == null) { - return 500; - } - return statusCode; + return statusCode == null ? SC_INTERNAL_SERVER_ERROR : statusCode; } } diff --git a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/exception/IdempotentCommandProcessSucceedException.java b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/exception/IdempotentCommandProcessSucceedException.java index d7437275b..0542b8b0d 100644 --- a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/exception/IdempotentCommandProcessSucceedException.java +++ b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/exception/IdempotentCommandProcessSucceedException.java @@ -18,6 +18,7 @@ */ package org.apache.fineract.infrastructure.core.exception; +import org.apache.fineract.commands.domain.CommandSource; import org.apache.fineract.commands.domain.CommandWrapper; /** @@ -27,9 +28,9 @@ public class IdempotentCommandProcessSucceedException extends AbstractIdempotent private final Integer statusCode; - public IdempotentCommandProcessSucceedException(CommandWrapper wrapper, String response, Integer statusCode) { - super(wrapper.actionName(), wrapper.entityName(), wrapper.getIdempotencyKey(), response); - this.statusCode = statusCode; + public IdempotentCommandProcessSucceedException(CommandWrapper wrapper, String idempotencyKey, CommandSource command) { + super(wrapper.actionName(), wrapper.entityName(), idempotencyKey, command.getResult()); + this.statusCode = command.getResultStatusCode(); } public Integer getStatusCode() { diff --git a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/exception/IdempotentCommandProcessUnderProcessingException.java b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/exception/IdempotentCommandProcessUnderProcessingException.java index 4e6b3f611..7e608e4be 100644 --- a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/exception/IdempotentCommandProcessUnderProcessingException.java +++ b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/exception/IdempotentCommandProcessUnderProcessingException.java @@ -25,7 +25,7 @@ import org.apache.fineract.commands.domain.CommandWrapper; */ public class IdempotentCommandProcessUnderProcessingException extends AbstractIdempotentCommandException { - public IdempotentCommandProcessUnderProcessingException(CommandWrapper wrapper) { - super(wrapper.actionName(), wrapper.entityName(), wrapper.getIdempotencyKey(), wrapper.getJson()); + public IdempotentCommandProcessUnderProcessingException(CommandWrapper wrapper, String idempotencyKey) { + super(wrapper.actionName(), wrapper.entityName(), idempotencyKey, wrapper.getJson()); } } diff --git a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/exceptionmapper/ConcurrencyFailureExceptionMapper.java b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/exceptionmapper/ConcurrencyFailureExceptionMapper.java index 41d7b6d85..665a3ef33 100644 --- a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/exceptionmapper/ConcurrencyFailureExceptionMapper.java +++ b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/exceptionmapper/ConcurrencyFailureExceptionMapper.java @@ -18,9 +18,10 @@ */ package org.apache.fineract.infrastructure.core.exceptionmapper; +import static org.apache.http.HttpStatus.SC_LOCKED; + import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.Response; -import jakarta.ws.rs.core.Response.Status; import jakarta.ws.rs.ext.ExceptionMapper; import jakarta.ws.rs.ext.Provider; import lombok.extern.slf4j.Slf4j; @@ -49,8 +50,8 @@ public class ConcurrencyFailureExceptionMapper implements FineractExceptionMappe type = olex.getPersistentClassName(); identifier = olex.getIdentifier() == null ? null : String.valueOf(olex.getIdentifier()); } - final ApiGlobalErrorResponse dataIntegrityError = ApiGlobalErrorResponse.conflict(type, identifier); - return Response.status(Status.CONFLICT).entity(dataIntegrityError).type(MediaType.APPLICATION_JSON).build(); + final ApiGlobalErrorResponse dataIntegrityError = ApiGlobalErrorResponse.locked(type, identifier); + return Response.status(SC_LOCKED).entity(dataIntegrityError).type(MediaType.APPLICATION_JSON).build(); } @Override diff --git a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/exceptionmapper/IdempotentCommandExceptionMapper.java b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/exceptionmapper/IdempotentCommandExceptionMapper.java index 5bc1846d3..4facc0976 100644 --- a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/exceptionmapper/IdempotentCommandExceptionMapper.java +++ b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/exceptionmapper/IdempotentCommandExceptionMapper.java @@ -48,8 +48,10 @@ public class IdempotentCommandExceptionMapper implements FineractExceptionMapper log.warn("Processing {} request: {}", exception.getClass().getName(), exception.getMessage()); Status status = null; if (exception instanceof IdempotentCommandProcessSucceedException pse) { - status = Status.fromStatusCode(pse.getStatusCode()); - } else if (exception instanceof IdempotentCommandProcessUnderProcessingException) { + Integer statusCode = pse.getStatusCode(); + status = statusCode == null ? Status.OK : Status.fromStatusCode(statusCode); + } + if (exception instanceof IdempotentCommandProcessUnderProcessingException) { status = Status.CONFLICT; } else if (exception instanceof IdempotentCommandProcessFailedException pfe) { status = Status.fromStatusCode(pfe.getStatusCode()); diff --git a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/exceptionmapper/OptimisticLockExceptionMapper.java b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/exceptionmapper/OptimisticLockExceptionMapper.java index 5b1ee011a..b4af9e3ff 100644 --- a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/exceptionmapper/OptimisticLockExceptionMapper.java +++ b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/exceptionmapper/OptimisticLockExceptionMapper.java @@ -18,9 +18,10 @@ */ package org.apache.fineract.infrastructure.core.exceptionmapper; +import static org.apache.http.HttpStatus.SC_LOCKED; + import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.Response; -import jakarta.ws.rs.core.Response.Status; import jakarta.ws.rs.ext.ExceptionMapper; import jakarta.ws.rs.ext.Provider; import lombok.extern.slf4j.Slf4j; @@ -45,8 +46,8 @@ public class OptimisticLockExceptionMapper implements FineractExceptionMapper, E log.warn("Exception: {}, Message: {}", exception.getClass().getName(), exception.getMessage()); String type = exception.getQuery() == null ? "unknown" : "query"; String identifier = "unknown"; - final ApiGlobalErrorResponse dataIntegrityError = ApiGlobalErrorResponse.conflict(type, identifier); - return Response.status(Status.CONFLICT).entity(dataIntegrityError).type(MediaType.APPLICATION_JSON).build(); + final ApiGlobalErrorResponse dataIntegrityError = ApiGlobalErrorResponse.locked(type, identifier); + return Response.status(SC_LOCKED).entity(dataIntegrityError).type(MediaType.APPLICATION_JSON).build(); } @Override diff --git a/fineract-core/src/test/java/org/apache/fineract/infrastructure/core/exception/IdempotencyCommandProcessFailedExceptionTest.java b/fineract-core/src/test/java/org/apache/fineract/infrastructure/core/exception/IdempotencyCommandProcessFailedExceptionTest.java index dc7ab739a..91e4095a1 100644 --- a/fineract-core/src/test/java/org/apache/fineract/infrastructure/core/exception/IdempotencyCommandProcessFailedExceptionTest.java +++ b/fineract-core/src/test/java/org/apache/fineract/infrastructure/core/exception/IdempotencyCommandProcessFailedExceptionTest.java @@ -54,7 +54,7 @@ public class IdempotencyCommandProcessFailedExceptionTest { CommandWrapper command = new CommandWrapper(null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null); CommandSource source = CommandSource.fullEntryFrom(command, JsonCommand.from("{}"), null, "dummy-key", null); - IdempotentCommandProcessFailedException exception = new IdempotentCommandProcessFailedException(command, source); + IdempotentCommandProcessFailedException exception = new IdempotentCommandProcessFailedException(command, null, source); Response result = mapper.toResponse(exception); assertEquals(500, result.getStatus()); assertEquals("true", result.getHeaderString(IDEMPOTENT_CACHE_HEADER)); diff --git a/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/CreateDatatableEntryCommandStrategy.java b/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/CreateDatatableEntryCommandStrategy.java index c6f69a0b4..b37c7d749 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/CreateDatatableEntryCommandStrategy.java +++ b/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/CreateDatatableEntryCommandStrategy.java @@ -48,27 +48,17 @@ public class CreateDatatableEntryCommandStrategy implements CommandStrategy { @Override public BatchResponse execute(BatchRequest request, @SuppressWarnings("unused") UriInfo uriInfo) { - - final BatchResponse response = new BatchResponse(); - final String responseBody; - - response.setRequestId(request.getRequestId()); - response.setHeaders(request.getHeaders()); - final List<String> pathParameters = Splitter.on('/').splitToList(relativeUrlWithoutVersion(request)); // Pluck out the datatable name & loanId out of the relative path final String datatableName = pathParameters.get(1); final Long loanId = Long.parseLong(pathParameters.get(2)); - // Calls 'createDatatableEntry' function from - // 'DatatablesApiResource' to create a datatable entry on an existing loan - responseBody = datatablesApiResource.createDatatableEntry(datatableName, loanId, request.getBody()); - - response.setStatusCode(HttpStatus.SC_OK); - // Sets the body of the response after datatable entry is successfully - // created - response.setBody(responseBody); + // Calls 'createDatatableEntry' function from 'DatatablesApiResource' to create a datatable entry on an existing + // loan + final String responseBody = datatablesApiResource.createDatatableEntry(datatableName, loanId, request.getBody()); - return response; + // Create the response after datatable entry is successfully created + return new BatchResponse().setRequestId(request.getRequestId()).setStatusCode(HttpStatus.SC_OK).setBody(responseBody) + .setHeaders(request.getHeaders()); } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/service/ReadWriteNonCoreDataServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/service/ReadWriteNonCoreDataServiceImpl.java index a5ccb9331..2ff1f24f0 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/service/ReadWriteNonCoreDataServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/service/ReadWriteNonCoreDataServiceImpl.java @@ -1587,13 +1587,13 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ if (!rs.next()) { throw new DatatableNotFoundException(entityTable, appTableId); } - final Long officeId = rs.getLong("officeId"); - final Long groupId = rs.getLong("groupId"); - final Long clientId = rs.getLong("clientId"); - final Long savingsId = rs.getLong("savingsId"); - final Long loanId = rs.getLong("loanId"); - final Long transactionId = rs.getLong("transactionId"); - final Long entityId = rs.getLong("entityId"); + final Long officeId = (Long) rs.getObject("officeId"); + final Long groupId = (Long) rs.getObject("groupId"); + final Long clientId = (Long) rs.getObject("clientId"); + final Long savingsId = (Long) rs.getObject("savingsId"); + final Long loanId = (Long) rs.getObject("loanId"); + final Long transactionId = (Long) rs.getObject("transactionId"); + final Long entityId = (Long) rs.getObject("entityId"); if (rs.next()) { throw new DatatableSystemErrorException("System Error: More than one row returned from data scoping query"); @@ -1604,7 +1604,7 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ .withGroupId(groupId) // .withClientId(clientId) // .withSavingsId(savingsId) // - .withLoanId(loanId).withTransactionId(String.valueOf(transactionId)).withEntityId(entityId)// + .withLoanId(loanId).withTransactionId(transactionId == null ? null : String.valueOf(transactionId)).withEntityId(entityId)// .build(); } diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/SavingsAccountTransactionTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/SavingsAccountTransactionTest.java index 057b19335..6523a6eba 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/SavingsAccountTransactionTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/SavingsAccountTransactionTest.java @@ -20,8 +20,8 @@ package org.apache.fineract.integrationtests; import static org.apache.fineract.integrationtests.common.savings.SavingsAccountHelper.PAYMENT_TYPE_ID; import static org.apache.fineract.integrationtests.common.system.DatatableHelper.addDatatableColumn; -import static org.apache.http.HttpStatus.SC_CONFLICT; import static org.apache.http.HttpStatus.SC_FORBIDDEN; +import static org.apache.http.HttpStatus.SC_LOCKED; import static org.apache.http.HttpStatus.SC_OK; import static org.hamcrest.Matchers.anyOf; import static org.hamcrest.Matchers.is; @@ -95,7 +95,7 @@ public class SavingsAccountTransactionTest { this.requestSpec = new RequestSpecBuilder().setContentType(ContentType.JSON).build(); this.requestSpec.header("Authorization", "Basic " + Utils.loginIntoServerAndGetBase64EncodedAuthenticationKey()); this.responseSpec = new ResponseSpecBuilder().expectStatusCode(SC_OK).build(); - this.concurrentResponseSpec = new ResponseSpecBuilder().expectStatusCode(anyOf(is(SC_OK), is(SC_CONFLICT))).build(); + this.concurrentResponseSpec = new ResponseSpecBuilder().expectStatusCode(anyOf(is(SC_OK), is(SC_LOCKED))).build(); this.savingsAccountHelper = new SavingsAccountHelper(this.requestSpec, this.responseSpec); this.savingsProductHelper = new SavingsProductHelper(); this.datatableHelper = new DatatableHelper(this.requestSpec, this.responseSpec); @@ -189,7 +189,7 @@ public class SavingsAccountTransactionTest { SavingsAccountHelper batchWithTransactionHelper = new SavingsAccountHelper(requestSpec, concurrentResponseSpec); SavingsAccountHelper batchWithoutTransactionHelper = new SavingsAccountHelper(requestSpec, - new ResponseSpecBuilder().expectStatusCode(anyOf(is(SC_OK), is(SC_CONFLICT), is(SC_FORBIDDEN))).build()); + new ResponseSpecBuilder().expectStatusCode(anyOf(is(SC_OK), is(SC_LOCKED), is(SC_FORBIDDEN))).build()); String transactionDate = SavingsAccountHelper.TRANSACTION_DATE; String transactionAmount = "10"; ExecutorService executor = Executors.newFixedThreadPool(30); @@ -322,7 +322,7 @@ public class SavingsAccountTransactionTest { if (enclosingTransaction) { Integer statusCode1 = responses.get(0).getStatusCode(); assertNotNull(statusCode1); - assertTrue(SC_OK == statusCode1 || SC_CONFLICT == statusCode1); + assertTrue(SC_OK == statusCode1 || SC_LOCKED == statusCode1); if (SC_OK == statusCode1) { assertEquals(4, responses.size()); Integer statusCode4 = responses.get(3).getStatusCode(); @@ -335,10 +335,10 @@ public class SavingsAccountTransactionTest { assertEquals(4, responses.size()); Integer statusCode1 = responses.get(0).getStatusCode(); assertNotNull(statusCode1); - assertTrue(SC_OK == statusCode1 || SC_CONFLICT == statusCode1); + assertTrue(SC_OK == statusCode1 || SC_LOCKED == statusCode1); Integer statusCode4 = responses.get(3).getStatusCode(); assertNotNull(statusCode4); - assertTrue(SC_OK == statusCode1 ? (SC_OK == statusCode4 || SC_CONFLICT == statusCode4) : SC_FORBIDDEN == statusCode4); + assertTrue(SC_OK == statusCode1 ? (SC_OK == statusCode4 || SC_LOCKED == statusCode4) : SC_FORBIDDEN == statusCode4); } } else { String json = transactionData.getJson(); @@ -359,7 +359,7 @@ public class SavingsAccountTransactionTest { assertNotNull(res.get(CommonConstants.RESPONSE_RESOURCE_ID)); return true; } - assertEquals(String.valueOf(SC_CONFLICT), statusCode); + assertEquals(String.valueOf(SC_LOCKED), statusCode); return false; } }