diff --git a/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/BatchApiTest.java b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/BatchApiTest.java index 2a2f16c6e..5c4ea5579 100644 --- a/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/BatchApiTest.java +++ b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/BatchApiTest.java @@ -24,9 +24,10 @@ import com.jayway.restassured.specification.RequestSpecification; import com.jayway.restassured.specification.ResponseSpecification; /** - * Test class for {@link org.mifosplatform.batch.command.CommandStrategyProvider}. - * This tests the response provided by commandStrategy by injecting it with - * a {@code BatchRequest}. + * Test class for + * {@link org.mifosplatform.batch.command.CommandStrategyProvider}. This tests + * the response provided by commandStrategy by injecting it with a + * {@code BatchRequest}. * * @author RishabhShukla * @@ -35,231 +36,280 @@ import com.jayway.restassured.specification.ResponseSpecification; */ public class BatchApiTest { - private ResponseSpecification responseSpec; - private RequestSpecification requestSpec; - - public BatchApiTest() { - super(); - } - - /** - * Sets up the essential settings for the TEST like contentType, expectedStatusCode. - * It uses the '@Before' annotation provided by jUnit. - */ - @Before - public void setup() { - - Utils.initializeRESTAssured(); - this.requestSpec = new RequestSpecBuilder().setContentType(ContentType.JSON).build(); - this.requestSpec.header("Authorization", "Basic " + Utils.loginIntoServerAndGetBase64EncodedAuthenticationKey()); - this.responseSpec = new ResponseSpecBuilder().expectStatusCode(200).build(); - } - - /** - * Tests for the unimplemented command Strategies by returning 501 status code. - * For a unknownRequest a statusCode 501 is returned back with response. - * - * @see org.mifosplatform.batch.command.internal.UnknownCommandStrategy - */ - @Test - public void shouldReturnStatusNotImplementedUnknownCommand() { + private ResponseSpecification responseSpec; + private RequestSpecification requestSpec; - final BatchRequest br = new BatchRequest(); - br.setRequestId(4711L); - br.setRelativeUrl("/nirvana"); - br.setMethod("POST"); + public BatchApiTest() { + super(); + } - final List response = BatchHelper.postWithSingleRequest(this.requestSpec, this.responseSpec, br); + /** + * Sets up the essential settings for the TEST like contentType, + * expectedStatusCode. It uses the '@Before' annotation provided by jUnit. + */ + @Before + public void setup() { - //Verify that only 501 is returned as the status code - for(BatchResponse resp : response) { - Assert.assertEquals("Verifying Status code 501",(long) 501,(long) resp.getStatusCode()); - } - } - - /** - * Tests for the successful response for a createClient request from createClientCommand. - * A successful response with statusCode '200' is returned back. - * - * @see org.mifosplatform.batch.command.internal.CreateClientCommandStrategy - */ - @Test - public void shouldReturnOkStatusForCreateClientCommand() { - - final BatchRequest br = BatchHelper.createClientRequest(4712L, ""); - - final List response = BatchHelper.postWithSingleRequest(this.requestSpec, this.responseSpec, br); - - //Verify that a 200 response is returned as the status code - for(BatchResponse resp : response) { - Assert.assertEquals("Verifying Status code 200",(long) 200,(long) resp.getStatusCode()); - } - } - - /** - * Tests for an erroneous response with statusCode '501' if transaction fails. - * If Query Parameter 'enclosingTransaction' is set to 'true' and if one of the - * request in BatchRequest fails then all transactions are rolled back. - * - * @see org.mifosplatform.batch.command.internal.CreateClientCommandStrategy - * @see org.mifosplatform.batch.api.BatchApiResource - * @see org.mifosplatform.batch.service.BatchApiService - */ - @Test - public void shouldRollBackAllTransactionsOnFailure() { - - //Create first client request - final BatchRequest br1 = BatchHelper.createClientRequest(4713L, "TestExtId11"); - - //Create second client request - final BatchRequest br2 = BatchHelper.createClientRequest(4714L, "TestExtId12"); - - //Create third client request, having same externalID as second client, hence cause of error - final BatchRequest br3 = BatchHelper.createClientRequest(4715L, "TestExtId11"); - - final List batchRequests = new ArrayList<>(); - - batchRequests.add(br1); - batchRequests.add(br2); - batchRequests.add(br3); - - final String jsonifiedRequest = BatchHelper.toJsonString(batchRequests); - final List response = BatchHelper.postBatchRequestsWithEnclosingTransaction(this.requestSpec, - this.responseSpec, jsonifiedRequest); - - //Verifies that none of the client in BatchRequest is created on the server - BatchHelper.verifyClientCreatedOnServer(this.requestSpec, this.responseSpec, "TestExtId11"); - BatchHelper.verifyClientCreatedOnServer(this.requestSpec, this.responseSpec, "TestExtId12"); - - //Asserts that all the transactions have been successfully rolled back - Assert.assertEquals(response.size(), 1); - Assert.assertEquals("Verifying Status code 400",(long) 400,(long) response.get(0).getStatusCode()); - } - - /** - * Tests that a client information was successfully updated through updateClientCommand. - * A 'changes' parameter is returned in the response after successful update of client - * information. - * - * @see org.mifosplatform.batch.command.internal.UpdateClientCommandStrategy - */ - @Test - public void shouldReflectChangesOnClientUpdate() { - - //Create a createClient Request - final BatchRequest br1 = BatchHelper.createClientRequest(4716L, ""); - - //Create a clientUpdate Request - final BatchRequest br2 = BatchHelper.updateClientRequest(4717L, 4716L); + Utils.initializeRESTAssured(); + this.requestSpec = new RequestSpecBuilder().setContentType(ContentType.JSON).build(); + this.requestSpec.header("Authorization", "Basic " + Utils.loginIntoServerAndGetBase64EncodedAuthenticationKey()); + this.responseSpec = new ResponseSpecBuilder().expectStatusCode(200).build(); + } - final List batchRequests = new ArrayList<>(); - - batchRequests.add(br1); - batchRequests.add(br2); - - final String jsonifiedRequest = BatchHelper.toJsonString(batchRequests); + /** + * Tests for the unimplemented command Strategies by returning 501 status + * code. For a unknownRequest a statusCode 501 is returned back with + * response. + * + * @see org.mifosplatform.batch.command.internal.UnknownCommandStrategy + */ + @Test + public void shouldReturnStatusNotImplementedUnknownCommand() { - final List response = BatchHelper.postBatchRequestsWithoutEnclosingTransaction(this.requestSpec, - this.responseSpec, jsonifiedRequest); - - //Get the changes parameter from updateClient Response - final JsonObject changes = new FromJsonHelper().parse(response.get(1).getBody()) - .getAsJsonObject().get("changes").getAsJsonObject(); - - //Asserts the client information is successfully updated - Assert.assertEquals("Firstname updated", "TestFirstName",changes.get("firstname").getAsString()); - Assert.assertEquals("Lastname updated", "TestLastName", changes.get("lastname").getAsString()); - } - - /** - * Tests that a ApplyLoanCommand was successfully executed and returned a 200(OK) - * status. It creates a new client and apply a loan to that client. This also - * verifies the successful resolution of dependencies among two requests. - * - * @see org.mifosplatform.batch.command.internal.ApplyLoanCommandStrategy - */ - @Test - public void shouldReturnOkStatusForApplyLoanCommand(){ + final BatchRequest br = new BatchRequest(); + br.setRequestId(4711L); + br.setRelativeUrl("/nirvana"); + br.setMethod("POST"); - final String loanProductJSON = new LoanProductTestBuilder() // - .withPrincipal("10000000.00") // - .withNumberOfRepayments("24") // - .withRepaymentAfterEvery("1") // - .withRepaymentTypeAsMonth() // - .withinterestRatePerPeriod("2") // - .withInterestRateFrequencyTypeAsMonths() // - .withAmortizationTypeAsEqualPrincipalPayment() // - .withInterestTypeAsDecliningBalance() // - .currencyDetails("0", "100").build(null); - - final Integer productId = new LoanTransactionHelper(this.requestSpec, this.responseSpec) - .getLoanProductId(loanProductJSON); - - //Create a createClient Request - final BatchRequest br1 = BatchHelper.createClientRequest(4718L, ""); - - //Create a ApplyLoan Request - final BatchRequest br2 = BatchHelper.applyLoanRequest(4719L, 4718L, productId); + final List response = BatchHelper.postWithSingleRequest(this.requestSpec, this.responseSpec, br); - final List batchRequests = new ArrayList<>(); - - batchRequests.add(br1); - batchRequests.add(br2); - - final String jsonifiedRequest = BatchHelper.toJsonString(batchRequests); + // Verify that only 501 is returned as the status code + for (BatchResponse resp : response) { + Assert.assertEquals("Verify Status code 501", (long) 501, (long) resp.getStatusCode()); + } + } - final List response = BatchHelper.postBatchRequestsWithoutEnclosingTransaction(this.requestSpec, - this.responseSpec, jsonifiedRequest); - - //Get the clientId parameter from createClient Response - final JsonElement clientId = new FromJsonHelper().parse(response.get(0).getBody()) - .getAsJsonObject().get("clientId"); - - Assert.assertEquals("Loan Successfully applied to client " + clientId.getAsString(), - 200L, (long) response.get(1).getStatusCode()); - } - - /** - * Tests that a new savings accounts was applied to an existing client and a - * 200(OK) status was returned. It first creates a new client and a savings product, - * then uses the cliendId and ProductId to apply a savings account. - * - * @see org.mifosplatform.batch.command.internal.ApplySavingsCommandStrategy - */ - @Test - public void shouldReturnOkStatusForApplySavingsCommand(){ - - final SavingsProductHelper savingsProductHelper = new SavingsProductHelper(); + /** + * Tests for the successful response for a createClient request from + * createClientCommand. A successful response with statusCode '200' is + * returned back. + * + * @see org.mifosplatform.batch.command.internal.CreateClientCommandStrategy + */ + @Test + public void shouldReturnOkStatusForCreateClientCommand() { + + final BatchRequest br = BatchHelper.createClientRequest(4712L, ""); + + final List response = BatchHelper.postWithSingleRequest(this.requestSpec, this.responseSpec, br); + + // Verify that a 200 response is returned as the status code + for (BatchResponse resp : response) { + Assert.assertEquals("Verify Status code 200", (long) 200, (long) resp.getStatusCode()); + } + } + + /** + * Tests for an erroneous response with statusCode '501' if transaction + * fails. If Query Parameter 'enclosingTransaction' is set to 'true' and if + * one of the request in BatchRequest fails then all transactions are rolled + * back. + * + * @see org.mifosplatform.batch.command.internal.CreateClientCommandStrategy + * @see org.mifosplatform.batch.api.BatchApiResource + * @see org.mifosplatform.batch.service.BatchApiService + */ + @Test + public void shouldRollBackAllTransactionsOnFailure() { + + // Create first client request + final BatchRequest br1 = BatchHelper.createClientRequest(4713L, "TestExtId11"); + + // Create second client request + final BatchRequest br2 = BatchHelper.createClientRequest(4714L, "TestExtId12"); + + // Create third client request, having same externalID as second client, + // hence cause of error + final BatchRequest br3 = BatchHelper.createClientRequest(4715L, "TestExtId11"); + + final List batchRequests = new ArrayList<>(); + + batchRequests.add(br1); + batchRequests.add(br2); + batchRequests.add(br3); + + final String jsonifiedRequest = BatchHelper.toJsonString(batchRequests); + final List response = BatchHelper.postBatchRequestsWithEnclosingTransaction(this.requestSpec, this.responseSpec, + jsonifiedRequest); + + // Verifies that none of the client in BatchRequest is created on the + // server + BatchHelper.verifyClientCreatedOnServer(this.requestSpec, this.responseSpec, "TestExtId11"); + BatchHelper.verifyClientCreatedOnServer(this.requestSpec, this.responseSpec, "TestExtId12"); + + // Asserts that all the transactions have been successfully rolled back + Assert.assertEquals(response.size(), 1); + Assert.assertEquals("Verify Status code 400", (long) 400, (long) response.get(0).getStatusCode()); + } + + /** + * Tests that a client information was successfully updated through + * updateClientCommand. A 'changes' parameter is returned in the response + * after successful update of client information. + * + * @see org.mifosplatform.batch.command.internal.UpdateClientCommandStrategy + */ + @Test + public void shouldReflectChangesOnClientUpdate() { + + // Create a createClient Request + final BatchRequest br1 = BatchHelper.createClientRequest(4716L, ""); + + // Create a clientUpdate Request + final BatchRequest br2 = BatchHelper.updateClientRequest(4717L, 4716L); + + final List batchRequests = new ArrayList<>(); + + batchRequests.add(br1); + batchRequests.add(br2); + + final String jsonifiedRequest = BatchHelper.toJsonString(batchRequests); + + final List response = BatchHelper.postBatchRequestsWithoutEnclosingTransaction(this.requestSpec, this.responseSpec, + jsonifiedRequest); + + // Get the changes parameter from updateClient Response + final JsonObject changes = new FromJsonHelper().parse(response.get(1).getBody()).getAsJsonObject().get("changes").getAsJsonObject(); + + // Asserts the client information is successfully updated + Assert.assertEquals("Verify Firstname", "TestFirstName", changes.get("firstname").getAsString()); + Assert.assertEquals("Verify Lastname", "TestLastName", changes.get("lastname").getAsString()); + } + + /** + * Tests that a ApplyLoanCommand was successfully executed and returned a + * 200(OK) status. It creates a new client and apply a loan to that client. + * This also verifies the successful resolution of dependencies among two + * requests. + * + * @see org.mifosplatform.batch.command.internal.ApplyLoanCommandStrategy + */ + @Test + public void shouldReturnOkStatusForApplyLoanCommand() { + + final String loanProductJSON = new LoanProductTestBuilder() // + .withPrincipal("10000000.00") // + .withNumberOfRepayments("24") // + .withRepaymentAfterEvery("1") // + .withRepaymentTypeAsMonth() // + .withinterestRatePerPeriod("2") // + .withInterestRateFrequencyTypeAsMonths() // + .withAmortizationTypeAsEqualPrincipalPayment() // + .withInterestTypeAsDecliningBalance() // + .currencyDetails("0", "100").build(null); + + final Integer productId = new LoanTransactionHelper(this.requestSpec, this.responseSpec).getLoanProductId(loanProductJSON); + + // Create a createClient Request + final BatchRequest br1 = BatchHelper.createClientRequest(4718L, ""); + + // Create a ApplyLoan Request + final BatchRequest br2 = BatchHelper.applyLoanRequest(4719L, 4718L, productId); + + final List batchRequests = new ArrayList<>(); + + batchRequests.add(br1); + batchRequests.add(br2); + + final String jsonifiedRequest = BatchHelper.toJsonString(batchRequests); + + final List response = BatchHelper.postBatchRequestsWithoutEnclosingTransaction(this.requestSpec, this.responseSpec, + jsonifiedRequest); + + // Get the clientId parameter from createClient Response + final JsonElement clientId = new FromJsonHelper().parse(response.get(0).getBody()).getAsJsonObject().get("clientId"); + + Assert.assertEquals("Verify Status Code 200" + clientId.getAsString(), 200L, (long) response.get(1).getStatusCode()); + } + + /** + * Tests that a new savings accounts was applied to an existing client and a + * 200(OK) status was returned. It first creates a new client and a savings + * product, then uses the cliendId and ProductId to apply a savings account. + * + * @see org.mifosplatform.batch.command.internal.ApplySavingsCommandStrategy + */ + @Test + public void shouldReturnOkStatusForApplySavingsCommand() { + + final SavingsProductHelper savingsProductHelper = new SavingsProductHelper(); final String savingsProductJSON = savingsProductHelper // .withInterestCompoundingPeriodTypeAsDaily() // .withInterestPostingPeriodTypeAsMonthly() // .withInterestCalculationPeriodTypeAsDailyBalance() // .withMinimumOpenningBalance("5000").build(); - - final Integer productId = SavingsProductHelper.createSavingsProduct(savingsProductJSON, - this.requestSpec, this.responseSpec); - - //Create a createClient Request - final BatchRequest br1 = BatchHelper.createClientRequest(4720L, ""); - - //Create a applySavings Request - final BatchRequest br2 = BatchHelper.applySavingsRequest(4721L, 4720L, productId); - - final List batchRequests = new ArrayList<>(); - - batchRequests.add(br1); - batchRequests.add(br2); - - final String jsonifiedRequest = BatchHelper.toJsonString(batchRequests); - - final List response = BatchHelper.postBatchRequestsWithoutEnclosingTransaction(this.requestSpec, - this.responseSpec, jsonifiedRequest); - - //Get the clientId parameter from createClient Response - final JsonElement clientId = new FromJsonHelper().parse(response.get(0).getBody()) - .getAsJsonObject().get("clientId"); - - Assert.assertEquals("Savings Successfully applied to client " + clientId.getAsString(), - 200L, (long) response.get(1).getStatusCode()); - } + + final Integer productId = SavingsProductHelper.createSavingsProduct(savingsProductJSON, this.requestSpec, this.responseSpec); + + // Create a createClient Request + final BatchRequest br1 = BatchHelper.createClientRequest(4720L, ""); + + // Create a applySavings Request + final BatchRequest br2 = BatchHelper.applySavingsRequest(4721L, 4720L, productId); + + final List batchRequests = new ArrayList<>(); + + batchRequests.add(br1); + batchRequests.add(br2); + + final String jsonifiedRequest = BatchHelper.toJsonString(batchRequests); + + final List response = BatchHelper.postBatchRequestsWithoutEnclosingTransaction(this.requestSpec, this.responseSpec, + jsonifiedRequest); + + Assert.assertEquals("Verify Status Code 200", 200L, (long) response.get(1).getStatusCode()); + } + + /** + * Tests that a new charge was added to a newly created loan and charges are + * Collected properly 200(OK) status was returned for successful responses. + * It first creates a new client and apply a loan, then creates a new charge + * for the create loan and then fetches all the applied charges + * + * @see org.mifosplatform.batch.command.internal.CollectChargesCommandStrategy + * @see org.mifosplatform.batch.command.internal.CreateChargeCommandStrategy + */ + @Test + public void shouldReturnOkStatusForCollectChargesCommand() { + + final String loanProductJSON = new LoanProductTestBuilder() // + .withPrincipal("10000000.00") // + .withNumberOfRepayments("24") // + .withRepaymentAfterEvery("1") // + .withRepaymentTypeAsMonth() // + .withinterestRatePerPeriod("2") // + .withInterestRateFrequencyTypeAsMonths() // + .withAmortizationTypeAsEqualPrincipalPayment() // + .withInterestTypeAsDecliningBalance() // + .currencyDetails("0", "100").build(null); + + final Integer productId = new LoanTransactionHelper(this.requestSpec, this.responseSpec).getLoanProductId(loanProductJSON); + + // Create a createClient Request + final BatchRequest br1 = BatchHelper.createClientRequest(4722L, ""); + + // Create a ApplyLoan Request + final BatchRequest br2 = BatchHelper.applyLoanRequest(4723L, 4722L, productId); + + // Create a createCharge Request + final BatchRequest br3 = BatchHelper.createChargeRequest(4724L, 4723L); + + // Create a Collect Charges Request + final BatchRequest br4 = BatchHelper.collectChargesRequest(4725L, 4723L); + + final List batchRequests = new ArrayList<>(); + + batchRequests.add(br1); + batchRequests.add(br2); + batchRequests.add(br3); + batchRequests.add(br4); + + final String jsonifiedRequest = BatchHelper.toJsonString(batchRequests); + + final List response = BatchHelper.postBatchRequestsWithoutEnclosingTransaction(this.requestSpec, this.responseSpec, + jsonifiedRequest); + + Assert.assertEquals("Verify Status Code 200 for Create Charge", 200L, (long) response.get(2).getStatusCode()); + Assert.assertEquals("Verify Status Code 200 for Collect Charges", 200L, (long) response.get(3).getStatusCode()); + } } \ No newline at end of file diff --git a/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/BatchRequestsIntegrationTest.java b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/BatchRequestsIntegrationTest.java new file mode 100644 index 000000000..e53a2cc2c --- /dev/null +++ b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/BatchRequestsIntegrationTest.java @@ -0,0 +1,122 @@ +package org.mifosplatform.integrationtests; + +import java.util.ArrayList; +import java.util.List; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.mifosplatform.batch.domain.BatchRequest; +import org.mifosplatform.batch.domain.BatchResponse; +import org.mifosplatform.integrationtests.common.BatchHelper; +import org.mifosplatform.integrationtests.common.ClientHelper; +import org.mifosplatform.integrationtests.common.GroupHelper; +import org.mifosplatform.integrationtests.common.Utils; +import org.mifosplatform.integrationtests.common.loans.LoanProductTestBuilder; +import org.mifosplatform.integrationtests.common.loans.LoanTransactionHelper; + +import com.jayway.restassured.builder.RequestSpecBuilder; +import com.jayway.restassured.builder.ResponseSpecBuilder; +import com.jayway.restassured.http.ContentType; +import com.jayway.restassured.specification.RequestSpecification; +import com.jayway.restassured.specification.ResponseSpecification; + +/** + * Test class for testing the integration of Batch API with custom batch + * requests and various user defined workflow. Like in the case of mifos + * community-app + * + * @author Rishabh Shukla + */ +public class BatchRequestsIntegrationTest { + + private ResponseSpecification responseSpec; + private RequestSpecification requestSpec; + + public BatchRequestsIntegrationTest() { + super(); + } + + /** + * Sets up the essential settings for the TEST like contentType, + * expectedStatusCode. It uses the '@Before' annotation provided by jUnit. + */ + @Before + public void setup() { + + Utils.initializeRESTAssured(); + this.requestSpec = new RequestSpecBuilder().setContentType(ContentType.JSON).build(); + this.requestSpec.header("Authorization", "Basic " + Utils.loginIntoServerAndGetBase64EncodedAuthenticationKey()); + this.responseSpec = new ResponseSpecBuilder().expectStatusCode(200).build(); + } + + @Test + /** + * Tests that a loan is successfully applied to client members of a group. + * Firstly, it'll create a few new clients and then will add those clients + * to the group. Then a few loans will be created and one of those loans + * will be chosen at random and similarily a few of the created clients will + * be chosen on random. Now, the selected loan will be applied to these + * clients through Batch - API ApplyLoanCommandStrategy. + */ + public void shouldReturnOkStatusForLoansAppliedToSelectedClients() { + + // Generate a random count of number of clients to be created + final Integer clientsCount = (int) Math.ceil(Math.random() * 7) + 3; + final Integer[] clientIDs = new Integer[clientsCount]; + + // Create a new group and get its groupId + Integer groupID = GroupHelper.createGroup(this.requestSpec, this.responseSpec, true); + + // Create new clients and add those to this group + for (Integer i = 0; i < clientsCount; i++) { + clientIDs[i] = ClientHelper.createClient(this.requestSpec, this.responseSpec); + groupID = GroupHelper.associateClient(this.requestSpec, this.responseSpec, groupID.toString(), clientIDs[i].toString()); + System.out.println("client " + clientIDs[i] + " has been added to the group " + groupID); + } + + // Generate a random count of number of new loan products to be created + final Integer loansCount = (int) Math.ceil(Math.random() * 4) + 1; + final Integer[] loanProducts = new Integer[loansCount]; + + // Create new loan Products + for (Integer i = 0; i < loansCount; i++) { + final String loanProductJSON = new LoanProductTestBuilder() // + .withPrincipal(String.valueOf(10000.00 + Math.ceil(Math.random() * 1000000.00))) // + .withNumberOfRepayments(String.valueOf(2 + (int) Math.ceil(Math.random() * 36))) // + .withRepaymentAfterEvery(String.valueOf(1 + (int) Math.ceil(Math.random() * 3))) // + .withRepaymentTypeAsMonth() // + .withinterestRatePerPeriod(String.valueOf(1 + (int) Math.ceil(Math.random() * 4))) // + .withInterestRateFrequencyTypeAsMonths() // + .withAmortizationTypeAsEqualPrincipalPayment() // + .withInterestTypeAsDecliningBalance() // + .currencyDetails("0", "100").build(null); + + loanProducts[i] = new LoanTransactionHelper(this.requestSpec, this.responseSpec).getLoanProductId(loanProductJSON); + } + + // Select anyone of the loan products at random + final Integer loanProductID = loanProducts[(int) Math.floor(Math.random() * (loansCount - 1))]; + + final List batchRequests = new ArrayList<>(); + + // Select a few clients from created group at random + Integer selClientsCount = (int) Math.ceil(Math.random() * clientsCount) + 2; + for (int i = 0; i < selClientsCount; i++) { + BatchRequest br = BatchHelper.applyLoanRequest((long) selClientsCount, null, loanProductID); + br.setBody(br.getBody().replace("$.clientId", String.valueOf(clientIDs[(int) Math.floor(Math.random() * (clientsCount - 1))]))); + batchRequests.add(br); + } + + // Send the request to Batch - API + final String jsonifiedRequest = BatchHelper.toJsonString(batchRequests); + + final List response = BatchHelper.postBatchRequestsWithoutEnclosingTransaction(this.requestSpec, this.responseSpec, + jsonifiedRequest); + + // Verify that each loan has been applied successfully + for (BatchResponse res : response) { + Assert.assertEquals("Verify Status Code 200", 200L, (long) res.getStatusCode()); + } + } +} diff --git a/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/BatchHelper.java b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/BatchHelper.java index ee4c99d38..89e7bfafa 100644 --- a/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/BatchHelper.java +++ b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/BatchHelper.java @@ -13,9 +13,9 @@ import com.jayway.restassured.specification.RequestSpecification; import com.jayway.restassured.specification.ResponseSpecification; /** - * Helper class for {@link org.mifosplatform.integrationtests.BatchApiTest}. - * It takes care of creation of {@code BatchRequest} list and posting this - * list to the server. + * Helper class for {@link org.mifosplatform.integrationtests.BatchApiTest}. It + * takes care of creation of {@code BatchRequest} list and posting this list to + * the server. * * @author Rishabh Shukla * @@ -23,210 +23,259 @@ import com.jayway.restassured.specification.ResponseSpecification; */ public class BatchHelper { - private static final String BATCH_API_URL = "/mifosng-provider/api/v1/batches?tenantIdentifier=default"; - private static final String BATCH_API_URL_EXT = BATCH_API_URL + "&enclosingTransaction=true"; - - private BatchHelper() { - super(); - } - - /** - * Returns a JSON String for a list of {@code BatchRequest}s - * - * @param batchRequests - * @return JSON String of BatchRequest - */ - public static String toJsonString(final List batchRequests) { - return new Gson().toJson(batchRequests); - } + private static final String BATCH_API_URL = "/mifosng-provider/api/v1/batches?tenantIdentifier=default"; + private static final String BATCH_API_URL_EXT = BATCH_API_URL + "&enclosingTransaction=true"; - /** - * Returns the converted string response into JSON. - * - * @param json - * @return List - */ - private static List fromJsonString(final String json) { - return new Gson().fromJson(json, new TypeToken>(){}.getType()); + private BatchHelper() { + super(); } - - /** - * Returns a list of BatchResponse with query parameter enclosing transaction set to - * false by posting the jsonified BatchRequest to the server. - * - * @param requestSpec - * @param responseSpec - * @param jsonifiedBatchRequests - * @return a list of BatchResponse - */ - public static List postBatchRequestsWithoutEnclosingTransaction(final RequestSpecification requestSpec, - final ResponseSpecification responseSpec, final String jsonifiedBatchRequests) { - final String response = Utils.performServerPost(requestSpec, responseSpec, BATCH_API_URL, jsonifiedBatchRequests, null); - return BatchHelper.fromJsonString(response); - } - - /** - * Returns a list of BatchResponse with query parameter enclosing transaction set to - * true by posting the jsonified BatchRequest to the server. - * - * @param requestSpec - * @param responseSpec - * @param jsonifiedBatchRequests - * @return a list of BatchResponse - */ - public static List postBatchRequestsWithEnclosingTransaction(final RequestSpecification requestSpec, - final ResponseSpecification responseSpec, final String jsonifiedBatchRequests) { - final String response = Utils.performServerPost(requestSpec, responseSpec, BATCH_API_URL_EXT, jsonifiedBatchRequests, null); - return BatchHelper.fromJsonString(response); - } - - /** - * Returns a BatchResponse based on the given BatchRequest, by posting the request - * to the server. + /** + * Returns a JSON String for a list of {@code BatchRequest}s + * + * @param batchRequests + * @return JSON String of BatchRequest + */ + public static String toJsonString(final List batchRequests) { + return new Gson().toJson(batchRequests); + } + + /** + * Returns the converted string response into JSON. + * + * @param json + * @return List + */ + private static List fromJsonString(final String json) { + return new Gson().fromJson(json, new TypeToken>() {}.getType()); + } + + /** + * Returns a list of BatchResponse with query parameter enclosing + * transaction set to false by posting the jsonified BatchRequest to the + * server. + * + * @param requestSpec + * @param responseSpec + * @param jsonifiedBatchRequests + * @return a list of BatchResponse + */ + public static List postBatchRequestsWithoutEnclosingTransaction(final RequestSpecification requestSpec, + final ResponseSpecification responseSpec, final String jsonifiedBatchRequests) { + final String response = Utils.performServerPost(requestSpec, responseSpec, BATCH_API_URL, jsonifiedBatchRequests, null); + return BatchHelper.fromJsonString(response); + } + + /** + * Returns a list of BatchResponse with query parameter enclosing + * transaction set to true by posting the jsonified BatchRequest to the + * server. + * + * @param requestSpec + * @param responseSpec + * @param jsonifiedBatchRequests + * @return a list of BatchResponse + */ + public static List postBatchRequestsWithEnclosingTransaction(final RequestSpecification requestSpec, + final ResponseSpecification responseSpec, final String jsonifiedBatchRequests) { + final String response = Utils.performServerPost(requestSpec, responseSpec, BATCH_API_URL_EXT, jsonifiedBatchRequests, null); + return BatchHelper.fromJsonString(response); + } + + /** + * Returns a BatchResponse based on the given BatchRequest, by posting the + * request to the server. * * @param BatchRequest * @return List */ public static List postWithSingleRequest(final RequestSpecification requestSpec, - final ResponseSpecification responseSpec,final BatchRequest br) { - - final List batchRequests = new ArrayList<>(); - batchRequests.add(br); - - final String jsonifiedRequest = BatchHelper.toJsonString(batchRequests); - final List response = BatchHelper.postBatchRequestsWithoutEnclosingTransaction(requestSpec, - responseSpec, jsonifiedRequest); - - //Verifies that the response result is there - Assert.assertNotNull(response); - Assert.assertTrue(response.size() > 0); - - return response; + final ResponseSpecification responseSpec, final BatchRequest br) { + + final List batchRequests = new ArrayList<>(); + batchRequests.add(br); + + final String jsonifiedRequest = BatchHelper.toJsonString(batchRequests); + final List response = BatchHelper.postBatchRequestsWithoutEnclosingTransaction(requestSpec, responseSpec, + jsonifiedRequest); + + // Verifies that the response result is there + Assert.assertNotNull(response); + Assert.assertTrue(response.size() > 0); + + return response; } - - /** - * Creates and returns a {@link org.mifosplatform.batch.command.internal.CreateClientCommandStrategy} - * Request as one of the request in Batch. - * - * @param reqId - * @param externalId - * @return BatchRequest - */ - public static BatchRequest createClientRequest(final Long requestId, final String externalId) { - - final BatchRequest br = new BatchRequest(); - br.setRequestId(requestId); - br.setRelativeUrl("clients"); - br.setMethod("POST"); - - final String extId; - if(externalId.equals("")) { - extId = "ext" + String.valueOf((10000 * Math.random())) + String.valueOf((10000 * Math.random())); - } - else { - extId = externalId; - } - - final String body = "{ \"officeId\": 1, \"firstname\": \"Petra\", \"lastname\": \"Yton\"," + - "\"externalId\": " + extId + ", \"dateFormat\": \"dd MMMM yyyy\", \"locale\": \"en\"," + - "\"active\": true, \"activationDate\": \"04 March 2009\", \"submittedOnDate\": \"04 March 2009\"}"; - - br.setBody(body); - - return br; - } - - /** - * Creates and returns a {@link org.mifosplatform.batch.command.internal.UpdateClientCommandStrategy} - * Request with given requestId and reference. - * - * @param reqId - * @param clientId - * @return BatchRequest - */ - public static BatchRequest updateClientRequest(final Long requestId, final Long reference) { - - final BatchRequest br = new BatchRequest(); - - br.setRequestId(requestId); - br.setRelativeUrl("clients/$.clientId"); - br.setMethod("PUT"); - br.setReference(reference); - br.setBody("{\"firstname\": \"TestFirstName\", \"lastname\": \"TestLastName\"}"); - - return br; - } - - /** - * Creates and returns a {@link org.mifosplatform.batch.command.internal.ApplyLoanCommandStrategy} - * Request with given requestId and reference. - * - * @param requestId - * @param reference - * @param productId - * @return BatchRequest - */ - public static BatchRequest applyLoanRequest(final Long requestId, final Long reference, - final Integer productId) { - - final BatchRequest br = new BatchRequest(); - - br.setRequestId(requestId); - br.setRelativeUrl("loans"); - br.setMethod("POST"); - br.setReference(reference); - - final String body = "{\"dateFormat\": \"dd MMMM yyyy\", \"locale\": \"en_GB\", \"clientId\": \"$.clientId\"," + - "\"productId\": "+productId+", \"principal\": \"10,000.00\", \"loanTermFrequency\": 12," + - "\"loanTermFrequencyType\": 2, \"loanType\": \"individual\", \"numberOfRepayments\": 10," + - "\"repaymentEvery\": 1, \"repaymentFrequencyType\": 2, \"interestRatePerPeriod\": 10," + - "\"amortizationType\": 1, \"interestType\": 0, \"interestCalculationPeriodType\": 1," + - "\"transactionProcessingStrategyId\": 1, \"expectedDisbursementDate\": \"10 Jun 2013\"," + - "\"submittedOnDate\": \"10 Jun 2013\"}"; - br.setBody(body); - - return br; - } - - /** - * Creates and returns a {@link org.mifosplatform.batch.command.internal.ApplySavingsCommandStrategy} - * Request with given requestId and reference. - * - * @param requestId - * @param reference - * @param productId - * @return BatchRequest - */ - public static BatchRequest applySavingsRequest(final Long requestId, final Long reference, - final Integer productId){ - - final BatchRequest br = new BatchRequest(); - - br.setRequestId(requestId); - br.setRelativeUrl("savingsaccounts"); - br.setMethod("POST"); - br.setReference(reference); - - final String body = "{\"clientId\": \"$.clientId\", \"productId\": "+productId+ "," + - "\"locale\": \"en\", \"dateFormat\": \"dd MMMM yyyy\", \"submittedOnDate\": \"01 March 2011\"}"; - br.setBody(body); - - return br; - } - - /** - * Checks that the client with given externalId is not created on the server. - * - * @param requestSpec - * @param responseSpec - * @param externalId - */ + + /** + * Creates and returns a + * {@link org.mifosplatform.batch.command.internal.CreateClientCommandStrategy} + * Request as one of the request in Batch. + * + * @param reqId + * @param externalId + * @return BatchRequest + */ + public static BatchRequest createClientRequest(final Long requestId, final String externalId) { + + final BatchRequest br = new BatchRequest(); + br.setRequestId(requestId); + br.setRelativeUrl("clients"); + br.setMethod("POST"); + + final String extId; + if (externalId.equals("")) { + extId = "ext" + String.valueOf((10000 * Math.random())) + String.valueOf((10000 * Math.random())); + } else { + extId = externalId; + } + + final String body = "{ \"officeId\": 1, \"firstname\": \"Petra\", \"lastname\": \"Yton\"," + "\"externalId\": " + extId + + ", \"dateFormat\": \"dd MMMM yyyy\", \"locale\": \"en\"," + + "\"active\": true, \"activationDate\": \"04 March 2009\", \"submittedOnDate\": \"04 March 2009\"}"; + + br.setBody(body); + + return br; + } + + /** + * Creates and returns a + * {@link org.mifosplatform.batch.command.internal.UpdateClientCommandStrategy} + * Request with given requestId and reference. + * + * @param reqId + * @param clientId + * @return BatchRequest + */ + public static BatchRequest updateClientRequest(final Long requestId, final Long reference) { + + final BatchRequest br = new BatchRequest(); + + br.setRequestId(requestId); + br.setRelativeUrl("clients/$.clientId"); + br.setMethod("PUT"); + br.setReference(reference); + br.setBody("{\"firstname\": \"TestFirstName\", \"lastname\": \"TestLastName\"}"); + + return br; + } + + /** + * Creates and returns a + * {@link org.mifosplatform.batch.command.internal.ApplyLoanCommandStrategy} + * Request with given requestId and reference. + * + * @param requestId + * @param reference + * @param productId + * @return BatchRequest + */ + public static BatchRequest applyLoanRequest(final Long requestId, final Long reference, final Integer productId) { + + final BatchRequest br = new BatchRequest(); + + br.setRequestId(requestId); + br.setRelativeUrl("loans"); + br.setMethod("POST"); + br.setReference(reference); + + final String body = "{\"dateFormat\": \"dd MMMM yyyy\", \"locale\": \"en_GB\", \"clientId\": \"$.clientId\"," + "\"productId\": " + + productId + ", \"principal\": \"10,000.00\", \"loanTermFrequency\": 12," + + "\"loanTermFrequencyType\": 2, \"loanType\": \"individual\", \"numberOfRepayments\": 10," + + "\"repaymentEvery\": 1, \"repaymentFrequencyType\": 2, \"interestRatePerPeriod\": 10," + + "\"amortizationType\": 1, \"interestType\": 0, \"interestCalculationPeriodType\": 1," + + "\"transactionProcessingStrategyId\": 1, \"expectedDisbursementDate\": \"10 Jun 2013\"," + + "\"submittedOnDate\": \"10 Jun 2013\"}"; + br.setBody(body); + + return br; + } + + /** + * Creates and returns a + * {@link org.mifosplatform.batch.command.internal.ApplySavingsCommandStrategy} + * Request with given requestId and reference. + * + * @param requestId + * @param reference + * @param productId + * @return BatchRequest + */ + public static BatchRequest applySavingsRequest(final Long requestId, final Long reference, final Integer productId) { + + final BatchRequest br = new BatchRequest(); + + br.setRequestId(requestId); + br.setRelativeUrl("savingsaccounts"); + br.setMethod("POST"); + br.setReference(reference); + + final String body = "{\"clientId\": \"$.clientId\", \"productId\": " + productId + "," + + "\"locale\": \"en\", \"dateFormat\": \"dd MMMM yyyy\", \"submittedOnDate\": \"01 March 2011\"}"; + br.setBody(body); + + return br; + } + + /** + * Creates and returns a + * {@link org.mifosplatform.batch.command.internal.CreateChargeCommandStrategy} + * Request with given requestId and reference + * + * @param requestId + * @param reference + * @return BatchRequest + */ + public static BatchRequest createChargeRequest(final Long requestId, final Long reference) { + + final BatchRequest br = new BatchRequest(); + br.setRequestId(requestId); + br.setRelativeUrl("loans/$.loanId/charges"); + br.setMethod("POST"); + br.setReference(reference); + + final String body = "{\"chargeId\": \"2\", \"locale\": \"en\", \"amount\": \"100\", " + + "\"dateFormat\": \"dd MMMM yyyy\", \"dueDate\": \"29 April 2013\"}"; + br.setBody(body); + + return br; + } + + /** + * Creates and returns a + * {@link org.mifosplatform.batch.command.internal.CollectChargesCommandStrategy} + * Request with given requestId and reference + * + * @param requestId + * @param reference + * @return BatchRequest + */ + public static BatchRequest collectChargesRequest(final Long requestId, final Long reference) { + + final BatchRequest br = new BatchRequest(); + + br.setRequestId(requestId); + br.setRelativeUrl("loans/$.loanId/charges"); + br.setReference(reference); + br.setMethod("GET"); + br.setBody("{ }"); + + return br; + } + + /** + * Checks that the client with given externalId is not created on the + * server. + * + * @param requestSpec + * @param responseSpec + * @param externalId + */ public static void verifyClientCreatedOnServer(final RequestSpecification requestSpec, final ResponseSpecification responseSpec, final String externalId) { System.out.println("------------------------------CHECK CLIENT DETAILS------------------------------------\n"); final String CLIENT_URL = "/mifosng-provider/api/v1/clients?externalId=" + externalId + "&tenantIdentifier=default"; final Integer responseRecords = Utils.performServerGet(requestSpec, responseSpec, CLIENT_URL, "totalFilteredRecords"); - Assert.assertEquals("No records found with given externalId",(long) responseRecords, (long) 0); + Assert.assertEquals("No records found with given externalId", (long) responseRecords, (long) 0); } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/batch/api/BatchApiResource.java b/mifosng-provider/src/main/java/org/mifosplatform/batch/api/BatchApiResource.java index c61b0e57c..71689a0e7 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/batch/api/BatchApiResource.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/batch/api/BatchApiResource.java @@ -9,12 +9,12 @@ import javax.ws.rs.POST; import javax.ws.rs.Path; import javax.ws.rs.Produces; import javax.ws.rs.QueryParam; +import javax.ws.rs.core.Context; import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.UriInfo; import org.mifosplatform.batch.domain.BatchRequest; import org.mifosplatform.batch.domain.BatchResponse; -import org.mifosplatform.batch.exception.ErrorHandler; -import org.mifosplatform.batch.exception.ErrorInfo; import org.mifosplatform.batch.serialization.BatchRequestJsonHelper; import org.mifosplatform.batch.service.BatchApiService; import org.mifosplatform.infrastructure.core.serialization.ToApiJsonSerializer; @@ -24,12 +24,13 @@ import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Component; /** - * Provides a REST resource for Batch Requests. This class acts as a proxy to - * {@link org.mifosplatform.batch.service.BatchApiService} and de-serializes - * the incoming JSON string to a list of {@link org.mifosplatform.batch.domain - * .BatchRequest} type. This list is forwarded to BatchApiService which finally - * returns a list of {@link org.mifosplatform.batch.domain.BatchResponse} type - * which is then serialized into JSON response by this Resource class. + * Provides a REST resource for Batch Requests. This class acts as a proxy to + * {@link org.mifosplatform.batch.service.BatchApiService} and de-serializes the + * incoming JSON string to a list of + * {@link org.mifosplatform.batch.domain .BatchRequest} type. This list is + * forwarded to BatchApiService which finally returns a list of + * {@link org.mifosplatform.batch.domain.BatchResponse} type which is then + * serialized into JSON response by this Resource class. * * @author Rishabh Shukla * @@ -41,80 +42,64 @@ import org.springframework.stereotype.Component; @Component @Scope("singleton") public class BatchApiResource { - - private final PlatformSecurityContext context; - private final ToApiJsonSerializer toApiJsonSerializer; - private final BatchApiService service; - private final BatchRequestJsonHelper batchRequestJsonHelper; - - /** - * Constructs a 'BatchApiService' with context, toApiJsonSerializer, service - * and batchRequestJsonHelper. - * - * @param context - * @param toApiJsonSerializer - * @param service - * @param batchRequestJsonHelper - */ - @Autowired - public BatchApiResource(final PlatformSecurityContext context, final ToApiJsonSerializer - toApiJsonSerializer, final BatchApiService service, final BatchRequestJsonHelper batchRequestJsonHelper) { - - this.context = context; - this.toApiJsonSerializer = toApiJsonSerializer; - this.service = service; - this.batchRequestJsonHelper = batchRequestJsonHelper; - } - - /** - * Rest assured POST method to get {@link BatchRequest} and returns back the - * consolidated {@link BatchResponse} - * - * @param jsonRequestString - * @return serialized JSON - */ - @POST - @Consumes({ MediaType.APPLICATION_JSON }) - @Produces({ MediaType.APPLICATION_JSON }) - public String handleBatchRequests(@DefaultValue("false") @QueryParam("enclosingTransaction") - final boolean enclosingTransaction, final String jsonRequestString) { - - //Handles user authentication - this.context.authenticatedUser(); - - //Converts request array into BatchRequest List - final List requestList = this.batchRequestJsonHelper.extractList(jsonRequestString); - //Gets back the consolidated BatchResponse from BatchApiservice - List result = new ArrayList<>(); + private final PlatformSecurityContext context; + private final ToApiJsonSerializer toApiJsonSerializer; + private final BatchApiService service; + private final BatchRequestJsonHelper batchRequestJsonHelper; - //If the request is to be handled as a Transaction. All requests will be rolled back on error - if(enclosingTransaction) { - - try { - result = service.handleBatchRequestsWithEnclosingTransaction(requestList); - } - catch(RuntimeException e) { - - BatchResponse response = new BatchResponse(); - - //Gets an object of type ErrorInfo, containing information about raised exception - ErrorInfo ex = ErrorHandler.handler(e); - - response.setStatusCode(ex.getStatusCode()); - response.setBody(ex.getMessage()); - result.add(response); - - return this.toApiJsonSerializer.serialize(result); - - } - - } - else { - result = service.handleBatchRequestsWithoutEnclosingTransaction(requestList); - } + /** + * Constructs a 'BatchApiService' with context, toApiJsonSerializer, service + * and batchRequestJsonHelper. + * + * @param context + * @param toApiJsonSerializer + * @param service + * @param batchRequestJsonHelper + */ + @Autowired + public BatchApiResource(final PlatformSecurityContext context, final ToApiJsonSerializer toApiJsonSerializer, + final BatchApiService service, final BatchRequestJsonHelper batchRequestJsonHelper) { - return this.toApiJsonSerializer.serialize(result); - - } + this.context = context; + this.toApiJsonSerializer = toApiJsonSerializer; + this.service = service; + this.batchRequestJsonHelper = batchRequestJsonHelper; + } + + /** + * Rest assured POST method to get {@link BatchRequest} and returns back the + * consolidated {@link BatchResponse} + * + * @param jsonRequestString + * @param enclosingTransaction + * @param uriInfo + * @return serialized JSON + */ + @POST + @Consumes({ MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_JSON }) + public String handleBatchRequests(@DefaultValue("false") @QueryParam("enclosingTransaction") final boolean enclosingTransaction, + final String jsonRequestString, @Context UriInfo uriInfo) { + + // Handles user authentication + this.context.authenticatedUser(); + + // Converts request array into BatchRequest List + final List requestList = this.batchRequestJsonHelper.extractList(jsonRequestString); + + // Gets back the consolidated BatchResponse from BatchApiservice + List result = new ArrayList<>(); + + // If the request is to be handled as a Transaction. All requests will + // be rolled back on error + if (enclosingTransaction) { + result = service.handleBatchRequestsWithEnclosingTransaction(requestList, uriInfo); + } else { + result = service.handleBatchRequestsWithoutEnclosingTransaction(requestList, uriInfo); + } + + return this.toApiJsonSerializer.serialize(result); + + } } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/batch/command/CommandContext.java b/mifosng-provider/src/main/java/org/mifosplatform/batch/command/CommandContext.java index f4e291c0b..4fe2d89fb 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/batch/command/CommandContext.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/batch/command/CommandContext.java @@ -1,9 +1,9 @@ package org.mifosplatform.batch.command; /** - * Provides an object to {@link org.mifosplatform.batch.service.BatchApiService} to - * get the proper commandStrategy for each request in BatchRequest. It uses Builder - * pattern to create object of this type. + * Provides an object to {@link org.mifosplatform.batch.service.BatchApiService} + * to get the proper commandStrategy for each request in BatchRequest. It uses + * Builder pattern to create object of this type. * * @author Rishabh Shukla * @@ -11,92 +11,80 @@ package org.mifosplatform.batch.command; */ public class CommandContext { - /** - * Static Builder class to provide a Build method for CommandContext. - * - * @author Rishabh Shukla - */ - public static class Builder{ - - private String resource; - private String method; - - private Builder(final String resource) { - this.resource = resource; - } - - public Builder method(final String method) { - this.method = method; - return this; - } - - public CommandContext build() { - return new CommandContext(this.resource, this.method); - } - - } - - private final String resource; - private final String method; - - private CommandContext(final String resource, final String method) { - - this.resource = resource; - this.method = method; - } - - public static Builder resource(final String resource) { - return new Builder(resource); - } - - /** - * Returns a boolean value if the relativeUrl 'matches' one of the regex keys in - * the available commandStrategies. It take CommandContext object as parameter - * which contains a 'resource' member as a regex key for available commandStrategies. - * - * @param other - * @return boolean - */ - public boolean matcher(CommandContext other) { - if(this.resource.matches(other.resource) && this.method.equals(other.method)) { - return true; - } - return false; - } + /** + * Static Builder class to provide a Build method for CommandContext. + * + * @author Rishabh Shukla + */ + public static class Builder { - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result - + ((this.method == null) ? 0 : this.method.hashCode()); - result = prime * result - + ((this.resource == null) ? 0 : this.resource.hashCode()); - return result; - } + private String resource; + private String method; + + private Builder(final String resource) { + this.resource = resource; + } + + public Builder method(final String method) { + this.method = method; + return this; + } + + public CommandContext build() { + return new CommandContext(this.resource, this.method); + } + + } + + private final String resource; + private final String method; + + private CommandContext(final String resource, final String method) { + + this.resource = resource; + this.method = method; + } + + public static Builder resource(final String resource) { + return new Builder(resource); + } + + /** + * Returns a boolean value if the relativeUrl 'matches' one of the regex + * keys in the available commandStrategies. It take CommandContext object as + * parameter which contains a 'resource' member as a regex key for available + * commandStrategies. + * + * @param other + * @return boolean + */ + public boolean matcher(CommandContext other) { + if (this.resource.matches(other.resource) && this.method.equals(other.method)) { return true; } + return false; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((this.method == null) ? 0 : this.method.hashCode()); + result = prime * result + ((this.resource == null) ? 0 : this.resource.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null) return false; + if (getClass() != obj.getClass()) return false; + CommandContext other = (CommandContext) obj; + if (this.method == null) { + if (other.method != null) return false; + } else if (!this.method.equals(other.method)) return false; + if (this.resource == null) { + if (other.resource != null) return false; + } else if (!this.resource.equals(other.resource)) return false; + return true; + } - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - CommandContext other = (CommandContext) obj; - if (this.method == null) { - if (other.method != null) - return false; - } else if (!this.method.equals(other.method)) - return false; - if (this.resource == null) { - if (other.resource != null) - return false; - } else if (!this.resource.equals(other.resource)) - return false; - return true; - } - - - } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/batch/command/CommandStrategy.java b/mifosng-provider/src/main/java/org/mifosplatform/batch/command/CommandStrategy.java index 80d60a431..07a5ffeeb 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/batch/command/CommandStrategy.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/batch/command/CommandStrategy.java @@ -1,5 +1,7 @@ package org.mifosplatform.batch.command; +import javax.ws.rs.core.UriInfo; + import org.mifosplatform.batch.domain.BatchRequest; import org.mifosplatform.batch.domain.BatchResponse; @@ -13,13 +15,15 @@ import org.mifosplatform.batch.domain.BatchResponse; */ public interface CommandStrategy { - /** - * Returns an object of type {@link org.mifosplatform.batch.domain.BatchResponse}. - * This takes {@link org.mifosplatform.batch.domain.BatchRequest} as it's single - * argument and provides appropriate response. - * - * @param batchRequest - * @return BatchResponse - */ - public BatchResponse execute(BatchRequest batchRequest); + /** + * Returns an object of type + * {@link org.mifosplatform.batch.domain.BatchResponse}. This takes + * {@link org.mifosplatform.batch.domain.BatchRequest} as it's single + * argument and provides appropriate response. + * + * @param batchRequest + * @param uriInfo + * @return BatchResponse + */ + public BatchResponse execute(BatchRequest batchRequest, UriInfo uriInfo); } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/batch/command/CommandStrategyProvider.java b/mifosng-provider/src/main/java/org/mifosplatform/batch/command/CommandStrategyProvider.java index 94ac2783a..b864a0922 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/batch/command/CommandStrategyProvider.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/batch/command/CommandStrategyProvider.java @@ -9,68 +9,71 @@ import org.springframework.stereotype.Component; /** * Provides an appropriate CommandStrategy using the 'method' and 'resourceUrl'. - * CommandStrategy bean is created using Spring Application Context. + * CommandStrategy bean is created using Spring Application Context. * * @author Rishabh Shukla * - * @see org.mifosplatform.batch.command.internal.UnknownCommandStrategy + * @see org.mifosplatform.batch.command.internal.UnknownCommandStrategy */ @Component public class CommandStrategyProvider { - - private final ApplicationContext applicationContext; - private final ConcurrentHashMap commandStrategies = new ConcurrentHashMap<>(); - - /** - * Constructs a CommandStrategyProvider with argument of ApplicationContext type. - * It also initialize commandStrategies using init() function by filling it - * with available CommandStrategies in {@link org.mifosplatform.batch.command.internal}. - * - * @param applicationContext - */ - @Autowired - public CommandStrategyProvider(final ApplicationContext applicationContext) { - - //calls init() function of this class. - init(); - - this.applicationContext = applicationContext; - } - - /** - * Returns an appropriate commandStrategy after determining it using - * the CommandContext of the request. If no such Strategy is found then - * a default strategy is returned back. - * - * @param commandContext - * @return CommandStrategy - * @see org.mifosplatform.batch.command.internal.UnknownCommandStrategy - */ - public CommandStrategy getCommandStrategy(final CommandContext commandContext) { - - if(this.commandStrategies.containsKey(commandContext)) { - return (CommandStrategy) this.applicationContext.getBean(this.commandStrategies.get(commandContext)); - } - - for(ConcurrentHashMap.Entry entry : this.commandStrategies.entrySet()) { - if(commandContext.matcher(entry.getKey())) { - return (CommandStrategy) this.applicationContext.getBean(this.commandStrategies.get(entry.getKey())); - } - } - - return new UnknownCommandStrategy(); - } - - /** - * Contains various available command strategies in {@link org.mifosplatform.batch.command.internal}. - * Any new command Strategy will have to be added within this function in order to initiate it - * within the constructor. - */ - private void init() { - this.commandStrategies.put(CommandContext.resource("clients").method("POST").build(), "createClientCommandStrategy"); - this.commandStrategies.put(CommandContext.resource("clients\\/\\d+").method("PUT").build(), "updateClientCommandStrategy"); - this.commandStrategies.put(CommandContext.resource("loans").method("POST").build(), "applyLoanCommandStrategy"); - this.commandStrategies.put(CommandContext.resource("savingsaccounts").method("POST").build(), "applySavingsCommandStrategy"); - } - + + private final ApplicationContext applicationContext; + private final ConcurrentHashMap commandStrategies = new ConcurrentHashMap<>(); + + /** + * Constructs a CommandStrategyProvider with argument of ApplicationContext + * type. It also initialize commandStrategies using init() function by + * filling it with available CommandStrategies in + * {@link org.mifosplatform.batch.command.internal}. + * + * @param applicationContext + */ + @Autowired + public CommandStrategyProvider(final ApplicationContext applicationContext) { + + // calls init() function of this class. + init(); + + this.applicationContext = applicationContext; + } + + /** + * Returns an appropriate commandStrategy after determining it using the + * CommandContext of the request. If no such Strategy is found then a + * default strategy is returned back. + * + * @param commandContext + * @return CommandStrategy + * @see org.mifosplatform.batch.command.internal.UnknownCommandStrategy + */ + public CommandStrategy getCommandStrategy(final CommandContext commandContext) { + + if (this.commandStrategies.containsKey(commandContext)) { return (CommandStrategy) this.applicationContext + .getBean(this.commandStrategies.get(commandContext)); } + + for (ConcurrentHashMap.Entry entry : this.commandStrategies.entrySet()) { + if (commandContext.matcher(entry.getKey())) { return (CommandStrategy) this.applicationContext.getBean(this.commandStrategies + .get(entry.getKey())); } + } + + return new UnknownCommandStrategy(); + } + + /** + * Contains various available command strategies in + * {@link org.mifosplatform.batch.command.internal}. Any new command + * Strategy will have to be added within this function in order to initiate + * it within the constructor. + */ + private void init() { + this.commandStrategies.put(CommandContext.resource("clients").method("POST").build(), "createClientCommandStrategy"); + this.commandStrategies.put(CommandContext.resource("clients\\/\\d+").method("PUT").build(), "updateClientCommandStrategy"); + this.commandStrategies.put(CommandContext.resource("loans").method("POST").build(), "applyLoanCommandStrategy"); + this.commandStrategies.put(CommandContext.resource("savingsaccounts").method("POST").build(), "applySavingsCommandStrategy"); + this.commandStrategies.put(CommandContext.resource("loans\\/\\d+\\/charges").method("POST").build(), "createChargeCommandStrategy"); + this.commandStrategies + .put(CommandContext.resource("loans\\/\\d+\\/charges").method("GET").build(), "collectChargesCommandStrategy"); + } + } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/batch/command/internal/ApplyLoanCommandStrategy.java b/mifosng-provider/src/main/java/org/mifosplatform/batch/command/internal/ApplyLoanCommandStrategy.java index 5eda17a55..ddd9da1b2 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/batch/command/internal/ApplyLoanCommandStrategy.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/batch/command/internal/ApplyLoanCommandStrategy.java @@ -1,5 +1,7 @@ package org.mifosplatform.batch.command.internal; +import javax.ws.rs.core.UriInfo; + import org.mifosplatform.batch.command.CommandStrategy; import org.mifosplatform.batch.domain.BatchRequest; import org.mifosplatform.batch.domain.BatchResponse; @@ -10,58 +12,60 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; /** - * Implements {@link org.mifosplatform.batch.command.CommandStrategy} and applies a new loan - * on an existing client. It passes the contents of the body from the BatchRequest - * to {@link org.mifosplatform.portfolio.client.api.LoansApiResource} and gets back - * the response. This class will also catch any errors raised by - * {@link org.mifosplatform.portfolio.client.api.LoansApiResource} and map those errors - * to appropriate status codes in BatchResponse. + * Implements {@link org.mifosplatform.batch.command.CommandStrategy} and + * applies a new loan on an existing client. It passes the contents of the body + * from the BatchRequest to + * {@link org.mifosplatform.portfolio.client.api.LoansApiResource} and gets back + * the response. This class will also catch any errors raised by + * {@link org.mifosplatform.portfolio.client.api.LoansApiResource} and map those + * errors to appropriate status codes in BatchResponse. * * @author Rishabh Shukla - * + * * @see org.mifosplatform.batch.command.CommandStrategy * @see org.mifosplatform.batch.domain.BatchRequest * @see org.mifosplatform.batch.domain.BatchResponse */ @Component -public class ApplyLoanCommandStrategy implements CommandStrategy{ +public class ApplyLoanCommandStrategy implements CommandStrategy { - private final LoansApiResource loansApiResource; - - @Autowired - public ApplyLoanCommandStrategy(final LoansApiResource loansApiResource) { - this.loansApiResource = loansApiResource; - } - - @Override - public BatchResponse execute(BatchRequest request) { - - final BatchResponse response = new BatchResponse(); - final String responseBody; + private final LoansApiResource loansApiResource; - response.setRequestId(request.getRequestId()); - response.setHeaders(request.getHeaders()); - - //Try-catch blocks to map exceptions to appropriate status codes - try { - - //Calls 'SubmitLoanFunction' function from 'LoansApiResource' to Apply Loan to an existing client - responseBody = loansApiResource.calculateLoanScheduleOrSubmitLoanApplication(null, null, request.getBody()); - - response.setStatusCode(200); - //Sets the body of the response after loan is successfully applied - response.setBody(responseBody); - - } - catch (RuntimeException e) { - - //Gets an object of type ErrorInfo, containing information about raised exception - ErrorInfo ex = ErrorHandler.handler(e); - - response.setStatusCode(ex.getStatusCode()); - response.setBody(ex.getMessage()); - } - - return response; - } + @Autowired + public ApplyLoanCommandStrategy(final LoansApiResource loansApiResource) { + this.loansApiResource = loansApiResource; + } + + @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()); + + // Try-catch blocks to map exceptions to appropriate status codes + try { + + // Calls 'SubmitLoanFunction' function from 'LoansApiResource' to + // Apply Loan to an existing client + responseBody = loansApiResource.calculateLoanScheduleOrSubmitLoanApplication(null, null, request.getBody()); + + response.setStatusCode(200); + // Sets the body of the response after loan is successfully applied + response.setBody(responseBody); + + } catch (RuntimeException e) { + + // Gets an object of type ErrorInfo, containing information about + // raised exception + ErrorInfo ex = ErrorHandler.handler(e); + + response.setStatusCode(ex.getStatusCode()); + response.setBody(ex.getMessage()); + } + + return response; + } } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/batch/command/internal/ApplySavingsCommandStrategy.java b/mifosng-provider/src/main/java/org/mifosplatform/batch/command/internal/ApplySavingsCommandStrategy.java index fe4290c58..8779d1836 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/batch/command/internal/ApplySavingsCommandStrategy.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/batch/command/internal/ApplySavingsCommandStrategy.java @@ -1,5 +1,7 @@ package org.mifosplatform.batch.command.internal; +import javax.ws.rs.core.UriInfo; + import org.mifosplatform.batch.command.CommandStrategy; import org.mifosplatform.batch.domain.BatchRequest; import org.mifosplatform.batch.domain.BatchResponse; @@ -10,58 +12,62 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; /** - * Implements {@link org.mifosplatform.batch.command.CommandStrategy} and applies a new savings - * on an existing client. It passes the contents of the body from the BatchRequest - * to {@link org.mifosplatform.portfolio.client.api.SavingsAccountsApiResource} and gets back - * the response. This class will also catch any errors raised by - * {@link org.mifosplatform.portfolio.client.api.SavingsAccountsApiResource} and map those errors - * to appropriate status codes in BatchResponse. + * Implements {@link org.mifosplatform.batch.command.CommandStrategy} and + * applies a new savings on an existing client. It passes the contents of the + * body from the BatchRequest to + * {@link org.mifosplatform.portfolio.client.api.SavingsAccountsApiResource} and + * gets back the response. This class will also catch any errors raised by + * {@link org.mifosplatform.portfolio.client.api.SavingsAccountsApiResource} and + * map those errors to appropriate status codes in BatchResponse. * * @author Rishabh Shukla - * + * * @see org.mifosplatform.batch.command.CommandStrategy * @see org.mifosplatform.batch.domain.BatchRequest * @see org.mifosplatform.batch.domain.BatchResponse */ @Component -public class ApplySavingsCommandStrategy implements CommandStrategy{ +public class ApplySavingsCommandStrategy implements CommandStrategy { - private final SavingsAccountsApiResource savingsAccountsApiResource; - - @Autowired - public ApplySavingsCommandStrategy(final SavingsAccountsApiResource savingsAccountsApiResource) { - this.savingsAccountsApiResource = savingsAccountsApiResource; - } - - @Override - public BatchResponse execute(BatchRequest request) { - - final BatchResponse response = new BatchResponse(); - final String responseBody; + private final SavingsAccountsApiResource savingsAccountsApiResource; - response.setRequestId(request.getRequestId()); - response.setHeaders(request.getHeaders()); - - //Try-catch blocks to map exceptions to appropriate status codes - try { - - //Calls 'submitApplication' function from 'SavingsAccountsApiResource' to Apply Savings to an existing client - responseBody = savingsAccountsApiResource.submitApplication(request.getBody()); - - response.setStatusCode(200); - //Sets the body of the response after savings is successfully applied - response.setBody(responseBody); - - } - catch (RuntimeException e) { - - //Gets an object of type ErrorInfo, containing information about raised exception - ErrorInfo ex = ErrorHandler.handler(e); - - response.setStatusCode(ex.getStatusCode()); - response.setBody(ex.getMessage()); - } - - return response; - } -} + @Autowired + public ApplySavingsCommandStrategy(final SavingsAccountsApiResource savingsAccountsApiResource) { + this.savingsAccountsApiResource = savingsAccountsApiResource; + } + + @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()); + + // Try-catch blocks to map exceptions to appropriate status codes + try { + + // Calls 'submitApplication' function from + // 'SavingsAccountsApiResource' to Apply Savings to an existing + // client + responseBody = savingsAccountsApiResource.submitApplication(request.getBody()); + + response.setStatusCode(200); + // Sets the body of the response after savings is successfully + // applied + response.setBody(responseBody); + + } catch (RuntimeException e) { + + // Gets an object of type ErrorInfo, containing information about + // raised exception + ErrorInfo ex = ErrorHandler.handler(e); + + response.setStatusCode(ex.getStatusCode()); + response.setBody(ex.getMessage()); + } + + return response; + } +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/batch/command/internal/CollectChargesCommandStrategy.java b/mifosng-provider/src/main/java/org/mifosplatform/batch/command/internal/CollectChargesCommandStrategy.java new file mode 100644 index 000000000..854c6533d --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/batch/command/internal/CollectChargesCommandStrategy.java @@ -0,0 +1,78 @@ +package org.mifosplatform.batch.command.internal; + +import javax.ws.rs.core.UriInfo; + +import org.mifosplatform.batch.command.CommandStrategy; +import org.mifosplatform.batch.domain.BatchRequest; +import org.mifosplatform.batch.domain.BatchResponse; +import org.mifosplatform.batch.exception.ErrorHandler; +import org.mifosplatform.batch.exception.ErrorInfo; +import org.mifosplatform.portfolio.loanaccount.api.LoanChargesApiResource; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +/** + * Implements {@link org.mifosplatform.batch.command.CommandStrategy} and + * Collect Charges for a Loan. It passes the contents of the body from the + * BatchRequest to + * {@link org.mifosplatform.portfolio.client.api.LoanChargesApiResource} and + * gets back the response. This class will also catch any errors raised by + * {@link org.mifosplatform.portfolio.client.api.LoanChargesApiResource} and map + * those errors to appropriate status codes in BatchResponse. + * + * @author Rishabh Shukla + * + * @see org.mifosplatform.batch.command.CommandStrategy + * @see org.mifosplatform.batch.domain.BatchRequest + * @see org.mifosplatform.batch.domain.BatchResponse + */ +@Component +public class CollectChargesCommandStrategy implements CommandStrategy { + + private final LoanChargesApiResource loanChargesApiResource; + + @Autowired + public CollectChargesCommandStrategy(final LoanChargesApiResource loanChargesApiResource) { + this.loanChargesApiResource = loanChargesApiResource; + } + + @Override + public BatchResponse execute(BatchRequest request, UriInfo uriInfo) { + + final BatchResponse response = new BatchResponse(); + final String responseBody; + + response.setRequestId(request.getRequestId()); + response.setHeaders(request.getHeaders()); + + final String[] pathParameters = request.getRelativeUrl().split("/"); + + // Pluck out the loanId out of the relative path + Long loanId = Long.parseLong(pathParameters[1]); + + // Try-catch blocks to map exceptions to appropriate status codes + try { + + // Calls 'retrieveAllLoanCharges' function from + // 'LoanChargesApiResource' to Collect + // Charges for a loan + responseBody = loanChargesApiResource.retrieveAllLoanCharges(loanId, uriInfo); + + response.setStatusCode(200); + // Sets the body of the response after Charges have been + // successfully collected + response.setBody(responseBody); + + } catch (RuntimeException e) { + + // Gets an object of type ErrorInfo, containing information about + // raised exception + ErrorInfo ex = ErrorHandler.handler(e); + + response.setStatusCode(ex.getStatusCode()); + response.setBody(ex.getMessage()); + } + + return response; + } +} diff --git a/mifosng-provider/src/main/java/org/mifosplatform/batch/command/internal/CreateChargeCommandStrategy.java b/mifosng-provider/src/main/java/org/mifosplatform/batch/command/internal/CreateChargeCommandStrategy.java new file mode 100644 index 000000000..af6d916ff --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/batch/command/internal/CreateChargeCommandStrategy.java @@ -0,0 +1,75 @@ +package org.mifosplatform.batch.command.internal; + +import javax.ws.rs.core.UriInfo; + +import org.mifosplatform.batch.command.CommandStrategy; +import org.mifosplatform.batch.domain.BatchRequest; +import org.mifosplatform.batch.domain.BatchResponse; +import org.mifosplatform.batch.exception.ErrorHandler; +import org.mifosplatform.batch.exception.ErrorInfo; +import org.mifosplatform.portfolio.loanaccount.api.LoanChargesApiResource; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +/** + * Implements {@link org.mifosplatform.batch.command.CommandStrategy} and Create + * Charge for a Loan. It passes the contents of the body from the BatchRequest + * to {@link org.mifosplatform.portfolio.client.api.LoanChargesApiResource} and + * gets back the response. This class will also catch any errors raised by + * {@link org.mifosplatform.portfolio.client.api.LoanChargesApiResource} and map + * those errors to appropriate status codes in BatchResponse. + * + * @author Rishabh Shukla + * + * @see org.mifosplatform.batch.command.CommandStrategy + * @see org.mifosplatform.batch.domain.BatchRequest + * @see org.mifosplatform.batch.domain.BatchResponse + */ +@Component +public class CreateChargeCommandStrategy implements CommandStrategy { + + private final LoanChargesApiResource loanChargesApiResource; + + @Autowired + public CreateChargeCommandStrategy(final LoanChargesApiResource loanChargesApiResource) { + this.loanChargesApiResource = loanChargesApiResource; + } + + @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 String[] pathParameters = request.getRelativeUrl().split("/"); + Long loanId = Long.parseLong(pathParameters[1]); + + // Try-catch blocks to map exceptions to appropriate status codes + try { + + // Calls 'executeLoanCharge' function from 'LoanChargesApiResource' + // to create + // a new charge for a loan + responseBody = loanChargesApiResource.executeLoanCharge(loanId, null, request.getBody()); + + response.setStatusCode(200); + // Sets the body of the response after Charge has been successfully + // created + response.setBody(responseBody); + + } catch (RuntimeException e) { + + // Gets an object of type ErrorInfo, containing information about + // raised exception + ErrorInfo ex = ErrorHandler.handler(e); + + response.setStatusCode(ex.getStatusCode()); + response.setBody(ex.getMessage()); + } + + return response; + } +} diff --git a/mifosng-provider/src/main/java/org/mifosplatform/batch/command/internal/CreateClientCommandStrategy.java b/mifosng-provider/src/main/java/org/mifosplatform/batch/command/internal/CreateClientCommandStrategy.java index 5d126d8fd..7b2fe9726 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/batch/command/internal/CreateClientCommandStrategy.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/batch/command/internal/CreateClientCommandStrategy.java @@ -1,5 +1,7 @@ package org.mifosplatform.batch.command.internal; +import javax.ws.rs.core.UriInfo; + import org.mifosplatform.batch.command.CommandStrategy; import org.mifosplatform.batch.domain.BatchRequest; import org.mifosplatform.batch.domain.BatchResponse; @@ -11,11 +13,12 @@ import org.springframework.stereotype.Component; /** * Implements {@link org.mifosplatform.batch.command.CommandStrategy} to handle - * creation of a new client. It passes the contents of the body from the BatchRequest - * to {@link org.mifosplatform.portfolio.client.api.ClientsApiResource} and gets back - * the response. This class will also catch any errors raised by - * {@link org.mifosplatform.portfolio.client.api.ClientsApiResource} and map those errors - * to appropriate status codes in BatchResponse. + * creation of a new client. It passes the contents of the body from the + * BatchRequest to + * {@link org.mifosplatform.portfolio.client.api.ClientsApiResource} and gets + * back the response. This class will also catch any errors raised by + * {@link org.mifosplatform.portfolio.client.api.ClientsApiResource} and map + * those errors to appropriate status codes in BatchResponse. * * @author Rishabh Shukla * @@ -24,45 +27,47 @@ import org.springframework.stereotype.Component; * @see org.mifosplatform.batch.domain.BatchResponse */ @Component -public class CreateClientCommandStrategy implements CommandStrategy{ +public class CreateClientCommandStrategy implements CommandStrategy { - private final ClientsApiResource clientsApiResource; - - @Autowired - public CreateClientCommandStrategy(final ClientsApiResource clientsApiResource) { - this.clientsApiResource = clientsApiResource; - } - - @Override - public BatchResponse execute(final BatchRequest request) { - - final BatchResponse response = new BatchResponse(); - final String responseBody; + private final ClientsApiResource clientsApiResource; - response.setRequestId(request.getRequestId()); - response.setHeaders(request.getHeaders()); - - //Try-catch blocks to map exceptions to appropriate status codes - try { - - //Calls 'create' function from 'ClientsApiResource' to create a new client - responseBody = clientsApiResource.create(request.getBody()); - - response.setStatusCode(200); - //Sets the body of the response after the successful creation of the client - response.setBody(responseBody); - - } - catch (RuntimeException e) { - - //Gets an object of type ErrorInfo, containing information about raised exception - ErrorInfo ex = ErrorHandler.handler(e); - - response.setStatusCode(ex.getStatusCode()); - response.setBody(ex.getMessage()); - } - - return response; - } + @Autowired + public CreateClientCommandStrategy(final ClientsApiResource clientsApiResource) { + this.clientsApiResource = clientsApiResource; + } + + @Override + public BatchResponse execute(final BatchRequest request, @SuppressWarnings("unused") UriInfo uriInfo) { + + final BatchResponse response = new BatchResponse(); + final String responseBody; + + response.setRequestId(request.getRequestId()); + response.setHeaders(request.getHeaders()); + + // Try-catch blocks to map exceptions to appropriate status codes + try { + + // Calls 'create' function from 'ClientsApiResource' to create a new + // client + responseBody = clientsApiResource.create(request.getBody()); + + response.setStatusCode(200); + // Sets the body of the response after the successful creation of + // the client + response.setBody(responseBody); + + } catch (RuntimeException e) { + + // Gets an object of type ErrorInfo, containing information about + // raised exception + ErrorInfo ex = ErrorHandler.handler(e); + + response.setStatusCode(ex.getStatusCode()); + response.setBody(ex.getMessage()); + } + + return response; + } } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/batch/command/internal/UnknownCommandStrategy.java b/mifosng-provider/src/main/java/org/mifosplatform/batch/command/internal/UnknownCommandStrategy.java index 27b9f7a1f..4fc879ed8 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/batch/command/internal/UnknownCommandStrategy.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/batch/command/internal/UnknownCommandStrategy.java @@ -1,5 +1,7 @@ package org.mifosplatform.batch.command.internal; +import javax.ws.rs.core.UriInfo; + import org.mifosplatform.batch.command.CommandStrategy; import org.mifosplatform.batch.domain.BatchRequest; import org.mifosplatform.batch.domain.BatchResponse; @@ -7,25 +9,25 @@ import org.springframework.stereotype.Component; /** * Provides a default CommandStrategy by implementing - * {@link org.mifosplatform.batch.command.CommandStrategy} - * in case there is no appropriate command strategy with requested - * 'method' and 'resoureUrl'. + * {@link org.mifosplatform.batch.command.CommandStrategy} in case there is no + * appropriate command strategy with requested 'method' and 'resoureUrl'. * * @author Rishabh Shukla */ @Component public class UnknownCommandStrategy implements CommandStrategy { - @Override - public BatchResponse execute(BatchRequest batchRequest) { - - final BatchResponse batchResponse = new BatchResponse(); - - batchResponse.setRequestId(batchRequest.getRequestId()); - batchResponse.setStatusCode(501); - - return batchResponse; - } + @Override + public BatchResponse execute(BatchRequest batchRequest, @SuppressWarnings("unused") UriInfo uriInfo) { + + final BatchResponse batchResponse = new BatchResponse(); + + batchResponse.setRequestId(batchRequest.getRequestId()); + batchResponse.setStatusCode(501); + batchResponse.setBody("Resource with method " + batchRequest.getMethod() + " and relativeUrl " + batchRequest.getRelativeUrl() + + " doesn't exist"); + + return batchResponse; + } - } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/batch/command/internal/UpdateClientCommandStrategy.java b/mifosng-provider/src/main/java/org/mifosplatform/batch/command/internal/UpdateClientCommandStrategy.java index d8469b047..db35d4fda 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/batch/command/internal/UpdateClientCommandStrategy.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/batch/command/internal/UpdateClientCommandStrategy.java @@ -1,5 +1,7 @@ package org.mifosplatform.batch.command.internal; +import javax.ws.rs.core.UriInfo; + import org.mifosplatform.batch.command.CommandStrategy; import org.mifosplatform.batch.domain.BatchRequest; import org.mifosplatform.batch.domain.BatchResponse; @@ -10,12 +12,13 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; /** - * Implements {@link org.mifosplatform.batch.command.CommandStrategy} and updates the - * information of an existing client. It passes the contents of the body from the BatchRequest - * to {@link org.mifosplatform.portfolio.client.api.ClientsApiResource} and gets back - * the response. This class will also catch any errors raised by - * {@link org.mifosplatform.portfolio.client.api.ClientsApiResource} and map those errors - * to appropriate status codes in BatchResponse. + * Implements {@link org.mifosplatform.batch.command.CommandStrategy} and + * updates the information of an existing client. It passes the contents of the + * body from the BatchRequest to + * {@link org.mifosplatform.portfolio.client.api.ClientsApiResource} and gets + * back the response. This class will also catch any errors raised by + * {@link org.mifosplatform.portfolio.client.api.ClientsApiResource} and map + * those errors to appropriate status codes in BatchResponse. * * @author Rishabh Shukla * @@ -26,46 +29,49 @@ import org.springframework.stereotype.Component; @Component public class UpdateClientCommandStrategy implements CommandStrategy { - private final ClientsApiResource clientsApiResource; - - @Autowired - public UpdateClientCommandStrategy(final ClientsApiResource clientsApiResource) { - this.clientsApiResource = clientsApiResource; - } - - @Override - public BatchResponse execute(BatchRequest request) { - - final BatchResponse response = new BatchResponse(); - final String responseBody; + private final ClientsApiResource clientsApiResource; - response.setRequestId(request.getRequestId()); - response.setHeaders(request.getHeaders()); - - //Get the clientID - final String relativeUrl = request.getRelativeUrl(); - final Long clientId = Long.parseLong(relativeUrl.substring(relativeUrl.indexOf('/') + 1)); - - //Try-catch blocks to map exceptions to appropriate status codes - try { - - //Calls 'update' function from 'ClientsApiResource' to update a client - responseBody = clientsApiResource.update(clientId, request.getBody()); - - response.setStatusCode(200); - //Sets the body of the response after the successful update of client information - response.setBody(responseBody); - - } catch (RuntimeException e) { - - //Gets an object of type ErrorInfo, containing information about raised exception - ErrorInfo ex = ErrorHandler.handler(e); - - response.setStatusCode(ex.getStatusCode()); - response.setBody(ex.getMessage()); - } - - return response; - } + @Autowired + public UpdateClientCommandStrategy(final ClientsApiResource clientsApiResource) { + this.clientsApiResource = clientsApiResource; + } + + @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()); + + // Get the clientID + final String relativeUrl = request.getRelativeUrl(); + final Long clientId = Long.parseLong(relativeUrl.substring(relativeUrl.indexOf('/') + 1)); + + // Try-catch blocks to map exceptions to appropriate status codes + try { + + // Calls 'update' function from 'ClientsApiResource' to update a + // client + responseBody = clientsApiResource.update(clientId, request.getBody()); + + response.setStatusCode(200); + // Sets the body of the response after the successful update of + // client information + response.setBody(responseBody); + + } catch (RuntimeException e) { + + // Gets an object of type ErrorInfo, containing information about + // raised exception + ErrorInfo ex = ErrorHandler.handler(e); + + response.setStatusCode(ex.getStatusCode()); + response.setBody(ex.getMessage()); + } + + return response; + } } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/batch/domain/BatchRequest.java b/mifosng-provider/src/main/java/org/mifosplatform/batch/domain/BatchRequest.java index 5132031bc..e13084842 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/batch/domain/BatchRequest.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/batch/domain/BatchRequest.java @@ -3,163 +3,170 @@ package org.mifosplatform.batch.domain; import java.util.Set; /** - * Provides an object for separate HTTP requests in the Batch Request for Batch API. - * A requestId is also included as data field which takes care of dependency issues - * among various requests. This class also provides getter and setter functions to - * access Batch Request data fields. + * Provides an object for separate HTTP requests in the Batch Request for Batch + * API. A requestId is also included as data field which takes care of + * dependency issues among various requests. This class also provides getter and + * setter functions to access Batch Request data fields. * - * @author Rishabh Shukla + * @author Rishabh Shukla * * @see org.mifosplatform.batch.api.BatchApiResource * @see Header */ public class BatchRequest { - - private Long requestId; - private String relativeUrl; - private String method; - private Set
headers; - private Long reference; - private String body; - - /** - * Constructs a 'BatchRequest' with requestId, relativeUrl, method, headers, reference and - * body of the incoming request. - * - * @param requestId of HTTP request. - * @param relativeUrl of HTTP request. - * @param method of HTTP request. - * @param headers of HTTP request. - * @param reference of HTTP request. - * @param body of HTTP request. - * - * @see Header - */ - public BatchRequest(Long requestId, String relativeUrl, String method, Set
headers, - Long reference, String body) { - - this.requestId = requestId; - this.relativeUrl = relativeUrl; - this.method = method; - this.headers = headers; - this.reference = reference; - this.body = body; - } - - /** - * Constructs a default constructor of 'BatchRequest' - */ - public BatchRequest() { - - } - - /** - * Returns the value of 'requestId' of an object of this class. - * - * @return requestId of the HTTP request. - */ - public Long getRequestId() { - return this.requestId; - } - - /** - * Sets the value of 'requestId' of an object of this class. - * - * @param requestId - */ - public void setRequestId(Long requestId) { - this.requestId = requestId; - } - - /** - * Returns the value of 'relativeUrl' of an object of this class. - * - * @return relativeUrl of the HTTP request. - */ - public String getRelativeUrl() { - return this.relativeUrl; - } - - /** - * Sets the value of 'relativeUrl' of an object of this class. - * - * @param relativeUrl - */ - public void setRelativeUrl(String relativeUrl) { - this.relativeUrl = relativeUrl; - } - - /** - * Returns the value of 'method' of an object of this class. - * - * @return method of the HTTP request. - */ - public String getMethod() { - return this.method; - } - - /** - * Sets the value of 'method' of the object of this class. - * - * @param method - */ - public void setMethod(String method) { - this.method = method; - } - - /** - * Returns the values of 'headers' of {@link Header} type of an object of this class. - * - * @return headers of the HTTP request. - * @see Header - */ - public Set
getHeaders() { - return this.headers; - } - - /** - * Sets the values of 'headers' of {@link Header} type of an object of this class. - * - * @param headers - * @see Header - */ - public void setHeaders(Set
headers) { - this.headers = headers; - } - - /** - * Returns the value of 'reference' of an object of this class - * - * @return reference of the HTTP request - */ - public Long getReference() { - return this.reference; - } - - /** - * Sets the value of 'reference' of an object of this class. - * - * @param reference - */ - public void setReference(Long reference) { - this.reference = reference; - } - - /** - * Returns the value of 'body' of an object of this class. - * - * @return body of the HTTP request. - */ - public String getBody() { - return this.body; - } - - /** - * Sets the value of 'body' of an object of this class. - * - * @param body - */ - public void setBody(String body) { - this.body = body; - } + + private Long requestId; + private String relativeUrl; + private String method; + private Set
headers; + private Long reference; + private String body; + + /** + * Constructs a 'BatchRequest' with requestId, relativeUrl, method, headers, + * reference and body of the incoming request. + * + * @param requestId + * of HTTP request. + * @param relativeUrl + * of HTTP request. + * @param method + * of HTTP request. + * @param headers + * of HTTP request. + * @param reference + * of HTTP request. + * @param body + * of HTTP request. + * + * @see Header + */ + public BatchRequest(Long requestId, String relativeUrl, String method, Set
headers, Long reference, String body) { + + this.requestId = requestId; + this.relativeUrl = relativeUrl; + this.method = method; + this.headers = headers; + this.reference = reference; + this.body = body; + } + + /** + * Constructs a default constructor of 'BatchRequest' + */ + public BatchRequest() { + + } + + /** + * Returns the value of 'requestId' of an object of this class. + * + * @return requestId of the HTTP request. + */ + public Long getRequestId() { + return this.requestId; + } + + /** + * Sets the value of 'requestId' of an object of this class. + * + * @param requestId + */ + public void setRequestId(Long requestId) { + this.requestId = requestId; + } + + /** + * Returns the value of 'relativeUrl' of an object of this class. + * + * @return relativeUrl of the HTTP request. + */ + public String getRelativeUrl() { + return this.relativeUrl; + } + + /** + * Sets the value of 'relativeUrl' of an object of this class. + * + * @param relativeUrl + */ + public void setRelativeUrl(String relativeUrl) { + this.relativeUrl = relativeUrl; + } + + /** + * Returns the value of 'method' of an object of this class. + * + * @return method of the HTTP request. + */ + public String getMethod() { + return this.method; + } + + /** + * Sets the value of 'method' of the object of this class. + * + * @param method + */ + public void setMethod(String method) { + this.method = method; + } + + /** + * Returns the values of 'headers' of {@link Header} type of an object of + * this class. + * + * @return headers of the HTTP request. + * @see Header + */ + public Set
getHeaders() { + return this.headers; + } + + /** + * Sets the values of 'headers' of {@link Header} type of an object of this + * class. + * + * @param headers + * @see Header + */ + public void setHeaders(Set
headers) { + this.headers = headers; + } + + /** + * Returns the value of 'reference' of an object of this class + * + * @return reference of the HTTP request + */ + public Long getReference() { + return this.reference; + } + + /** + * Sets the value of 'reference' of an object of this class. + * + * @param reference + */ + public void setReference(Long reference) { + this.reference = reference; + } + + /** + * Returns the value of 'body' of an object of this class. + * + * @return body of the HTTP request. + */ + public String getBody() { + return this.body; + } + + /** + * Sets the value of 'body' of an object of this class. + * + * @param body + */ + public void setBody(String body) { + this.body = body; + } } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/batch/domain/BatchResponse.java b/mifosng-provider/src/main/java/org/mifosplatform/batch/domain/BatchResponse.java index 74a1f845e..d2e3865f3 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/batch/domain/BatchResponse.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/batch/domain/BatchResponse.java @@ -3,9 +3,10 @@ package org.mifosplatform.batch.domain; import java.util.Set; /** - * Provides an object for separate HTTP responses in the Batch Response for Batch API. - * It contains all the information about a particular HTTP response in the Batch Response. - * Getter and Setter functions are also included to access response data fields. + * Provides an object for separate HTTP responses in the Batch Response for + * Batch API. It contains all the information about a particular HTTP response + * in the Batch Response. Getter and Setter functions are also included to + * access response data fields. * * @author Rishabh Shukla * @@ -15,106 +16,108 @@ import java.util.Set; */ public class BatchResponse { - private Long requestId; - private Integer statusCode; - private Set
headers; - private String body; - - /** - * Constructs a 'BatchResponse' with requestId, statusCode, headers - * and body of the HTTP requests. - * - * @param requestId - * @param statusCode - * @param headers - * @param body - * @see Header - */ - public BatchResponse(Long requestId, Integer statusCode, Set
headers, String body) { - this.requestId = requestId; - this.statusCode = statusCode; - this.headers = headers; - this.body = body; - } - - /** - * Constructs a default constructor of 'BatchResponse' - */ - public BatchResponse() { + private Long requestId; + private Integer statusCode; + private Set
headers; + private String body; - } - - /** - * Returns the 'requestId' of an object of this class. - * - * @return requestId of the HTTP request. - */ - public Long getRequestId() { - return this.requestId; - } - - /** - * Sets the value of 'requestId' of an object of this class. - * - * @param requestId - */ - public void setRequestId(Long requestId) { - this.requestId = requestId; - } - - /** - * Returns the 'statusCode' of an object of this class. - * - * @return statusCode of the HTTP request. - */ - public Integer getStatusCode() { - return this.statusCode; - } - - /** - * Sets the value of 'statusCode' of an object of this class. - * - * @param statusCode - */ - public void setStatusCode(Integer statusCode) { - this.statusCode = statusCode; - } - - /** - * Returns the 'headers' of {@link Header} type of an object of this class. - * - * @return headers of the HTTP request. - * @see Header - */ - public Set
getHeaders() { - return this.headers; - } - - /** - * Sets the value of 'headers' of {@link Header} type of an object of this class. - * - * @param headers of {@link Header} Type - * @see Header - */ - public void setHeaders(Set
headers) { - this.headers = headers; - } - - /** - * Returns the 'body' of an object of this class. - * - * @return body of the HTTP request. - */ - public String getBody() { - return this.body; - } - - /** - * Sets the value of 'body' of an object of this class. - * - * @param body - */ - public void setBody(String body) { - this.body = body; - } + /** + * Constructs a 'BatchResponse' with requestId, statusCode, headers and body + * of the HTTP requests. + * + * @param requestId + * @param statusCode + * @param headers + * @param body + * @see Header + */ + public BatchResponse(Long requestId, Integer statusCode, Set
headers, String body) { + this.requestId = requestId; + this.statusCode = statusCode; + this.headers = headers; + this.body = body; + } + + /** + * Constructs a default constructor of 'BatchResponse' + */ + public BatchResponse() { + + } + + /** + * Returns the 'requestId' of an object of this class. + * + * @return requestId of the HTTP request. + */ + public Long getRequestId() { + return this.requestId; + } + + /** + * Sets the value of 'requestId' of an object of this class. + * + * @param requestId + */ + public void setRequestId(Long requestId) { + this.requestId = requestId; + } + + /** + * Returns the 'statusCode' of an object of this class. + * + * @return statusCode of the HTTP request. + */ + public Integer getStatusCode() { + return this.statusCode; + } + + /** + * Sets the value of 'statusCode' of an object of this class. + * + * @param statusCode + */ + public void setStatusCode(Integer statusCode) { + this.statusCode = statusCode; + } + + /** + * Returns the 'headers' of {@link Header} type of an object of this class. + * + * @return headers of the HTTP request. + * @see Header + */ + public Set
getHeaders() { + return this.headers; + } + + /** + * Sets the value of 'headers' of {@link Header} type of an object of this + * class. + * + * @param headers + * of {@link Header} Type + * @see Header + */ + public void setHeaders(Set
headers) { + this.headers = headers; + } + + /** + * Returns the 'body' of an object of this class. + * + * @return body of the HTTP request. + */ + public String getBody() { + return this.body; + } + + /** + * Sets the value of 'body' of an object of this class. + * + * @param body + */ + public void setBody(String body) { + this.body = body; + } } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/batch/domain/Header.java b/mifosng-provider/src/main/java/org/mifosplatform/batch/domain/Header.java index ecd7824bf..94c01c064 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/batch/domain/Header.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/batch/domain/Header.java @@ -1,9 +1,9 @@ package org.mifosplatform.batch.domain; /** - * Provides an object to handle HTTP headers as name and value pairs for Batch API. - * It is used in {@link BatchRequest} and {@link BatchResponse} to store the - * information regarding the headers in incoming and outgoing JSON Strings. + * Provides an object to handle HTTP headers as name and value pairs for Batch + * API. It is used in {@link BatchRequest} and {@link BatchResponse} to store + * the information regarding the headers in incoming and outgoing JSON Strings. * * @author Rishabh Shukla * @@ -11,62 +11,64 @@ package org.mifosplatform.batch.domain; * @see BatchResponse */ public class Header { - - private String name; - private String value; - - /** - * Constructs a 'Header' with the name and value of HTTP headers. - * - * @param name of the HTTP header. - * @param value of the HTTP header. - */ - public Header(String name, String value) { - this.name = name; - this.value = value; - } - - /** - * Constructs a default constructor of 'Header' - */ - public Header() { - - } - - /** - * Returns the 'name' data field of the object of this class. - * - * @return name data field of this class - */ - public String getName() { - return this.name; - } - - /** - * Sets 'name' data field of this class. - * - * @param name - */ - public void setName(String name) { - this.name = name; - } - - /** - * Returns the 'value' data field of the object of this class. - * - * @return value data field of this class - */ - public String getValue() { - return this.value; - } - - /** - * Sets 'value' data field of this class. - * - * @param value - */ - public void setValue(String value) { - this.value = value; - } + + private String name; + private String value; + + /** + * Constructs a 'Header' with the name and value of HTTP headers. + * + * @param name + * of the HTTP header. + * @param value + * of the HTTP header. + */ + public Header(String name, String value) { + this.name = name; + this.value = value; + } + + /** + * Constructs a default constructor of 'Header' + */ + public Header() { + + } + + /** + * Returns the 'name' data field of the object of this class. + * + * @return name data field of this class + */ + public String getName() { + return this.name; + } + + /** + * Sets 'name' data field of this class. + * + * @param name + */ + public void setName(String name) { + this.name = name; + } + + /** + * Returns the 'value' data field of the object of this class. + * + * @return value data field of this class + */ + public String getValue() { + return this.value; + } + + /** + * Sets 'value' data field of this class. + * + * @param value + */ + public void setValue(String value) { + this.value = value; + } } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/batch/exception/ErrorHandler.java b/mifosng-provider/src/main/java/org/mifosplatform/batch/exception/ErrorHandler.java index ec49da4e9..aed59e948 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/batch/exception/ErrorHandler.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/batch/exception/ErrorHandler.java @@ -3,52 +3,90 @@ package org.mifosplatform.batch.exception; import org.mifosplatform.infrastructure.core.exception.AbstractPlatformResourceNotFoundException; import org.mifosplatform.infrastructure.core.exception.PlatformApiDataValidationException; import org.mifosplatform.infrastructure.core.exception.PlatformDataIntegrityException; +import org.mifosplatform.infrastructure.core.exception.PlatformInternalServerException; import org.mifosplatform.infrastructure.core.exception.UnsupportedParameterException; +import org.mifosplatform.infrastructure.core.exceptionmapper.PlatformApiDataValidationExceptionMapper; +import org.mifosplatform.infrastructure.core.exceptionmapper.PlatformDataIntegrityExceptionMapper; +import org.mifosplatform.infrastructure.core.exceptionmapper.PlatformInternalServerExceptionMapper; +import org.mifosplatform.infrastructure.core.exceptionmapper.PlatformResourceNotFoundExceptionMapper; +import org.mifosplatform.infrastructure.core.exceptionmapper.UnsupportedParameterExceptionMapper; import org.springframework.transaction.TransactionException; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; + /** - * Provides an Error Handler method that returns an object of type {@link ErrorInfo} - * to the CommandStrategy which raised the exception. This class uses various subclasses - * of RuntimeException to check the kind of exception raised and provide appropriate - * status and error codes for each one of the raised exception. + * Provides an Error Handler method that returns an object of type + * {@link ErrorInfo} to the CommandStrategy which raised the exception. This + * class uses various subclasses of RuntimeException to check the kind of + * exception raised and provide appropriate status and error codes for each one + * of the raised exception. * * @author Rishabh Shukla * * @see org.mifosplatform.batch.command.CommandStrategy - * @see org.mifosplatform.batch.command.internal.CreateClientCommandStrategy + * @see org.mifosplatform.batch.command.internal.CreateClientCommandStrategy */ -public class ErrorHandler extends RuntimeException{ - - /** - * Sole Constructor - */ - ErrorHandler() { +public class ErrorHandler extends RuntimeException { + + private static Gson jsonHelper = new GsonBuilder().setPrettyPrinting().create(); + + /** + * Sole Constructor + */ + ErrorHandler() { super(); } - - /** - * Returns an object of ErrorInfo type containing the information regarding - * the raised error. - * - * @param exception - * @return ErrorInfo - */ - public static ErrorInfo handler(RuntimeException exception) { - - if(exception instanceof AbstractPlatformResourceNotFoundException) { - return new ErrorInfo(404, 1001, "Requested Resource was not Found: Check for any unavailable Parameters"); - } else if(exception instanceof UnsupportedParameterException) { - return new ErrorInfo(400, 2001, "UnsupportedParameterException: Check for any unsupported Parameters"); - } else if(exception instanceof PlatformApiDataValidationException) { - return new ErrorInfo(400, 2002, "ApiDataValidationException: Re-Check the input data"); - } else if(exception instanceof PlatformDataIntegrityException) { - return new ErrorInfo(403, 3001, "DataIntegrityException: Check for any duplicate data"); - } else if(exception instanceof TransactionException) { - return new ErrorInfo(400, 4001, "TransactionException: One or more of your requests were unsuccessful," + - " reverting back all the transactions in this Batch Request"); - } - - return new ErrorInfo(500, 9999, "Internal Server Error"); - - } + + /** + * Returns an object of ErrorInfo type containing the information regarding + * the raised error. + * + * @param exception + * @return ErrorInfo + */ + public static ErrorInfo handler(final RuntimeException exception) { + + if (exception instanceof AbstractPlatformResourceNotFoundException) { + + final PlatformResourceNotFoundExceptionMapper mapper = new PlatformResourceNotFoundExceptionMapper(); + final String errorBody = jsonHelper + .toJson(mapper.toResponse((AbstractPlatformResourceNotFoundException) exception).getEntity()); + + return new ErrorInfo(404, 1001, errorBody); + + } else if (exception instanceof UnsupportedParameterException) { + + final UnsupportedParameterExceptionMapper mapper = new UnsupportedParameterExceptionMapper(); + final String errorBody = jsonHelper.toJson(mapper.toResponse((UnsupportedParameterException) exception).getEntity()); + + return new ErrorInfo(400, 2001, errorBody); + + } else if (exception instanceof PlatformApiDataValidationException) { + + final PlatformApiDataValidationExceptionMapper mapper = new PlatformApiDataValidationExceptionMapper(); + final String errorBody = jsonHelper.toJson(mapper.toResponse((PlatformApiDataValidationException) exception).getEntity()); + + return new ErrorInfo(400, 2002, errorBody); + + } else if (exception instanceof PlatformDataIntegrityException) { + + final PlatformDataIntegrityExceptionMapper mapper = new PlatformDataIntegrityExceptionMapper(); + final String errorBody = jsonHelper.toJson(mapper.toResponse((PlatformDataIntegrityException) exception).getEntity()); + + return new ErrorInfo(403, 3001, errorBody); + + } else if (exception instanceof TransactionException) { + return new ErrorInfo(400, 4001, "Exception " + exception.getCause() + " " + exception.getMessage()); + + } else if (exception instanceof PlatformInternalServerException) { + + final PlatformInternalServerExceptionMapper mapper = new PlatformInternalServerExceptionMapper(); + final String errorBody = jsonHelper.toJson(mapper.toResponse((PlatformInternalServerException) exception).getEntity()); + + return new ErrorInfo(500, 5001, errorBody); + } + + return new ErrorInfo(500, 9999, exception.toString() + " " + exception.getStackTrace()); + } } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/batch/exception/ErrorInfo.java b/mifosng-provider/src/main/java/org/mifosplatform/batch/exception/ErrorInfo.java index 8240bb4f1..969481af4 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/batch/exception/ErrorInfo.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/batch/exception/ErrorInfo.java @@ -5,7 +5,7 @@ package org.mifosplatform.batch.exception; * commandStrategy classes. * * @author Rishabh Shukla - * + * * @see ErrorHandler */ public final class ErrorInfo { @@ -26,15 +26,15 @@ public final class ErrorInfo { this.statusCode = statusCode; this.errorCode = errorCode; this.message = message; - } + } /** - * Constructor so JSON serialization will work with out special Serialiazer + * Constructor so JSON serialization will work with out special Serialiazer */ ErrorInfo() { super(); - } - + } + /** * Getter method to provide the statusCode for an object of this type. * @@ -43,7 +43,7 @@ public final class ErrorInfo { public Integer getStatusCode() { return this.statusCode; } - + /** * Setter method to set the statusCode for an object of this type. * @@ -61,7 +61,7 @@ public final class ErrorInfo { public Integer getErrorCode() { return this.errorCode; } - + /** * Setter method to set the errorCode for an object of this type. * @@ -72,8 +72,8 @@ public final class ErrorInfo { } /** - * Getter method to provide the message of the error for an object - * of this type. + * Getter method to provide the message of the error for an object of this + * type. * * @return String */ @@ -82,12 +82,11 @@ public final class ErrorInfo { } /** - * Setter method to set the message of the error for an object - * of this type. + * Setter method to set the message of the error for an object of this type. * * @param message */ public void setMessage(final String message) { this.message = message; } - } +} diff --git a/mifosng-provider/src/main/java/org/mifosplatform/batch/serialization/BatchRequestJsonHelper.java b/mifosng-provider/src/main/java/org/mifosplatform/batch/serialization/BatchRequestJsonHelper.java index 1488e3ea2..8f1b4e0ad 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/batch/serialization/BatchRequestJsonHelper.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/batch/serialization/BatchRequestJsonHelper.java @@ -10,7 +10,8 @@ import org.springframework.stereotype.Component; import com.google.gson.reflect.TypeToken; /** - * Extends {@link org.mifosplatform.infrastructure.core.serialization.FromJsonHelper} to + * Extends + * {@link org.mifosplatform.infrastructure.core.serialization.FromJsonHelper} to * de-serialize the incoming String into a JSON List of type * {@link org.mifosplatform.batch.domain.BatchRequest} * @@ -21,17 +22,17 @@ import com.google.gson.reflect.TypeToken; */ @Component public class BatchRequestJsonHelper extends FromJsonHelper { - - /** - * Returns a list of batchRequests after de-serializing it from the input - * JSON string. - * - * @param json - * @return List - */ - public List extractList(final String json) { - final Type listType = new TypeToken>(){}.getType(); - final List requests = super.getGsonConverter().fromJson(json, listType); - return requests; - } + + /** + * Returns a list of batchRequests after de-serializing it from the input + * JSON string. + * + * @param json + * @return List + */ + public List extractList(final String json) { + final Type listType = new TypeToken>() {}.getType(); + final List requests = super.getGsonConverter().fromJson(json, listType); + return requests; + } } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/batch/service/BatchApiService.java b/mifosng-provider/src/main/java/org/mifosplatform/batch/service/BatchApiService.java index 0d0c33d05..33c17e463 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/batch/service/BatchApiService.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/batch/service/BatchApiService.java @@ -2,12 +2,14 @@ package org.mifosplatform.batch.service; import java.util.List; +import javax.ws.rs.core.UriInfo; + import org.mifosplatform.batch.domain.BatchRequest; import org.mifosplatform.batch.domain.BatchResponse; /** - * Provides an interface for service class, that implements the method to - * handle separate Batch Requests. + * Provides an interface for service class, that implements the method to handle + * separate Batch Requests. * * @author Rishabh Shukla * @@ -16,26 +18,30 @@ import org.mifosplatform.batch.domain.BatchResponse; * @see BatchApiServiceImpl */ public interface BatchApiService { - - /** - * Returns a list of {@link org.mifosplatform.batch.domain.BatchResponse}s by getting - * the appropriate CommandStrategy for every {@link org.mifosplatform.batch.domain.BatchRequest}. - * It will be used when the Query Parameter "enclosingTransaction "is set to 'false'. - * - * @param requestList - * @return List - */ - List handleBatchRequestsWithoutEnclosingTransaction(List requestList); - - /** - * returns a list of {@link org.mifosplatform.batch.domain.BatchResponse}s by getting - * the appropriate CommandStrategy for every {@link org.mifosplatform.batch.domain.BatchRequest}. - * It will be used when the Query Parameter "enclosingTransaction "is set to 'true'. If one or - * more of the requests are not completed properly then whole of the transaction will be rolled back - * properly. - * - * @param requestList - * @return List - */ - List handleBatchRequestsWithEnclosingTransaction(List requestList); + + /** + * Returns a list of {@link org.mifosplatform.batch.domain.BatchResponse}s + * by getting the appropriate CommandStrategy for every + * {@link org.mifosplatform.batch.domain.BatchRequest}. It will be used when + * the Query Parameter "enclosingTransaction "is set to 'false'. + * + * @param requestList + * @param uriInfo + * @return List + */ + List handleBatchRequestsWithoutEnclosingTransaction(List requestList, UriInfo uriInfo); + + /** + * returns a list of {@link org.mifosplatform.batch.domain.BatchResponse}s + * by getting the appropriate CommandStrategy for every + * {@link org.mifosplatform.batch.domain.BatchRequest}. It will be used when + * the Query Parameter "enclosingTransaction "is set to 'true'. If one or + * more of the requests are not completed properly then whole of the + * transaction will be rolled back properly. + * + * @param requestList + * @param uriInfo + * @return List + */ + List handleBatchRequestsWithEnclosingTransaction(List requestList, UriInfo uriInfo); } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/batch/service/BatchApiServiceImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/batch/service/BatchApiServiceImpl.java index 5b4a83f76..a5b7beef7 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/batch/service/BatchApiServiceImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/batch/service/BatchApiServiceImpl.java @@ -1,129 +1,205 @@ package org.mifosplatform.batch.service; import java.util.ArrayList; +import java.util.Comparator; import java.util.List; -import java.util.concurrent.ConcurrentHashMap; +import javax.ws.rs.core.Response; import javax.ws.rs.core.Response.Status; +import javax.ws.rs.core.UriInfo; import org.mifosplatform.batch.command.CommandContext; import org.mifosplatform.batch.command.CommandStrategy; import org.mifosplatform.batch.command.CommandStrategyProvider; import org.mifosplatform.batch.domain.BatchRequest; import org.mifosplatform.batch.domain.BatchResponse; +import org.mifosplatform.batch.exception.ErrorHandler; import org.mifosplatform.batch.exception.ErrorInfo; +import org.mifosplatform.batch.service.ResolutionHelper.BatchRequestNode; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; +import org.springframework.transaction.TransactionException; +import org.springframework.transaction.TransactionStatus; +import org.springframework.transaction.support.TransactionCallback; +import org.springframework.transaction.support.TransactionTemplate; import com.google.gson.Gson; +import edu.emory.mathcs.backport.java.util.Collections; + /** - * Implementation for {@link BatchApiService} to iterate through all the incoming - * requests and obtain the appropriate CommandStrategy from CommandStrategyProvider. + * Implementation for {@link BatchApiService} to iterate through all the + * incoming requests and obtain the appropriate CommandStrategy from + * CommandStrategyProvider. * * @author Rishabh Shukla - * + * * @see org.mifosplatform.batch.domain.BatchRequest * @see org.mifosplatform.batch.domain.BatchResponse * @see org.mifosplatform.batch.command.CommandStrategyProvider */ @Service -public class BatchApiServiceImpl implements BatchApiService{ - - private final CommandStrategyProvider strategyProvider; - private final ResolutionHelper resolutionHelper; - - /** - * Constructs a 'BatchApiServiceImpl' with an argument of - * {@link org.mifosplatform.batch.command.CommandStrategyProvider} type. - * - * @param strategyProvider - */ - @Autowired - public BatchApiServiceImpl(final CommandStrategyProvider strategyProvider, - final ResolutionHelper resolutionHelper) { - this.strategyProvider = strategyProvider; - this.resolutionHelper = resolutionHelper; - } +public class BatchApiServiceImpl implements BatchApiService { - /** - * Returns the response list by getting a proper {@link org.mifosplatform.batch.command.CommandStrategy}. - * execute() method of acquired commandStrategy is then provided with the separate Request. - * - * @param requestList - * @return List - */ - private List handleBatchRequests(final List requestList) { + private final CommandStrategyProvider strategyProvider; + private final ResolutionHelper resolutionHelper; + private final TransactionTemplate transactionTemplate; + private List checkList = new ArrayList<>(); - final List responseList = new ArrayList<>(); - - final ConcurrentHashMap> requestMap = this.resolutionHelper.getDependencyMap(requestList); - - for(ConcurrentHashMap.Entry> entry : requestMap.entrySet()) { - - final ArrayList mappedList = entry.getValue(); - - for(BatchRequest br: mappedList) { - - //If this request is dependent on any other request in the list - if(br.getReference() != null) { - - BatchResponse parentResponse = new BatchResponse(); - - //Fetch the response of the request on which it is dependent from responseList - for(final BatchResponse res: responseList) { - - if(res.getRequestId().equals(br.getReference())) { - parentResponse = res; - } - } - - //If parentResponse has returned a successful request - if(parentResponse.getStatusCode() == 200) { - br = this.resolutionHelper.resoluteRequest(br, parentResponse); - } else { - //Something went wrong with the parent request, create a response with status code 409 - final BatchResponse response = new BatchResponse(); - response.setRequestId(br.getRequestId()); - response.setStatusCode(Status.CONFLICT.getStatusCode()); - - //Some detail information about the error - final ErrorInfo conflictError = new ErrorInfo(Status.CONFLICT.getStatusCode(), 8001, - "Parent request with id " + parentResponse.getRequestId() + " was erroneous!"); - response.setBody(conflictError.getMessage()); - responseList.add(response); - - //Proceed with next list entry - continue; - } - } - - final CommandStrategy commandStrategy = this.strategyProvider.getCommandStrategy(CommandContext. - resource(br.getRelativeUrl()).method(br.getMethod()).build()); - - final BatchResponse response = commandStrategy.execute(br); - - responseList.add(response); - } - - } + /** + * Constructs a 'BatchApiServiceImpl' with an argument of + * {@link org.mifosplatform.batch.command.CommandStrategyProvider} type. + * + * @param strategyProvider + * @param resolutionHelper + * @param transactionTemplate + */ + @Autowired + public BatchApiServiceImpl(final CommandStrategyProvider strategyProvider, final ResolutionHelper resolutionHelper, + final TransactionTemplate transactionTemplate) { + this.strategyProvider = strategyProvider; + this.resolutionHelper = resolutionHelper; + this.transactionTemplate = transactionTemplate; + } - return responseList; - } - - @Override - public List handleBatchRequestsWithoutEnclosingTransaction(final - List requestList) { - - return handleBatchRequests(requestList); - } + /** + * Returns the response list by getting a proper + * {@link org.mifosplatform.batch.command.CommandStrategy}. execute() method + * of acquired commandStrategy is then provided with the separate Request. + * + * @param requestList + * @param uriInfo + * @return List + */ + private List handleBatchRequests(final List requestList, final UriInfo uriInfo) { - @Transactional - @Override - public List handleBatchRequestsWithEnclosingTransaction( final - List requestList) { - - return handleBatchRequests(requestList); - } + final List responseList = new ArrayList<>(requestList.size()); + + final List batchRequestNodes = this.resolutionHelper.getDependingRequests(requestList); + checkList.clear(); + + for (BatchRequestNode rootNode : batchRequestNodes) { + final BatchRequest rootRequest = rootNode.getRequest(); + final CommandStrategy commandStrategy = this.strategyProvider.getCommandStrategy(CommandContext + .resource(rootRequest.getRelativeUrl()).method(rootRequest.getMethod()).build()); + final BatchResponse rootResponse = commandStrategy.execute(rootRequest, uriInfo); + + responseList.add(rootResponse); + responseList.addAll(this.processChildRequests(rootNode, rootResponse, uriInfo)); + } + + Collections.sort(responseList, new Comparator() { + + @Override + public int compare(BatchResponse source, BatchResponse testee) { + return source.getRequestId().compareTo(testee.getRequestId()); + } + }); + + checkList = responseList; + return responseList; + + } + + private List processChildRequests(final BatchRequestNode rootRequest, BatchResponse rootResponse, UriInfo uriInfo) { + + final List childResponses = new ArrayList<>(); + if (rootRequest.getChildRequests().size() > 0) { + + for (BatchRequestNode childNode : rootRequest.getChildRequests()) { + + BatchRequest childRequest = childNode.getRequest(); + BatchResponse childResponse; + + try { + + if (rootResponse.getStatusCode().equals(200)) { + childRequest = this.resolutionHelper.resoluteRequest(childRequest, rootResponse); + final CommandStrategy commandStrategy = this.strategyProvider.getCommandStrategy(CommandContext + .resource(childRequest.getRelativeUrl()).method(childRequest.getMethod()).build()); + + childResponse = commandStrategy.execute(childRequest, uriInfo); + + } else { + // Something went wrong with the parent request, create + // a response with status code 409 + childResponse = new BatchResponse(); + childResponse.setRequestId(childRequest.getRequestId()); + childResponse.setStatusCode(Status.CONFLICT.getStatusCode()); + + // Some detail information about the error + final ErrorInfo conflictError = new ErrorInfo(Status.CONFLICT.getStatusCode(), 8001, "Parent request with id " + + rootResponse.getRequestId() + " was erroneous!"); + childResponse.setBody(conflictError.getMessage()); + } + childResponses.addAll(this.processChildRequests(childNode, childResponse, uriInfo)); + + } catch (Throwable ex) { + + childResponse = new BatchResponse(); + childResponse.setRequestId(childRequest.getRequestId()); + childResponse.setStatusCode(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + childResponse.setBody(ex.getMessage()); + + } + + childResponses.add(childResponse); + } + } + + return childResponses; + } + + @Override + public List handleBatchRequestsWithoutEnclosingTransaction(final List requestList, UriInfo uriInfo) { + + return handleBatchRequests(requestList, uriInfo); + } + + @Override + public List handleBatchRequestsWithEnclosingTransaction(final List requestList, final UriInfo uriInfo) { + + try { + return this.transactionTemplate.execute(new TransactionCallback>() { + + @Override + public List doInTransaction(TransactionStatus status) { + try { + return handleBatchRequests(requestList, uriInfo); + } catch (RuntimeException ex) { + + ErrorInfo e = ErrorHandler.handler(ex); + BatchResponse errResponse = new BatchResponse(); + errResponse.setStatusCode(e.getStatusCode()); + errResponse.setBody(e.getMessage()); + + List errResponseList = new ArrayList<>(); + errResponseList.add(errResponse); + + status.setRollbackOnly(); + return errResponseList; + } + } + + }); + } catch (TransactionException ex) { + ErrorInfo e = ErrorHandler.handler(ex); + BatchResponse errResponse = new BatchResponse(); + errResponse.setStatusCode(e.getStatusCode()); + + for (BatchResponse res : checkList) { + if (!res.getStatusCode().equals(200)) { + errResponse.setBody("Transaction is being rolled back. First erroneous request: \n" + new Gson().toJson(res)); + break; + } + } + + checkList.clear(); + List errResponseList = new ArrayList<>(); + errResponseList.add(errResponse); + + return errResponseList; + } + + } } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/batch/service/ResolutionHelper.java b/mifosng-provider/src/main/java/org/mifosplatform/batch/service/ResolutionHelper.java index 24512c873..b060f0af9 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/batch/service/ResolutionHelper.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/batch/service/ResolutionHelper.java @@ -3,7 +3,6 @@ package org.mifosplatform.batch.service; import java.util.ArrayList; import java.util.List; import java.util.Map.Entry; -import java.util.concurrent.ConcurrentHashMap; import org.mifosplatform.batch.domain.BatchRequest; import org.mifosplatform.batch.domain.BatchResponse; @@ -11,166 +10,201 @@ import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; +import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.jayway.jsonpath.JsonModel; /** - * Provides methods to create dependency map among the various batchRequests. - * It also provides method that takes care of dependency resolution among - * related requests. + * Provides methods to create dependency map among the various batchRequests. It + * also provides method that takes care of dependency resolution among related + * requests. * * @author Rishabh Shukla * @see BatchApiServiceImpl */ @Component public class ResolutionHelper { - - private FromJsonHelper fromJsonHelper; - - @Autowired - public ResolutionHelper(final FromJsonHelper fromJsonHelper) { - this.fromJsonHelper = fromJsonHelper; - } - - /** - * Returns a map containing requests that are divided in accordance of dependency relations - * among them. Each different list is identified with a "Key" which is the "requestId" of - * the request at topmost level in dependency hierarchy of that particular list. - * - * @param requestList - * @return ConcurrentHashMap> - */ - public ConcurrentHashMap> getDependencyMap(final List requestList) { - - //Create a map with a '-1L' which will contain a list of independent requests - final ConcurrentHashMap> dependencyMap = new ConcurrentHashMap<>(); - - dependencyMap.put(-1L, new ArrayList()); - - //For every request in the requestList - for(final BatchRequest br : requestList) { - - final Long reference = br.getReference(); - - //If current request is dependent on some other request - if(reference != null) { - - //Then find the request on which br is dependent on - for(final BatchRequest parentRequest : requestList) { - - //If request on which br is dependent is found - if(parentRequest.getRequestId().equals(reference)) { - - //Then start the process of adding it to one of the key in the dependencyMap - - //If referenced request is in the list with key "-1L" - if(dependencyMap.get(-1L).contains(parentRequest)) { - - //Then create a new list with key = reference - final ArrayList newList = new ArrayList<>(); - newList.add(parentRequest); - newList.add(br); - - //And add this list to the map - dependencyMap.put(reference, newList); - - //Also remove parentRequest from the list at '-1L' - final ArrayList listCopy = dependencyMap.get(-1L); - - listCopy.remove(parentRequest); - - dependencyMap.replace(-1L, listCopy); - } - //If referenced request is not in key '-1L' - else { - //Find the list in which it is present - for(final ConcurrentHashMap.Entry> entry: dependencyMap.entrySet()) { - if(entry.getValue().contains(parentRequest)) { - final ArrayList listCopy = entry.getValue(); - listCopy.add(br); - - //Add this request to this list - dependencyMap.replace(entry.getKey(), listCopy); - } - } - } - } - - } - } - //If request is independent then add it to '-1L' - else { - final ArrayList listCopy = dependencyMap.get(-1L); - listCopy.add(br); - - dependencyMap.replace(-1L, listCopy); - } - - } - - return dependencyMap; - } - /** - * Returns a BatchRequest after dependency resolution. It takes a request and the - * response of the request it is dependent upon as its arguments and change the body - * or relativeUrl of the request according to parent Request. - * - * @param request - * @param lastResponse - * @return BatchRequest - */ - public BatchRequest resoluteRequest(final BatchRequest request,final BatchResponse parentResponse) { - - //Create a duplicate request - final BatchRequest br = request; - - final JsonModel responseJsonModel = JsonModel.model(parentResponse.getBody()); - - //Gets the body from current Request as a JsonObject - final JsonObject jsonRequestBody = this.fromJsonHelper.parse(request.getBody()).getAsJsonObject(); - - JsonObject jsonResultBody = new JsonObject(); - - //Iterate through each element in the requestBody to find dependent parameter - for(Entry element: jsonRequestBody.entrySet()) { - - String paramVal = element.getValue().getAsString(); - - //If a dependent parameter is found - if(paramVal.contains("$.")) { - - //Get the value of the parameter from parent response - final String resParamValue = responseJsonModel.get(paramVal).toString(); + /** + * Provides a Node like object for the request tree. + * + * @author Rishabh shukla + * + */ + public class BatchRequestNode { - //Add the value after dependency resolution - jsonResultBody.add(element.getKey(), this.fromJsonHelper.parse(resParamValue)); - } - else { - jsonResultBody.add(element.getKey(), element.getValue()); - } - } + private BatchRequest request; + private final List childRequests = new ArrayList<>(); - //Set the body after dependency resolution - br.setBody(jsonResultBody.toString()); - - //Also check the relativeUrl for any dependency resolution - String relativeUrl = request.getRelativeUrl(); - - if(relativeUrl.contains("$.")) { - - final String parameter = relativeUrl.substring(relativeUrl.indexOf('/') + 1, relativeUrl.length()); - - //Get the value of the parameter from last response - final String resParamValue = responseJsonModel.get(parameter).toString(); + public BatchRequestNode() { + super(); + } + + public BatchRequest getRequest() { + return this.request; + } + + public void setRequest(BatchRequest request) { + this.request = request; + } + + public List getChildRequests() { + return this.childRequests; + } + + public void addChildRequest(final BatchRequestNode batchRequest) { + this.childRequests.add(batchRequest); + } + + } + + private FromJsonHelper fromJsonHelper; + + @Autowired + public ResolutionHelper(final FromJsonHelper fromJsonHelper) { + this.fromJsonHelper = fromJsonHelper; + } + + /** + * Returns a map containing requests that are divided in accordance of + * dependency relations among them. Each different list is identified with a + * "Key" which is the "requestId" of the request at topmost level in + * dependency hierarchy of that particular list. + * + * @param batchRequests + * @return List> + */ + public List getDependingRequests(final List batchRequests) { + final List rootRequests = new ArrayList<>(); + + for (BatchRequest batchRequest : batchRequests) { + if (batchRequest.getReference() == null) { + final BatchRequestNode node = new BatchRequestNode(); + node.setRequest(batchRequest); + rootRequests.add(node); + } else { + this.addDependingRequest(batchRequest, rootRequests); + } + } + + return rootRequests; + } + + private void addDependingRequest(final BatchRequest batchRequest, final List parentRequests) { + for (BatchRequestNode batchRequestNode : parentRequests) { + if (batchRequestNode.getRequest().getRequestId().equals(batchRequest.getReference())) { + final BatchRequestNode dependingRequest = new BatchRequestNode(); + dependingRequest.setRequest(batchRequest); + batchRequestNode.addChildRequest(dependingRequest); + } else { + addDependingRequest(batchRequest, batchRequestNode.getChildRequests()); + } + } + } + + /** + * Returns a BatchRequest after dependency resolution. It takes a request + * and the response of the request it is dependent upon as its arguments and + * change the body or relativeUrl of the request according to parent + * Request. + * + * @param request + * @param lastResponse + * @return BatchRequest + */ + public BatchRequest resoluteRequest(final BatchRequest request, final BatchResponse parentResponse) { + + // Create a duplicate request + final BatchRequest br = request; + + final JsonModel responseJsonModel = JsonModel.model(parentResponse.getBody()); + + // Gets the body from current Request as a JsonObject + final JsonObject jsonRequestBody = this.fromJsonHelper.parse(request.getBody()).getAsJsonObject(); + + JsonObject jsonResultBody = new JsonObject(); + + // Iterate through each element in the requestBody to find dependent + // parameter + for (Entry element : jsonRequestBody.entrySet()) { + final String key = element.getKey(); + final JsonElement value = resolveDependentVariables(element, responseJsonModel); + jsonResultBody.add(key, value); + } + + // Set the body after dependency resolution + br.setBody(jsonResultBody.toString()); + + // Also check the relativeUrl for any dependency resolution + String relativeUrl = request.getRelativeUrl(); + + if (relativeUrl.contains("$.")) { + + final String[] parameters = relativeUrl.split("/"); + + for (String parameter : parameters) { + if (parameter.contains("$.")) { + final String resParamValue = responseJsonModel.get(parameter).toString(); + relativeUrl = relativeUrl.replace(parameter, resParamValue); + br.setRelativeUrl(relativeUrl); + } + } + } + + return br; + } + + private JsonElement resolveDependentVariables(final Entry entryElement, final JsonModel responseJsonModel) { + JsonElement value = null; + + final JsonElement element = entryElement.getValue(); + + if (element.isJsonObject()) { + final JsonObject jsObject = element.getAsJsonObject(); + value = processJsonObject(jsObject, responseJsonModel); + } else if (element.isJsonArray()) { + final JsonArray jsElementArray = element.getAsJsonArray(); + value = processJsonArray(jsElementArray, responseJsonModel); + } else { + value = resolveDependentVariable(element, responseJsonModel); + } + return value; + } + + private JsonElement processJsonObject(final JsonObject jsObject, final JsonModel responseJsonModel) { + JsonObject valueObj = new JsonObject(); + for (Entry element : jsObject.entrySet()) { + final String key = element.getKey(); + final JsonElement value = resolveDependentVariable(element.getValue(), responseJsonModel); + valueObj.add(key, value); + } + return valueObj; + } + + private JsonArray processJsonArray(final JsonArray elementArray, final JsonModel responseJsonModel) { + + JsonArray valueArr = new JsonArray(); + + for (JsonElement element : elementArray) { + if (element.isJsonObject()) { + final JsonObject jsObject = element.getAsJsonObject(); + valueArr.add(processJsonObject(jsObject, responseJsonModel)); + } + } + + return valueArr; + } + + private JsonElement resolveDependentVariable(final JsonElement element, final JsonModel responseJsonModel) { + JsonElement value = element; + String paramVal = element.getAsString(); + if (paramVal.contains("$.")) { + // Get the value of the parameter from parent response + final String resParamValue = responseJsonModel.get(paramVal).toString(); + value = this.fromJsonHelper.parse(resParamValue); + } + return value; + } - relativeUrl = relativeUrl.replace(parameter, resParamValue); - - br.setRelativeUrl(relativeUrl); - } - - return br; - } - } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/core/exceptionmapper/PlatformInternalServerExceptionMapper.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/core/exceptionmapper/PlatformInternalServerExceptionMapper.java index 6b854e894..f90a5c1e6 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/core/exceptionmapper/PlatformInternalServerExceptionMapper.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/core/exceptionmapper/PlatformInternalServerExceptionMapper.java @@ -31,7 +31,7 @@ public class PlatformInternalServerExceptionMapper implements ExceptionMapper { // NOTE: must add new loan charge to set of loan charges before // reporcessing the repayment schedule. + if(this.charges == null) { + this.charges = new HashSet<>(); + } this.charges.add(loanCharge); this.summary = updateSummaryWithTotalFeeChargesDueAtDisbursement(deriveSumTotalOfChargesDueAtDisbursement()); final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = this.transactionProcessorFactory diff --git a/mifosng-provider/src/main/resources/META-INF/spring/infrastructure.xml b/mifosng-provider/src/main/resources/META-INF/spring/infrastructure.xml index c273aa343..67431b6ec 100644 --- a/mifosng-provider/src/main/resources/META-INF/spring/infrastructure.xml +++ b/mifosng-provider/src/main/resources/META-INF/spring/infrastructure.xml @@ -27,6 +27,11 @@ + + + + + diff --git a/mifosng-provider/src/test/java/org/mifosplatform/batch/BatchBuilder.java b/mifosng-provider/src/test/java/org/mifosplatform/batch/BatchBuilder.java index f7f2be124..0dcc1f6a5 100644 --- a/mifosng-provider/src/test/java/org/mifosplatform/batch/BatchBuilder.java +++ b/mifosng-provider/src/test/java/org/mifosplatform/batch/BatchBuilder.java @@ -3,6 +3,8 @@ package org.mifosplatform.batch; import java.util.ArrayList; import java.util.List; +import javax.ws.rs.core.UriInfo; + import org.junit.Assert; import org.junit.Test; import org.mifosplatform.batch.domain.BatchRequest; @@ -11,33 +13,37 @@ import org.mifosplatform.batch.service.BatchApiService; import org.mockito.Mockito; /** - * Runs a unit test for BatchApiResource by mocking the - * BatchRequest and BatchApiService objects. + * Runs a unit test for BatchApiResource by mocking the BatchRequest and + * BatchApiService objects. * * @author Rishabh Shukla */ public class BatchBuilder { - //Verify a non-empty response by BatchApiResource. - @Test - public void batchApiTest() { - - //Mock a BatchRequest objects - final BatchRequest batchTest = Mockito.mock(BatchRequest.class); - - //Mock a BatchApiService object - final BatchApiService serviceTest = Mockito.mock(BatchApiService.class); - - final List requestList = new ArrayList<>(); - requestList.add(batchTest); + // Verify a non-empty response by BatchApiResource. + @Test + public void batchApiTest() { - //Call the BatchApiService using mocked objects - final List result = serviceTest.handleBatchRequestsWithoutEnclosingTransaction(requestList); - - //Verifies whether handleBatchRequests() function of BatchApiService was called - Mockito.verify(serviceTest).handleBatchRequestsWithoutEnclosingTransaction(requestList); + // Mock a BatchRequest objects + final BatchRequest batchTest = Mockito.mock(BatchRequest.class); - //Verifies a non-empty response by the BatchApiResource - Assert.assertNotNull(result); - } + // Mock a BatchApiService object + final BatchApiService serviceTest = Mockito.mock(BatchApiService.class); + + // Mock a UriInfo object + final UriInfo uriInfo = Mockito.mock(UriInfo.class); + + final List requestList = new ArrayList<>(); + requestList.add(batchTest); + + // Call the BatchApiService using mocked objects + final List result = serviceTest.handleBatchRequestsWithoutEnclosingTransaction(requestList, uriInfo); + + // Verifies whether handleBatchRequests() function of BatchApiService + // was called + Mockito.verify(serviceTest).handleBatchRequestsWithoutEnclosingTransaction(requestList, uriInfo); + + // Verifies a non-empty response by the BatchApiResource + Assert.assertNotNull(result); + } }