Merge pull request #1001 from rishy/Batch-API

added create and collect charges command
This commit is contained in:
Vishwas Babu A J
2014-07-16 15:39:17 -07:00
27 changed files with 2072 additions and 1515 deletions
@@ -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<BatchResponse> 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<BatchResponse>
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<BatchRequest> requestList = this.batchRequestJsonHelper.extractList(jsonRequestString);
//Gets back the consolidated BatchResponse from BatchApiservice
List<BatchResponse> result = new ArrayList<>();
private final PlatformSecurityContext context;
private final ToApiJsonSerializer<BatchResponse> 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<BatchResponse> 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<BatchRequest> requestList = this.batchRequestJsonHelper.extractList(jsonRequestString);
// Gets back the consolidated BatchResponse from BatchApiservice
List<BatchResponse> 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);
}
}
@@ -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;
}
}
@@ -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);
}
@@ -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<CommandContext, String> 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<CommandContext,String> 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<CommandContext, String> 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<CommandContext, String> 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");
}
}
@@ -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;
}
}
@@ -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;
}
}
@@ -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;
}
}
@@ -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;
}
}
@@ -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;
}
}
@@ -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;
}
}
@@ -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;
}
}
@@ -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<Header> 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<Header> 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<Header> 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<Header> 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<Header> 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<Header> 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<Header> 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<Header> 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;
}
}
@@ -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<Header> 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<Header> 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<Header> 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<Header> 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<Header> 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<Header> 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<Header> 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<Header> 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;
}
}
@@ -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;
}
}
@@ -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());
}
}
@@ -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;
}
}
}
@@ -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<BatchRequest>
*/
public List<BatchRequest> extractList(final String json) {
final Type listType = new TypeToken<List<BatchRequest>>(){}.getType();
final List<BatchRequest> 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<BatchRequest>
*/
public List<BatchRequest> extractList(final String json) {
final Type listType = new TypeToken<List<BatchRequest>>() {}.getType();
final List<BatchRequest> requests = super.getGsonConverter().fromJson(json, listType);
return requests;
}
}
@@ -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<BatchResponse>
*/
List<BatchResponse> handleBatchRequestsWithoutEnclosingTransaction(List<BatchRequest> 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<BatchResponse>
*/
List<BatchResponse> handleBatchRequestsWithEnclosingTransaction(List<BatchRequest> 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<BatchResponse>
*/
List<BatchResponse> handleBatchRequestsWithoutEnclosingTransaction(List<BatchRequest> 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<BatchResponse>
*/
List<BatchResponse> handleBatchRequestsWithEnclosingTransaction(List<BatchRequest> requestList, UriInfo uriInfo);
}
@@ -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<BatchResponse>
*/
private List<BatchResponse> handleBatchRequests(final List<BatchRequest> requestList) {
private final CommandStrategyProvider strategyProvider;
private final ResolutionHelper resolutionHelper;
private final TransactionTemplate transactionTemplate;
private List<BatchResponse> checkList = new ArrayList<>();
final List<BatchResponse> responseList = new ArrayList<>();
final ConcurrentHashMap<Long, ArrayList<BatchRequest>> requestMap = this.resolutionHelper.getDependencyMap(requestList);
for(ConcurrentHashMap.Entry<Long, ArrayList<BatchRequest>> entry : requestMap.entrySet()) {
final ArrayList<BatchRequest> 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<BatchResponse> handleBatchRequestsWithoutEnclosingTransaction(final
List<BatchRequest> 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<BatchResponse>
*/
private List<BatchResponse> handleBatchRequests(final List<BatchRequest> requestList, final UriInfo uriInfo) {
@Transactional
@Override
public List<BatchResponse> handleBatchRequestsWithEnclosingTransaction( final
List<BatchRequest> requestList) {
return handleBatchRequests(requestList);
}
final List<BatchResponse> responseList = new ArrayList<>(requestList.size());
final List<BatchRequestNode> 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<BatchResponse>() {
@Override
public int compare(BatchResponse source, BatchResponse testee) {
return source.getRequestId().compareTo(testee.getRequestId());
}
});
checkList = responseList;
return responseList;
}
private List<BatchResponse> processChildRequests(final BatchRequestNode rootRequest, BatchResponse rootResponse, UriInfo uriInfo) {
final List<BatchResponse> 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<BatchResponse> handleBatchRequestsWithoutEnclosingTransaction(final List<BatchRequest> requestList, UriInfo uriInfo) {
return handleBatchRequests(requestList, uriInfo);
}
@Override
public List<BatchResponse> handleBatchRequestsWithEnclosingTransaction(final List<BatchRequest> requestList, final UriInfo uriInfo) {
try {
return this.transactionTemplate.execute(new TransactionCallback<List<BatchResponse>>() {
@Override
public List<BatchResponse> 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<BatchResponse> 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<BatchResponse> errResponseList = new ArrayList<>();
errResponseList.add(errResponse);
return errResponseList;
}
}
}
@@ -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<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();
/**
* 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<BatchRequestNode> 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<BatchRequestNode> 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<ArrayList<BatchRequestNode>>
*/
public List<BatchRequestNode> getDependingRequests(final List<BatchRequest> batchRequests) {
final List<BatchRequestNode> 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<BatchRequestNode> 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<String, JsonElement> 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<String, JsonElement> 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<String, JsonElement> 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;
}
}
@@ -31,7 +31,7 @@ public class PlatformInternalServerExceptionMapper implements ExceptionMapper<Pl
@Override
public Response toResponse(final PlatformInternalServerException exception) {
final ApiGlobalErrorResponse notFoundErrorResponse = ApiGlobalErrorResponse.notFound(exception.getGlobalisationMessageCode(),
final ApiGlobalErrorResponse notFoundErrorResponse = ApiGlobalErrorResponse.serverSideError(exception.getGlobalisationMessageCode(),
exception.getDefaultUserMessage(), exception.getDefaultUserMessageArgs());
return Response.status(Status.INTERNAL_SERVER_ERROR).entity(notFoundErrorResponse).type(MediaType.APPLICATION_JSON).build();
}
@@ -494,6 +494,9 @@ public class Loan extends AbstractPersistable<Long> {
// 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
@@ -27,6 +27,11 @@
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<!-- Create instance of transaction template for programmatic transaction manipulation -->
<bean id="txTemplate" class="org.springframework.transaction.support.TransactionTemplate">
<property name="transactionManager" ref="transactionManager"></property>
</bean>
<jee:jndi-lookup jndi-name="java:comp/env/jdbc/mifosplatform-tenants"
id="tenantDataSourceJndi" />