/**
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package org.mifosplatform.batch.service;
import java.util.ArrayList;
import java.util.List;
import java.util.Map.Entry;
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.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.
*
* @author Rishabh Shukla
* @see BatchApiServiceImpl
*/
@Component
public class ResolutionHelper {
/**
* Provides a Node like object for the request tree.
*
* @author Rishabh shukla
*
*/
public class BatchRequestNode {
private BatchRequest request;
private final List<BatchRequestNode> childRequests = new ArrayList<>();
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("$.")) {
String queryParams = "";
if(relativeUrl.contains("?")) {
queryParams = relativeUrl.substring(relativeUrl.indexOf("?"));
relativeUrl = relativeUrl.substring(0, relativeUrl.indexOf("?"));
}
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+queryParams);
}
}
}
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;
}
}