/* vim: set ts=2 et sw=2 cindent fo=qroca: */
package com.globant.google.mendoza;
import java.util.HashSet;
import java.util.List;
import java.util.ArrayList;
import java.util.Set;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import com.globant.google.mendoza.malbec.schema._2.MerchantCalculationCallback;
import com.globant.google.mendoza.malbec.schema._2.MerchantCalculationResults;
import com.globant.google.mendoza.malbec.schema._2.AnonymousAddress;
import com.globant.google.mendoza.malbec.schema._2.Calculate;
import com.globant.google.mendoza.malbec.schema._2.Method;
import com.globant.google.mendoza.malbec.schema._2.Result;
/** Validates the Merchant calculation.
*/
public final class MendozaMerchantCalculationValidator {
/** The class logger.
*/
private static Log log =
LogFactory.getLog(MendozaMerchantCalculationValidator.class);
/** The expected merchant calculation response time.
*/
private long calculationTimeout = -1;
/** Constructor. Creates an instance of
* MendozaMerchantCalculationValidator.
*
* @param maxCalculationTime The max merchant calculation response time.
*/
public MendozaMerchantCalculationValidator(
final long maxCalculationTime) {
calculationTimeout = maxCalculationTime;
}
/** Validates the results of the merchant calculation.
*
* @param merchantCalculation The merchant calculation to validate. Cannot be
* null.
*
* @return Returns the calculation validation.
*/
public MendozaMerchantCalculationValidation validate(
final MendozaMerchantCalculation merchantCalculation) {
if (merchantCalculation == null) {
throw new IllegalArgumentException(
"The merchant calculation to validate cannot be null");
}
log.trace("Entering validate");
List<String> requestedAddressIdList =
getRequestedAddressIdList(merchantCalculation);
List<String> requestedMethodNameList =
getRequestedMethodNameList(merchantCalculation);
List<Result> resultList = getResultList(merchantCalculation);
MendozaMerchantCalculationValidation calculationValidation =
new MendozaMerchantCalculationValidation(calculationTimeout);
validateResultSize(resultList, requestedAddressIdList,
requestedMethodNameList, calculationValidation);
validateResponseTime(merchantCalculation, calculationValidation);
validateAddressResponse(requestedAddressIdList, resultList,
calculationValidation);
validateMethodResponse(requestedMethodNameList, resultList,
calculationValidation);
log.trace("Leaving validate");
return calculationValidation;
}
/** Validates that the calculation result contains all
* the requested method names.
*
* @param requestedMethodNameList The requested method names.
*
* @param resultList The calculation result list.
*
* @param calculationValidation The validation result.
*/
private void validateMethodResponse(
final List<String> requestedMethodNameList,
final List<Result> resultList,
final MendozaMerchantCalculationValidation calculationValidation) {
log.trace("Entering validateMethodResponse");
Set<String> responseMethodNameSet =
getResponseMethodNameSet(resultList);
boolean missingMethodResponses =
!responseMethodNameSet.containsAll(requestedMethodNameList);
if (missingMethodResponses) {
Set<String> missingMethods =
getMissingResponse(requestedMethodNameList, responseMethodNameSet);
calculationValidation.addMissingRequestedShipping(missingMethods);
}
responseMethodNameSet.removeAll(requestedMethodNameList);
if (responseMethodNameSet.size() > 0) {
calculationValidation.addNotRequestedShipping(responseMethodNameSet);
}
log.trace("Leaving validateMethodResponse");
}
/** Validates that the calculation result contains all
* the requested address ids.
*
* @param requestedAddressIdList The requested address ids.
*
* @param resultList The calculation result list.
*
* @param calculationValidation The validation result.
*/
private void validateAddressResponse(
final List<String> requestedAddressIdList,
final List<Result> resultList,
final MendozaMerchantCalculationValidation calculationValidation) {
log.trace("Entering validateAddressResponse");
// Uses Set to avoid duplicates.
Set<String> responseAddressIdSet =
getResponseAddressIdSet(resultList);
boolean missingAddressResponses =
!responseAddressIdSet.containsAll(requestedAddressIdList);
if (missingAddressResponses) {
Set<String> missingIds =
getMissingResponse(requestedAddressIdList, responseAddressIdSet);
calculationValidation.addMissingRequestedAddress(missingIds);
}
responseAddressIdSet.removeAll(requestedAddressIdList);
if (responseAddressIdSet.size() > 0) {
calculationValidation.addNotRequestedAddress(responseAddressIdSet);
}
log.trace("Leaving validateAddressResponse");
}
/** Gets the elements that not exists in the result but
* were requested in the callback.
*
* @param requestedElements The requested elements.
*
* @param responseElements The requested elements.
*
* @return missing elements in the calculation response.
*/
private Set<String> getMissingResponse(
final List<String> requestedElements,
final Set<String> responseElements) {
log.trace("Entering validateAddressResponse");
Set<String> responseAux = new HashSet<String>();
responseAux.addAll(responseElements);
List<String> requestAux = new ArrayList<String>();
requestAux.addAll(requestedElements);
responseAux.retainAll(requestAux);
requestAux.removeAll(responseAux);
log.trace("Leaving getMissingResponse");
return responseAux;
}
/** Gets the method names of the calculation response.
*
* @param resultList The calculation results.
*
* @return Returns the method names of the calculation response.
*/
private Set<String> getResponseMethodNameSet(
final List<Result> resultList) {
log.trace("Entering getResponseMethodNameSet");
Set<String> result = new HashSet<String>();
for (Result calculationResult : resultList) {
String resultShippingName = calculationResult.getShippingName();
result.add(resultShippingName);
}
log.trace("Leaving getResponseMethodNameSet");
return result;
}
/** Gets the address ids of the calculation response.
*
* @param resultList The calculation results.
*
* @return Returns the address ids of the calculation response.
*/
private Set<String> getResponseAddressIdSet(
final List<Result> resultList) {
log.trace("Entering getResponseAddressIdSet");
Set<String> result = new HashSet<String>();
for (Result calculationResult : resultList) {
String resultAddressId = calculationResult.getAddressId();
result.add(resultAddressId);
}
log.trace("Leaving getResponseAddressIdSet");
return result;
}
/** Validates the size of the calculation result.
*
* @param resultList The calculation results.
*
* @param requestedAddressIdList The requested address ids.
*
* @param requestedMethodNameList The requested method names.
*
* @param calculationValidation The validation result.
*/
private void validateResultSize(final List<Result> resultList,
final List<String> requestedAddressIdList,
final List<String> requestedMethodNameList,
final MendozaMerchantCalculationValidation calculationValidation) {
log.trace("Entering validateResultSize");
int resultSize = resultList.size();
int expectedResultSize =
(requestedAddressIdList.size() * requestedMethodNameList.size());
boolean correctSize = true;
if (resultSize < expectedResultSize) {
correctSize = false;
}
calculationValidation.setCalculationResultSize(
correctSize, expectedResultSize, resultSize);
log.trace("Leaving validateResultSize");
}
/** Gets the calculation results.
*
* @param merchantCalculation The merchant calculation.
*
* @return Returns the calculation results.
*/
private List<Result> getResultList(
final MendozaMerchantCalculation merchantCalculation) {
log.trace("Entering getResultList");
MerchantCalculationResults result =
merchantCalculation.getMerchantCalculationResult();
MerchantCalculationResults.Results results = result.getResults();
log.trace("Leaving getResultList");
return results.getResult();
}
/** Validates the response time of the calculation.
*
* @param merchantCalculation The merchant calculation.
*
* @param calculationValidation The result validation.
*/
private void validateResponseTime(
final MendozaMerchantCalculation merchantCalculation,
final MendozaMerchantCalculationValidation calculationValidation) {
log.trace("Entering validateResponseTime");
if (merchantCalculation.getCalculationTime() > calculationTimeout) {
calculationValidation.markCalculationAsTimeout();
}
log.trace("Leaving validateResponseTime");
}
/** Gets the calculation requested shipping method names.
*
* @param merchantCalculation The merchant calculation.
*
* @return Returns the requested shipping methods names.
*/
private List<String> getRequestedMethodNameList(
final MendozaMerchantCalculation merchantCalculation) {
log.trace("Entering getRequestedMethodNameList");
List<String> result = new ArrayList<String>();
Calculate calculate = getCallbackCalculate(merchantCalculation);
if (calculate != null) {
Calculate.Shipping shippings = calculate.getShipping();
List<Method> shippingMethods = shippings.getMethod();
/** Get all the shipping methods from the callback */
for (Method method : shippingMethods) {
result.add(method.getName());
}
}
log.trace("Leaving getRequestedMethodNameList");
return result;
}
/** Gets the calculation requested address ids.
*
* @param merchantCalculation The merchant calculation.
*
* @return Returns the requested address ids.
*/
private List<String> getRequestedAddressIdList(
final MendozaMerchantCalculation merchantCalculation) {
log.trace("Entering getRequestedAddressIdList");
List<String> result = new ArrayList<String>();
Calculate calculate = getCallbackCalculate(merchantCalculation);
if (calculate != null) {
List<AnonymousAddress> addresses =
calculate.getAddresses().getAnonymousAddress();
/** Get all the address id from the callback */
for (AnonymousAddress address : addresses) {
result.add(address.getId());
}
}
log.trace("Leaving getRequestedAddressIdList");
return result;
}
/** Gets the callback calculate.
*
* @param merchantCalculation The merchant calculation.
*
* @return Returns the callbak calculate.
*/
private Calculate getCallbackCalculate(
final MendozaMerchantCalculation merchantCalculation) {
log.trace("Entering getCallbackCalculate");
MerchantCalculationCallback callback =
merchantCalculation.getMerchantCalculationCallback();
log.trace("Leaving getCallbackCalculate");
return callback.getCalculate();
}
}