Merge pull request #968 from rishy/Batch-API
added "UpdateClient" and "ApplyLoan" commands with dependency resolution
This commit is contained in:
@@ -136,8 +136,8 @@ dependencies {
|
|||||||
[group: 'org.quartz-scheduler', name: 'quartz', version: '2.1.7'],
|
[group: 'org.quartz-scheduler', name: 'quartz', version: '2.1.7'],
|
||||||
[group: 'com.amazonaws', name: 'aws-java-sdk', version: '1.2.1'],
|
[group: 'com.amazonaws', name: 'aws-java-sdk', version: '1.2.1'],
|
||||||
[group: 'net.sf.ehcache', name: 'ehcache', version: '2.7.2'],
|
[group: 'net.sf.ehcache', name: 'ehcache', version: '2.7.2'],
|
||||||
[group: 'com.github.spullara.mustache.java', name: 'compiler', version: '0.8.12']
|
[group: 'com.github.spullara.mustache.java', name: 'compiler', version: '0.8.12'],
|
||||||
)
|
[group: 'com.jayway.jsonpath', name: 'json-path', version: '0.9.1'])
|
||||||
|
|
||||||
testCompile 'junit:junit:4.10',
|
testCompile 'junit:junit:4.10',
|
||||||
'junit:junit-dep:4.10',
|
'junit:junit-dep:4.10',
|
||||||
@@ -401,3 +401,4 @@ def qualifyVersionIfNecessary(version) {
|
|||||||
}
|
}
|
||||||
return version
|
return version
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+111
-12
@@ -8,9 +8,12 @@ import org.junit.Before;
|
|||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.mifosplatform.batch.domain.BatchRequest;
|
import org.mifosplatform.batch.domain.BatchRequest;
|
||||||
import org.mifosplatform.batch.domain.BatchResponse;
|
import org.mifosplatform.batch.domain.BatchResponse;
|
||||||
|
import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper;
|
||||||
import org.mifosplatform.integrationtests.common.BatchHelper;
|
import org.mifosplatform.integrationtests.common.BatchHelper;
|
||||||
import org.mifosplatform.integrationtests.common.Utils;
|
import org.mifosplatform.integrationtests.common.Utils;
|
||||||
|
|
||||||
|
import com.google.gson.JsonElement;
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
import com.jayway.restassured.builder.RequestSpecBuilder;
|
import com.jayway.restassured.builder.RequestSpecBuilder;
|
||||||
import com.jayway.restassured.builder.ResponseSpecBuilder;
|
import com.jayway.restassured.builder.ResponseSpecBuilder;
|
||||||
import com.jayway.restassured.http.ContentType;
|
import com.jayway.restassured.http.ContentType;
|
||||||
@@ -49,7 +52,12 @@ public class BatchApiTest {
|
|||||||
this.responseSpec = new ResponseSpecBuilder().expectStatusCode(200).build();
|
this.responseSpec = new ResponseSpecBuilder().expectStatusCode(200).build();
|
||||||
}
|
}
|
||||||
|
|
||||||
//Tests for the unimplemented command Strategies by returning 501 status code
|
/**
|
||||||
|
* 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
|
@Test
|
||||||
public void shouldReturnStatusNotImplementedUnknownCommand() {
|
public void shouldReturnStatusNotImplementedUnknownCommand() {
|
||||||
|
|
||||||
@@ -58,7 +66,7 @@ public class BatchApiTest {
|
|||||||
br.setRelativeUrl("/nirvana");
|
br.setRelativeUrl("/nirvana");
|
||||||
br.setMethod("POST");
|
br.setMethod("POST");
|
||||||
|
|
||||||
final List<BatchResponse> response = BatchHelper.createRequest(this.requestSpec, this.responseSpec, br);
|
final List<BatchResponse> response = BatchHelper.postWithSingleRequest(this.requestSpec, this.responseSpec, br);
|
||||||
|
|
||||||
//Verify that only 501 is returned as the status code
|
//Verify that only 501 is returned as the status code
|
||||||
for(BatchResponse resp : response) {
|
for(BatchResponse resp : response) {
|
||||||
@@ -66,13 +74,18 @@ public class BatchApiTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Tests for the successful response for a createClient request from createClientCommand
|
/**
|
||||||
|
* 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
|
@Test
|
||||||
public void shouldReturnOkStatusForCreateClientCommand() {
|
public void shouldReturnOkStatusForCreateClientCommand() {
|
||||||
|
|
||||||
final BatchRequest br = BatchHelper.createClientRequest(4712L, "");
|
final BatchRequest br = BatchHelper.createClientRequest(4712L, "");
|
||||||
|
|
||||||
final List<BatchResponse> response = BatchHelper.createRequest(this.requestSpec, this.responseSpec, br);
|
final List<BatchResponse> response = BatchHelper.postWithSingleRequest(this.requestSpec, this.responseSpec, br);
|
||||||
|
|
||||||
//Verify that a 200 response is returned as the status code
|
//Verify that a 200 response is returned as the status code
|
||||||
for(BatchResponse resp : response) {
|
for(BatchResponse resp : response) {
|
||||||
@@ -80,18 +93,26 @@ public class BatchApiTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Tests for an erroneous response with statusCode 501 if transaction fails
|
/**
|
||||||
|
* 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
|
@Test
|
||||||
public void shouldRollBackAllTransactionsOnFailure() {
|
public void shouldRollBackAllTransactionsOnFailure() {
|
||||||
|
|
||||||
//Create first client
|
//Create first client request
|
||||||
final BatchRequest br1 = BatchHelper.createClientRequest(4713L, "TestExtId1");
|
final BatchRequest br1 = BatchHelper.createClientRequest(4713L, "TestExtId11");
|
||||||
|
|
||||||
//Create second client
|
//Create second client request
|
||||||
final BatchRequest br2 = BatchHelper.createClientRequest(4714L, "TestExtId2");
|
final BatchRequest br2 = BatchHelper.createClientRequest(4714L, "TestExtId12");
|
||||||
|
|
||||||
//Create third client, having same externalID as second client, hence cause of error
|
//Create third client request, having same externalID as second client, hence cause of error
|
||||||
final BatchRequest br3 = BatchHelper.createClientRequest(4715L, "TestExtId2");
|
final BatchRequest br3 = BatchHelper.createClientRequest(4715L, "TestExtId11");
|
||||||
|
|
||||||
final List<BatchRequest> batchRequests = new ArrayList<>();
|
final List<BatchRequest> batchRequests = new ArrayList<>();
|
||||||
|
|
||||||
@@ -103,7 +124,85 @@ public class BatchApiTest {
|
|||||||
final List<BatchResponse> response = BatchHelper.postBatchRequestsWithEnclosingTransaction(this.requestSpec,
|
final List<BatchResponse> response = BatchHelper.postBatchRequestsWithEnclosingTransaction(this.requestSpec,
|
||||||
this.responseSpec, jsonifiedRequest);
|
this.responseSpec, jsonifiedRequest);
|
||||||
|
|
||||||
Assert.assertEquals(response.size(), 1);
|
//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());
|
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);
|
||||||
|
|
||||||
|
final List<BatchRequest> batchRequests = new ArrayList<>();
|
||||||
|
|
||||||
|
batchRequests.add(br1);
|
||||||
|
batchRequests.add(br2);
|
||||||
|
|
||||||
|
final String jsonifiedRequest = BatchHelper.toJsonString(batchRequests);
|
||||||
|
|
||||||
|
final List<BatchResponse> 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(){
|
||||||
|
|
||||||
|
//Create a createClient Request
|
||||||
|
final BatchRequest br1 = BatchHelper.createClientRequest(4718L, "");
|
||||||
|
|
||||||
|
//Create a ApplyLoan Request
|
||||||
|
final BatchRequest br2 = BatchHelper.applyLoanRequest(4719L, 4718L);
|
||||||
|
|
||||||
|
final List<BatchRequest> batchRequests = new ArrayList<>();
|
||||||
|
|
||||||
|
batchRequests.add(br1);
|
||||||
|
batchRequests.add(br2);
|
||||||
|
|
||||||
|
final String jsonifiedRequest = BatchHelper.toJsonString(batchRequests);
|
||||||
|
|
||||||
|
final List<BatchResponse> 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");
|
||||||
|
|
||||||
|
//Get the loanId parameter from applyLoan Response
|
||||||
|
final JsonElement loanId = new FromJsonHelper().parse(response.get(1).getBody())
|
||||||
|
.getAsJsonObject().get("loanId");
|
||||||
|
|
||||||
|
Assert.assertEquals("Loan Successfully applied to client " + clientId.getAsString() +
|
||||||
|
" with loanId: " + loanId.getAsString(), 200L, (long) response.get(1).getStatusCode());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
+100
-33
@@ -62,7 +62,7 @@ public class BatchHelper {
|
|||||||
*/
|
*/
|
||||||
public static List<BatchResponse> postBatchRequestsWithoutEnclosingTransaction(final RequestSpecification requestSpec,
|
public static List<BatchResponse> postBatchRequestsWithoutEnclosingTransaction(final RequestSpecification requestSpec,
|
||||||
final ResponseSpecification responseSpec, final String jsonifiedBatchRequests) {
|
final ResponseSpecification responseSpec, final String jsonifiedBatchRequests) {
|
||||||
final String response = Utils.performServerPost(requestSpec, responseSpec, BATCH_API_URL, jsonifiedBatchRequests, null);
|
final String response = Utils.performServerPost(requestSpec, responseSpec, BATCH_API_URL, jsonifiedBatchRequests, null);
|
||||||
return BatchHelper.fromJsonString(response);
|
return BatchHelper.fromJsonString(response);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -82,44 +82,13 @@ public class BatchHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new Client Request as one of the request in Batch.
|
|
||||||
*
|
|
||||||
* @param reqId
|
|
||||||
* @param externalId
|
|
||||||
* @return BatchRequest
|
|
||||||
*/
|
|
||||||
public static BatchRequest createClientRequest(final Long reqId, final String externalId) {
|
|
||||||
|
|
||||||
final BatchRequest br = new BatchRequest();
|
|
||||||
br.setRequestId(reqId);
|
|
||||||
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\": false, \"activationDate\": \"04 March 2009\", \"submittedOnDate\": \"04 March 2009\"}";
|
|
||||||
|
|
||||||
br.setBody(body);
|
|
||||||
|
|
||||||
return br;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a BatchResponse based on the given BatchRequest, by posting the request
|
* Returns a BatchResponse based on the given BatchRequest, by posting the request
|
||||||
* to the server.
|
* to the server.
|
||||||
*
|
*
|
||||||
* @param BatchRequest
|
* @param BatchRequest
|
||||||
* @return List<BatchResponse>
|
* @return List<BatchResponse>
|
||||||
*/
|
*/
|
||||||
public static List<BatchResponse> createRequest(final RequestSpecification requestSpec,
|
public static List<BatchResponse> postWithSingleRequest(final RequestSpecification requestSpec,
|
||||||
final ResponseSpecification responseSpec,final BatchRequest br) {
|
final ResponseSpecification responseSpec,final BatchRequest br) {
|
||||||
|
|
||||||
final List<BatchRequest> batchRequests = new ArrayList<>();
|
final List<BatchRequest> batchRequests = new ArrayList<>();
|
||||||
@@ -135,4 +104,102 @@ public class BatchHelper {
|
|||||||
|
|
||||||
return response;
|
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
|
||||||
|
* @return BatchRequest
|
||||||
|
*/
|
||||||
|
public static BatchRequest applyLoanRequest(final Long requestId, final Long reference) {
|
||||||
|
|
||||||
|
final BatchRequest br = new BatchRequest();
|
||||||
|
|
||||||
|
br.setRequestId(requestId);
|
||||||
|
br.setRelativeUrl("loans");
|
||||||
|
br.setMethod("POST");
|
||||||
|
br.setReference(reference);
|
||||||
|
|
||||||
|
//NOTE: Set the value productId according to your db else will result in a '404' response
|
||||||
|
final String body = "{\"dateFormat\": \"dd MMMM yyyy\", \"locale\": \"en_GB\", \"clientId\": \"$.clientId\"," +
|
||||||
|
"\"productId\": 26, \"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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -41,8 +41,7 @@ import org.springframework.stereotype.Component;
|
|||||||
public class BatchApiResource {
|
public class BatchApiResource {
|
||||||
|
|
||||||
private final PlatformSecurityContext context;
|
private final PlatformSecurityContext context;
|
||||||
@SuppressWarnings("rawtypes")
|
private final ToApiJsonSerializer<BatchResponse> toApiJsonSerializer;
|
||||||
private final ToApiJsonSerializer toApiJsonSerializer;
|
|
||||||
private final BatchApiService service;
|
private final BatchApiService service;
|
||||||
private final BatchRequestJsonHelper batchRequestJsonHelper;
|
private final BatchRequestJsonHelper batchRequestJsonHelper;
|
||||||
|
|
||||||
@@ -56,9 +55,8 @@ public class BatchApiResource {
|
|||||||
* @param batchRequestJsonHelper
|
* @param batchRequestJsonHelper
|
||||||
*/
|
*/
|
||||||
@Autowired
|
@Autowired
|
||||||
public BatchApiResource(final PlatformSecurityContext context, @SuppressWarnings("rawtypes")
|
public BatchApiResource(final PlatformSecurityContext context, final ToApiJsonSerializer<BatchResponse>
|
||||||
final ToApiJsonSerializer toApiJsonSerializer, final BatchApiService service,
|
toApiJsonSerializer, final BatchApiService service, final BatchRequestJsonHelper batchRequestJsonHelper) {
|
||||||
final BatchRequestJsonHelper batchRequestJsonHelper) {
|
|
||||||
|
|
||||||
this.context = context;
|
this.context = context;
|
||||||
this.toApiJsonSerializer = toApiJsonSerializer;
|
this.toApiJsonSerializer = toApiJsonSerializer;
|
||||||
@@ -88,7 +86,7 @@ public class BatchApiResource {
|
|||||||
//Gets back the consolidated BatchResponse from BatchApiservice
|
//Gets back the consolidated BatchResponse from BatchApiservice
|
||||||
List<BatchResponse> result = new ArrayList<>();
|
List<BatchResponse> result = new ArrayList<>();
|
||||||
|
|
||||||
//if the request is to be handled as a Transaction. All requests will be rolled back on error
|
//If the request is to be handled as a Transaction. All requests will be rolled back on error
|
||||||
if(enclosingTransaction) {
|
if(enclosingTransaction) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -48,6 +48,21 @@ public class CommandContext {
|
|||||||
public static Builder resource(final String resource) {
|
public static Builder resource(final String resource) {
|
||||||
return new Builder(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
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
|
|||||||
+9
-1
@@ -52,6 +52,12 @@ public class CommandStrategyProvider {
|
|||||||
return (CommandStrategy) this.applicationContext.getBean(this.commandStrategies.get(commandContext));
|
return (CommandStrategy) this.applicationContext.getBean(this.commandStrategies.get(commandContext));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for(ConcurrentHashMap.Entry<CommandContext,String> entry : this.commandStrategies.entrySet()) {
|
||||||
|
if(commandContext.matcher(entry.getKey())) {
|
||||||
|
return (CommandStrategy) this.applicationContext.getBean(this.commandStrategies.get(entry.getKey()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return new UnknownCommandStrategy();
|
return new UnknownCommandStrategy();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -61,7 +67,9 @@ public class CommandStrategyProvider {
|
|||||||
* within the constructor.
|
* within the constructor.
|
||||||
*/
|
*/
|
||||||
private void init() {
|
private void init() {
|
||||||
this.commandStrategies.put(CommandContext.resource("clients").method("POST").build(), "CreateClientCommandStrategy");
|
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");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
+69
@@ -0,0 +1,69 @@
|
|||||||
|
package org.mifosplatform.batch.command.internal;
|
||||||
|
|
||||||
|
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.LoansApiResource;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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{
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
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(new Gson().toJson(ex));
|
||||||
|
}
|
||||||
|
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
}
|
||||||
+21
-35
@@ -3,13 +3,13 @@ package org.mifosplatform.batch.command.internal;
|
|||||||
import org.mifosplatform.batch.command.CommandStrategy;
|
import org.mifosplatform.batch.command.CommandStrategy;
|
||||||
import org.mifosplatform.batch.domain.BatchRequest;
|
import org.mifosplatform.batch.domain.BatchRequest;
|
||||||
import org.mifosplatform.batch.domain.BatchResponse;
|
import org.mifosplatform.batch.domain.BatchResponse;
|
||||||
import org.mifosplatform.infrastructure.core.exception.AbstractPlatformResourceNotFoundException;
|
import org.mifosplatform.batch.exception.ErrorHandler;
|
||||||
import org.mifosplatform.infrastructure.core.exception.PlatformApiDataValidationException;
|
import org.mifosplatform.batch.exception.ErrorInfo;
|
||||||
import org.mifosplatform.infrastructure.core.exception.PlatformDataIntegrityException;
|
|
||||||
import org.mifosplatform.infrastructure.core.exception.PlatformInternalServerException;
|
|
||||||
import org.mifosplatform.infrastructure.core.exception.UnsupportedParameterException;
|
|
||||||
import org.mifosplatform.portfolio.client.api.ClientsApiResource;
|
import org.mifosplatform.portfolio.client.api.ClientsApiResource;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implements {@link org.mifosplatform.batch.command.CommandStrategy} to handle
|
* Implements {@link org.mifosplatform.batch.command.CommandStrategy} to handle
|
||||||
@@ -25,6 +25,7 @@ import org.springframework.beans.factory.annotation.Autowired;
|
|||||||
* @see org.mifosplatform.batch.domain.BatchRequest
|
* @see org.mifosplatform.batch.domain.BatchRequest
|
||||||
* @see org.mifosplatform.batch.domain.BatchResponse
|
* @see org.mifosplatform.batch.domain.BatchResponse
|
||||||
*/
|
*/
|
||||||
|
@Component
|
||||||
public class CreateClientCommandStrategy implements CommandStrategy{
|
public class CreateClientCommandStrategy implements CommandStrategy{
|
||||||
|
|
||||||
private final ClientsApiResource clientsApiResource;
|
private final ClientsApiResource clientsApiResource;
|
||||||
@@ -32,51 +33,36 @@ public class CreateClientCommandStrategy implements CommandStrategy{
|
|||||||
@Autowired
|
@Autowired
|
||||||
public CreateClientCommandStrategy(final ClientsApiResource clientsApiResource) {
|
public CreateClientCommandStrategy(final ClientsApiResource clientsApiResource) {
|
||||||
this.clientsApiResource = clientsApiResource;
|
this.clientsApiResource = clientsApiResource;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public BatchResponse execute(final BatchRequest request) {
|
public BatchResponse execute(final BatchRequest request) {
|
||||||
|
|
||||||
final BatchResponse response = new BatchResponse();
|
final BatchResponse response = new BatchResponse();
|
||||||
final String responseBody;
|
final String responseBody;
|
||||||
|
|
||||||
|
response.setRequestId(request.getRequestId());
|
||||||
|
response.setHeaders(request.getHeaders());
|
||||||
|
|
||||||
// try-catch blocks to map exceptions to appropriate status codes
|
//Try-catch blocks to map exceptions to appropriate status codes
|
||||||
try {
|
try {
|
||||||
|
|
||||||
//calls 'create' function from 'ClientsApiResource' to create a new client
|
//Calls 'create' function from 'ClientsApiResource' to create a new client
|
||||||
responseBody = clientsApiResource.create(request.getBody());
|
responseBody = clientsApiResource.create(request.getBody());
|
||||||
|
|
||||||
response.setRequestId(request.getRequestId());
|
|
||||||
response.setHeaders(request.getHeaders());
|
|
||||||
response.setStatusCode(200);
|
response.setStatusCode(200);
|
||||||
//sets the body of the response after the successful creation of the client
|
//Sets the body of the response after the successful creation of the client
|
||||||
response.setBody(responseBody);
|
response.setBody(responseBody);
|
||||||
|
|
||||||
} catch (AbstractPlatformResourceNotFoundException e) {
|
}
|
||||||
|
catch (RuntimeException e) {
|
||||||
|
|
||||||
response.setStatusCode(404);
|
//Gets an object of type ErrorInfo, containing information about raised exception
|
||||||
response.setBody("error : " + e.toString());
|
ErrorInfo ex = ErrorHandler.handler(e);
|
||||||
|
|
||||||
} catch (UnsupportedParameterException e) {
|
response.setStatusCode(ex.getStatusCode());
|
||||||
|
response.setBody(new Gson().toJson(ex));
|
||||||
response.setStatusCode(400);
|
}
|
||||||
response.setBody("error : " + e.toString());
|
|
||||||
|
|
||||||
} catch(PlatformApiDataValidationException e) {
|
|
||||||
|
|
||||||
response.setStatusCode(400);
|
|
||||||
response.setBody("error : " + e.toString());
|
|
||||||
|
|
||||||
} catch (PlatformDataIntegrityException e) {
|
|
||||||
|
|
||||||
response.setStatusCode(403);
|
|
||||||
response.setBody("error : " + e.toString());
|
|
||||||
|
|
||||||
} catch (PlatformInternalServerException e) {
|
|
||||||
|
|
||||||
response.setStatusCode(500);
|
|
||||||
response.setBody("error : " + e.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|||||||
+2
@@ -3,6 +3,7 @@ package org.mifosplatform.batch.command.internal;
|
|||||||
import org.mifosplatform.batch.command.CommandStrategy;
|
import org.mifosplatform.batch.command.CommandStrategy;
|
||||||
import org.mifosplatform.batch.domain.BatchRequest;
|
import org.mifosplatform.batch.domain.BatchRequest;
|
||||||
import org.mifosplatform.batch.domain.BatchResponse;
|
import org.mifosplatform.batch.domain.BatchResponse;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides a default CommandStrategy by implementing
|
* Provides a default CommandStrategy by implementing
|
||||||
@@ -12,6 +13,7 @@ import org.mifosplatform.batch.domain.BatchResponse;
|
|||||||
*
|
*
|
||||||
* @author Rishabh Shukla
|
* @author Rishabh Shukla
|
||||||
*/
|
*/
|
||||||
|
@Component
|
||||||
public class UnknownCommandStrategy implements CommandStrategy {
|
public class UnknownCommandStrategy implements CommandStrategy {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
+73
@@ -0,0 +1,73 @@
|
|||||||
|
package org.mifosplatform.batch.command.internal;
|
||||||
|
|
||||||
|
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.client.api.ClientsApiResource;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
*
|
||||||
|
* @see org.mifosplatform.batch.command.CommandStrategy
|
||||||
|
* @see org.mifosplatform.batch.domain.BatchRequest
|
||||||
|
* @see org.mifosplatform.batch.domain.BatchResponse
|
||||||
|
*/
|
||||||
|
@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;
|
||||||
|
|
||||||
|
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(new Gson().toJson(ex));
|
||||||
|
}
|
||||||
|
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
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.UnsupportedParameterException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
public class ErrorHandler extends RuntimeException{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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");
|
||||||
|
} 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");
|
||||||
|
}
|
||||||
|
|
||||||
|
return new ErrorInfo(500, 9999, "Internal Server Error");
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,93 @@
|
|||||||
|
package org.mifosplatform.batch.exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides members to hold the basic information about the exceptions raised in
|
||||||
|
* commandStrategy classes.
|
||||||
|
*
|
||||||
|
* @author Rishabh Shukla
|
||||||
|
*
|
||||||
|
* @see ErrorHandler
|
||||||
|
*/
|
||||||
|
public final class ErrorInfo {
|
||||||
|
|
||||||
|
private Integer statusCode;
|
||||||
|
private Integer errorCode;
|
||||||
|
private String message;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor to initialize the members of this class.
|
||||||
|
*
|
||||||
|
* @param statusCode
|
||||||
|
* @param errorCode
|
||||||
|
* @param message
|
||||||
|
*/
|
||||||
|
public ErrorInfo(final Integer statusCode, final Integer errorCode, final String message) {
|
||||||
|
super();
|
||||||
|
this.statusCode = statusCode;
|
||||||
|
this.errorCode = errorCode;
|
||||||
|
this.message = message;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor so JSON serialization will work with out special Serialiazer
|
||||||
|
*/
|
||||||
|
ErrorInfo() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Getter method to provide the statusCode for an object of this type.
|
||||||
|
*
|
||||||
|
* @return Integer
|
||||||
|
*/
|
||||||
|
public Integer getStatusCode() {
|
||||||
|
return this.statusCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Setter method to set the statusCode for an object of this type.
|
||||||
|
*
|
||||||
|
* @param statusCode
|
||||||
|
*/
|
||||||
|
public void setStatusCode(final Integer statusCode) {
|
||||||
|
this.statusCode = statusCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Getter method to provide the errorCode for an object of this type.
|
||||||
|
*
|
||||||
|
* @return Integer
|
||||||
|
*/
|
||||||
|
public Integer getErrorCode() {
|
||||||
|
return this.errorCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Setter method to set the errorCode for an object of this type.
|
||||||
|
*
|
||||||
|
* @param errorCode
|
||||||
|
*/
|
||||||
|
public void setErrorCode(final Integer errorCode) {
|
||||||
|
this.errorCode = errorCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Getter method to provide the message of the error for an object
|
||||||
|
* of this type.
|
||||||
|
*
|
||||||
|
* @return String
|
||||||
|
*/
|
||||||
|
public String getMessage() {
|
||||||
|
return this.message;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
+66
-9
@@ -2,16 +2,22 @@ package org.mifosplatform.batch.service;
|
|||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
import javax.ws.rs.core.Response.Status;
|
||||||
|
|
||||||
import org.mifosplatform.batch.command.CommandContext;
|
import org.mifosplatform.batch.command.CommandContext;
|
||||||
import org.mifosplatform.batch.command.CommandStrategy;
|
import org.mifosplatform.batch.command.CommandStrategy;
|
||||||
import org.mifosplatform.batch.command.CommandStrategyProvider;
|
import org.mifosplatform.batch.command.CommandStrategyProvider;
|
||||||
import org.mifosplatform.batch.domain.BatchRequest;
|
import org.mifosplatform.batch.domain.BatchRequest;
|
||||||
import org.mifosplatform.batch.domain.BatchResponse;
|
import org.mifosplatform.batch.domain.BatchResponse;
|
||||||
|
import org.mifosplatform.batch.exception.ErrorInfo;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implementation for {@link BatchApiService} to iterate through all the incoming
|
* Implementation for {@link BatchApiService} to iterate through all the incoming
|
||||||
* requests and obtain the appropriate CommandStrategy from CommandStrategyProvider.
|
* requests and obtain the appropriate CommandStrategy from CommandStrategyProvider.
|
||||||
@@ -26,6 +32,7 @@ import org.springframework.transaction.annotation.Transactional;
|
|||||||
public class BatchApiServiceImpl implements BatchApiService{
|
public class BatchApiServiceImpl implements BatchApiService{
|
||||||
|
|
||||||
private final CommandStrategyProvider strategyProvider;
|
private final CommandStrategyProvider strategyProvider;
|
||||||
|
private final ResolutionHelper resolutionHelper;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a 'BatchApiServiceImpl' with an argument of
|
* Constructs a 'BatchApiServiceImpl' with an argument of
|
||||||
@@ -34,27 +41,77 @@ public class BatchApiServiceImpl implements BatchApiService{
|
|||||||
* @param strategyProvider
|
* @param strategyProvider
|
||||||
*/
|
*/
|
||||||
@Autowired
|
@Autowired
|
||||||
public BatchApiServiceImpl(final CommandStrategyProvider strategyProvider) {
|
public BatchApiServiceImpl(final CommandStrategyProvider strategyProvider,
|
||||||
|
final ResolutionHelper resolutionHelper) {
|
||||||
this.strategyProvider = strategyProvider;
|
this.strategyProvider = strategyProvider;
|
||||||
|
this.resolutionHelper = resolutionHelper;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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<BatchResponse>
|
||||||
|
*/
|
||||||
private List<BatchResponse> handleBatchRequests(final List<BatchRequest> requestList) {
|
private List<BatchResponse> handleBatchRequests(final List<BatchRequest> requestList) {
|
||||||
|
|
||||||
final List<BatchResponse> responseList = new ArrayList<>(requestList.size());
|
final List<BatchResponse> responseList = new ArrayList<>();
|
||||||
|
|
||||||
for(final BatchRequest br: requestList) {
|
final ConcurrentHashMap<Long, ArrayList<BatchRequest>> requestMap = this.resolutionHelper.getDependencyMap(requestList);
|
||||||
|
|
||||||
|
for(ConcurrentHashMap.Entry<Long, ArrayList<BatchRequest>> entry : requestMap.entrySet()) {
|
||||||
|
|
||||||
final CommandStrategy commandStrategy = this.strategyProvider.getCommandStrategy(CommandContext.
|
final ArrayList<BatchRequest> mappedList = entry.getValue();
|
||||||
resource(br.getRelativeUrl()).method(br.getMethod()).build());
|
|
||||||
|
|
||||||
final BatchResponse response = commandStrategy.execute(br);
|
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(new Gson().toJson(conflictError));
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
responseList.add(response);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return responseList;
|
return responseList;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<BatchResponse> handleBatchRequestsWithoutEnclosingTransaction(final
|
public List<BatchResponse> handleBatchRequestsWithoutEnclosingTransaction(final
|
||||||
List<BatchRequest> requestList) {
|
List<BatchRequest> requestList) {
|
||||||
|
|||||||
@@ -0,0 +1,176 @@
|
|||||||
|
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;
|
||||||
|
import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
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.
|
||||||
|
*
|
||||||
|
* @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<Long, List<BatchRequest>>
|
||||||
|
*/
|
||||||
|
public ConcurrentHashMap<Long, ArrayList<BatchRequest>> getDependencyMap(final List<BatchRequest> requestList) {
|
||||||
|
|
||||||
|
//Create a map with a '-1L' which will contain a list of independent requests
|
||||||
|
final ConcurrentHashMap<Long, ArrayList<BatchRequest>> dependencyMap = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
dependencyMap.put(-1L, new ArrayList<BatchRequest>());
|
||||||
|
|
||||||
|
//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<BatchRequest> 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<BatchRequest> 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<Long, ArrayList<BatchRequest>> entry: dependencyMap.entrySet()) {
|
||||||
|
if(entry.getValue().contains(parentRequest)) {
|
||||||
|
final ArrayList<BatchRequest> 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<BatchRequest> 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<String, JsonElement> 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();
|
||||||
|
|
||||||
|
//Add the value after dependency resolution
|
||||||
|
jsonResultBody.add(element.getKey(), this.fromJsonHelper.parse(resParamValue));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
jsonResultBody.add(element.getKey(), element.getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//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();
|
||||||
|
|
||||||
|
relativeUrl = relativeUrl.replace(parameter, resParamValue);
|
||||||
|
|
||||||
|
br.setRelativeUrl(relativeUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
return br;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -35,13 +35,11 @@
|
|||||||
org.mifosplatform.template.*,
|
org.mifosplatform.template.*,
|
||||||
org.mifosplatform.template.service.*,
|
org.mifosplatform.template.service.*,
|
||||||
org.mifosplatform.useradministration.*,
|
org.mifosplatform.useradministration.*,
|
||||||
org.mifosplatform.batch.*">
|
org.mifosplatform.batch">
|
||||||
<context:exclude-filter expression="org.springframework.stereotype.Controller"
|
<context:exclude-filter expression="org.springframework.stereotype.Controller"
|
||||||
type="annotation" />
|
type="annotation" />
|
||||||
</context:component-scan>
|
</context:component-scan>
|
||||||
|
|
||||||
<bean id="CreateClientCommandStrategy"
|
|
||||||
class="org.mifosplatform.batch.command.internal.CreateClientCommandStrategy"/>
|
|
||||||
<bean id="auditorAware"
|
<bean id="auditorAware"
|
||||||
class="org.mifosplatform.infrastructure.core.domain.AuditorAwareImpl" />
|
class="org.mifosplatform.infrastructure.core.domain.AuditorAwareImpl" />
|
||||||
<jpa:auditing auditor-aware-ref="auditorAware" />
|
<jpa:auditing auditor-aware-ref="auditorAware" />
|
||||||
@@ -55,8 +53,7 @@
|
|||||||
<jpa:repositories base-package="org.mifosplatform.mix.domain" />
|
<jpa:repositories base-package="org.mifosplatform.mix.domain" />
|
||||||
<jpa:repositories base-package="org.mifosplatform.scheduledjobs.domain" />
|
<jpa:repositories base-package="org.mifosplatform.scheduledjobs.domain" />
|
||||||
<jpa:repositories base-package="org.mifosplatform.template.domain" />
|
<jpa:repositories base-package="org.mifosplatform.template.domain" />
|
||||||
<jpa:repositories base-package="org.mifosplatform.batch.domain"/>
|
|
||||||
|
|
||||||
<import resource="infrastructure.xml" />
|
<import resource="infrastructure.xml" />
|
||||||
|
|
||||||
<import resource="securityContext.xml" />
|
<import resource="securityContext.xml" />
|
||||||
|
|||||||
Reference in New Issue
Block a user