/* vim: set ts=2 et sw=2 cindent fo=qroca: */
package com.globant.google.mendoza;
import java.util.Date;
import javax.xml.bind.JAXBElement;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import com.globant.google.mendoza.malbec.Order;
import com.globant.google.mendoza.malbec.SchemaValidator;
import com.globant.google.mendoza.malbec.SeleniumBuyerRobot;
import com.globant.google.mendoza.malbec.CartUtils;
import com.globant.google.mendoza.malbec.SeleniumBuyerRobotFactory;
import com.globant.google.mendoza.malbec.SchemaValidator.SchemaValidationResult;
import com.globant.google.mendoza.malbec.schema._2.NewOrderNotification;
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.RiskInformationNotification;
import com.globant.google.mendoza.malbec.schema._2.ObjectFactory;
import com.globant.google.mendoza.command.MendozaAddGiftCommand;
import com.globant.google.mendoza.command.MendozaAssertCartCommand;
import com.globant.google.mendoza.command.MendozaAssertSignatureCommand;
import com.globant.google.mendoza.command.MendozaCancelOrderCommand;
import com.globant.google.mendoza.command.MendozaChangeMerchantCommand;
import com.globant.google.mendoza.command.MendozaChargeOrderCommand;
import com.globant.google.mendoza.command.MendozaCommandResult;
import com.globant.google.mendoza.command.MendozaAddCouponCommand;
import com.globant.google.mendoza.command.MendozaHelpCommand;
import com.globant.google.mendoza.command.MendozaLoginCommand;
import com.globant.google.mendoza.command.MendozaPlaceOrderCommand;
import com.globant.google.mendoza.command.MendozaCheckoutCommand;
import com.globant.google.mendoza.command.MendozaCheckoutEncodedCommand;
import com.globant.google.mendoza.command.MendozaRefundOrderCommand;
import com.globant.google.mendoza.command.MendozaResetCommand;
import com.globant.google.mendoza.command.MendozaStatusCommand;
/** Helps running test cases in e-commerce applications.
*
* This server acts as a sort of proxy between an e-commerce application and
* google checkout. It waits for commands from the application under test such
* as place order, post cart, etc, and then sends the equivalent command to
* checkout.
*/
public final class MendozaServer {
/** The class logger.
*/
private static Log log = LogFactory.getLog(MendozaServer.class);
/** The merchant calculation validator.
*/
private MendozaMerchantCalculationValidator mcValidator;
/** The buyer robot used to place the order.
*/
private SeleniumBuyerRobot buyerRobot;
/** The mendoza status information.
*/
private MendozaStatus mendozaStatus;
/** The buyer robot factory. */
private SeleniumBuyerRobotFactory buyerRobotFactory;
/** The received messages from Checkout. */
private TransportProxyMessages proxyMessages =
new TransportProxyMessages();
/** The mendoza server state. */
private MendozaServerState serverState;
/** Creates an instance of mendoza.
*
* @param factory The selenium buyer robot factory. Cannot be null.
*
* @param theMerchantId The merchant id. Cannot be null.
*
* @param theMerchantKey The merchant key. Cannot be null.
*
* @param calculationsTimeout The merchant calculations timeout.
*/
public MendozaServer(final SeleniumBuyerRobotFactory factory,
final String theMerchantId, final String theMerchantKey,
final int calculationsTimeout) {
if (factory == null) {
throw new IllegalArgumentException("The buyer factory cannot be null");
}
if (theMerchantId == null) {
throw new IllegalArgumentException("The merchant id cannot be null");
}
if (theMerchantKey == null) {
throw new IllegalArgumentException("The merchant key cannot be null");
}
buyerRobotFactory = factory;
serverState = new MendozaServerState();
serverState.setMerchantId(theMerchantId);
serverState.setMerchantKey(theMerchantKey);
mendozaStatus = new MendozaStatus();
mcValidator = new MendozaMerchantCalculationValidator(
calculationsTimeout);
initBuyerRobot();
}
/** Sets the cart to be posted to checkout.
*
* @param request The Mendoza server request.
*
* @return Returns the command result.
*/
public MendozaCommandResult checkoutEncoded(final MendozaRequest request) {
log.trace("Entering checkout encoded");
MendozaCheckoutEncodedCommand command =
new MendozaCheckoutEncodedCommand(request, this, serverState);
command.execute();
log.trace("Leaving checkout encoded");
return command.getResult();
}
/** Sets the cart to be posted to checkout.
*
* @param request The Mendoza server request.
*
* @return Returns the command result.
*/
public MendozaCommandResult checkout(final MendozaRequest request) {
log.trace("Entering checkout");
MendozaCheckoutCommand command =
new MendozaCheckoutCommand(request, this, serverState);
command.execute();
log.trace("Leaving checkout");
return command.getResult();
}
/** Sets the new merchant id and key.
*
* @param request The Mendoza server request.
*
* @return Returns the command result.
*/
public MendozaCommandResult changeMerchant(final MendozaRequest request) {
log.trace("Entering changeMerchant");
MendozaChangeMerchantCommand command =
new MendozaChangeMerchantCommand(request, this, serverState);
command.execute();
initBuyerRobot();
if (buyerRobot == null) {
throw new RuntimeException("Cannot init buyer robot.");
}
log.trace("Leaving changeMerchant");
return command.getResult();
}
/** Initializes and logs to the application as a buyer.
*
* @param request The Mendoza server request.
*
* @return Returns the command result.
*/
public MendozaCommandResult login(final MendozaRequest request) {
log.trace("Entering login");
MendozaLoginCommand command =
new MendozaLoginCommand(request, this, serverState);
command.execute();
log.trace("Leaving login");
return command.getResult();
}
/** Adds a coupon to the order.
*
* @param request The Mendoza server request.
*
* @return Returns the command result.
*/
public MendozaCommandResult addCoupon(final MendozaRequest request) {
log.trace("Entering addCoupon");
MendozaAddCouponCommand command =
new MendozaAddCouponCommand(request, this, serverState);
command.execute();
log.trace("Leaving addCoupon");
return command.getResult();
}
/** Adds a gift certificate to the order.
*
* @param request The Mendoza server request.
*
* @return Returns the command result.
*/
public MendozaCommandResult addGiftCertificate(
final MendozaRequest request) {
log.trace("Entering addGiftCertificate");
MendozaAddGiftCommand command =
new MendozaAddGiftCommand(request, this, serverState);
command.execute();
log.trace("Leaving addGiftCertificate");
return command.getResult();
}
/** Sets the Mendoza Server to the initial state.
*
* @param request The Mendoza server request.
*
* @return Returns the command result.
*/
public MendozaCommandResult reset(final MendozaRequest request) {
log.trace("Entering reset");
proxyMessages = new TransportProxyMessages();
MendozaResetCommand command =
new MendozaResetCommand(request, this, serverState);
command.execute();
log.trace("Leaving reset");
return command.getResult();
}
/** Gets the Mendoza Server help.
*
* @param request The Mendoza server request.
*
* @return Returns the command result.
*/
public MendozaCommandResult help(final MendozaRequest request) {
log.trace("Entering help");
proxyMessages = new TransportProxyMessages();
MendozaHelpCommand command =
new MendozaHelpCommand(request, this, serverState);
command.execute();
log.trace("Leaving help");
return command.getResult();
}
/** Gets the mendoza status.
*
* @param request The Mendoza server request.
*
* @return Returns the command result.
*/
public MendozaCommandResult status(final MendozaRequest request) {
log.trace("Entering status");
MendozaStatusCommand command =
new MendozaStatusCommand(request, this, serverState);
command.execute();
log.trace("Leaving status");
return command.getResult();
}
/** Places an order to checkout.
*
* @param request The mendoza server request.
*
* @return Returns the command result.
*/
public MendozaCommandResult placeOrder(final MendozaRequest request) {
log.trace("Entering placeOrder");
clearReceivedMessagesFromCheckout();
MendozaPlaceOrderCommand command =
new MendozaPlaceOrderCommand(request, this, serverState, buyerRobot);
command.execute();
log.trace("Leaving placeOrder");
return command.getResult();
}
/** Charges the order.
*
* @param request The mendoza server request.
*
* @return Returns the command result.
*/
public MendozaCommandResult chargeOrder(final MendozaRequest request) {
log.trace("Entering chargeOrder");
MendozaChargeOrderCommand command =
new MendozaChargeOrderCommand(request, this, serverState);
command.execute();
log.trace("Leaving chargeOrder");
return command.getResult();
}
/** Cancels the order.
*
* @param request The mendoza server request.
*
* @return Returns the command result.
*/
public MendozaCommandResult cancelOrder(final MendozaRequest request) {
log.trace("Entering cancelOrder");
MendozaCancelOrderCommand command =
new MendozaCancelOrderCommand(request, this, serverState);
command.execute();
log.trace("Leaving cancelOrder");
return command.getResult();
}
/** Refunds the order.
*
* @param request The mendoza server request.
*
* @return Returns the command result.
*/
public MendozaCommandResult refundOrder(final MendozaRequest request) {
log.trace("Entering refundOrder");
MendozaRefundOrderCommand command =
new MendozaRefundOrderCommand(request, this, serverState);
command.execute();
log.trace("Leaving refundOrder");
return command.getResult();
}
/** Asserts the validation of the cart signature.
*
* @param request The mendoza server request.
*
* @return Returns the command result.
*/
public MendozaCommandResult assertSignature(final MendozaRequest request) {
log.trace("Entering assertSignature");
MendozaAssertSignatureCommand command =
new MendozaAssertSignatureCommand(request, this, serverState);
command.execute();
log.trace("Leaving assertSignature");
return command.getResult();
}
/** Asserts the validation of the cart.
*
* @param request The mendoza server request.
*
* @return Returns the command result.
*/
public MendozaCommandResult assertCart(final MendozaRequest request) {
log.trace("Entering assertCart");
MendozaAssertCartCommand command =
new MendozaAssertCartCommand(request, this, serverState);
command.execute();
log.trace("Leaving assertCart");
return command.getResult();
}
/** Gets the mendoza status.
*
* @return Returns the mendoza server status.
*/
public MendozaStatus getMendozaStatus() {
if (serverState.getGoogleOrderNumber() != null) {
updateNotifications();
}
return mendozaStatus;
}
/** Sets the merchant calculation callback and result.
*
* @param callbackMsg The merchant calculation callback message
*
* @param resultMsg The merchant calculation result.
*
* @param startTime The time when the calculation started.
*
* @param endTime The time when the calculation was responded.
*/
public void setMerchantCalculation(final String callbackMsg,
final String resultMsg, final Date startTime, final Date endTime) {
log.trace("Entering setMerchantCalculation");
SchemaValidator validator = new SchemaValidator();
SchemaValidationResult result = validator.validate(resultMsg);
boolean resultXMLValid = result.isXmlValid();
String validationMessage = "Merchant calculation results XML is valid.";
if (!resultXMLValid) {
validationMessage = "Merchant calculation results XML is not valid.\n";
validationMessage = validationMessage + result.getMessage();
log.debug("Merchant calculation result message: " + resultMsg);
log.debug("The merchant calculation result message is not a valid XML: "
+ validationMessage);
}
MerchantCalculationCallback merchantCalculationCallback = null;
MerchantCalculationResults merchantCalculationResult = null;
try {
/* Callback */
JAXBElement callbackNode =
(JAXBElement) CartUtils.unmarshal(callbackMsg);
merchantCalculationCallback =
(MerchantCalculationCallback) callbackNode.getValue();
if (resultXMLValid) {
/* Result */
JAXBElement resultNode =
(JAXBElement) CartUtils.unmarshal(resultMsg);
merchantCalculationResult =
(MerchantCalculationResults) resultNode.getValue();
}
} catch (Exception e) {
log.trace("Leaving setMerchantCalculation");
throw new RuntimeException(e);
}
MendozaMerchantCalculation merchantCalculation =
new MendozaMerchantCalculation(
callbackMsg, merchantCalculationCallback, resultMsg,
merchantCalculationResult, startTime, endTime, mcValidator);
merchantCalculation.setResultSchemaValidation(validationMessage);
mendozaStatus.addMerchantCalculation(merchantCalculation);
log.trace("Leaving setMerchantCalculation");
}
/** Sets the new order notification message received.
*
* @param theNewOrderNotification The new order notification received.
*/
private void setNewOrderNotification(
final NewOrderNotification theNewOrderNotification) {
log.trace("Entering setNewOrderNotification");
String marshaled = "";
try {
ObjectFactory objectFactory = new ObjectFactory();
marshaled = CartUtils.marshal(
objectFactory.createNewOrderNotification(theNewOrderNotification),
true);
marshaled = marshaled.trim();
} catch (Exception e) {
log.trace("Leaving setMerchantCalculation");
throw new RuntimeException(e);
}
mendozaStatus.setNewOrderNotification(marshaled, theNewOrderNotification);
mendozaStatus.setInitialOrderStates(
theNewOrderNotification.getFulfillmentOrderState().value(),
theNewOrderNotification.getFinancialOrderState().value());
log.trace("Leaving setNewOrderNotification");
}
/** Sets the risk information notification message received.
*
* @param riskInformation The risk information received.
*/
private void setRiskInformationNotification(
final RiskInformationNotification riskInformation) {
log.trace("Entering setRiskInformationNotification");
String marshaled = "";
try {
ObjectFactory objectFactory = new ObjectFactory();
marshaled = CartUtils.marshal(
objectFactory.createRiskInformationNotification(riskInformation),
true);
marshaled = marshaled.trim();
} catch (Exception e) {
log.trace("Leaving setRiskInformationNotification");
throw new RuntimeException(e);
}
mendozaStatus.setRiskInformationNotification(marshaled, riskInformation);
log.trace("Leaving setRiskInformationNotification");
}
/** Initializes the buyer robot.
*/
private void initBuyerRobot() {
log.trace("Entering initBuyerRobot");
try {
buyerRobot = buyerRobotFactory.createSeleniumBuyerRobot(
serverState.getMerchantId(), serverState.getMerchantKey());
} catch (Exception e) {
log.debug(e.getMessage());
log.trace("Leaving initBuyerRobot");
}
log.trace("Leaving initBuyerRobot");
}
/** Registers the new order notification message received.
*
* @param orderNumber The google order number.
*
* @param newOrderNotification The new order notification received.
*/
public void registerNewOrderNotification(final String orderNumber,
final NewOrderNotification newOrderNotification) {
log.trace("Entering registerNewOrderNotification");
proxyMessages.addNewOrderNotification(orderNumber, newOrderNotification);
serverState.setNewOrderNotificationReceived(true);
log.trace("Leaving registerNewOrderNotification");
}
/** Registers the risk information message received.
*
* @param orderNumber The google order number.
*
* @param riskNotification The risk information notification received.
*/
public void registerRiskInformationNotification(final String orderNumber,
final RiskInformationNotification riskNotification) {
log.trace("Entering registerRiskInformationNotification");
proxyMessages.addRiskInformationNotification(orderNumber, riskNotification);
serverState.setRiskInformationNotificationReceived(true);
log.trace("Leaving registerRiskInformationNotification");
}
/** Registers the order state change.
*
* @param orderNumber The google order number.
*
* @param newFulfillmentState Order's current fulfillment state.
*
* @param newFinancialState Order's current financial state.
*/
public void registerOrderStateChanged(final String orderNumber,
final String newFulfillmentState,
final String newFinancialState) {
log.trace("Entering registerOrderStateChanged");
proxyMessages.addOrderStateChanged(
orderNumber, newFulfillmentState, newFinancialState);
log.trace("Leaving registerOrderStateChanged");
}
/** Sets the notifications that belongs to a specific order number.
*/
private void updateNotifications() {
log.trace("Entering setNotifications");
NewOrderNotification non =
proxyMessages.getNewOrderNotification(serverState.getGoogleOrderNumber());
if (non != null) {
setNewOrderNotification(non);
}
RiskInformationNotification risk =
proxyMessages.getRiskInformationNotification(
serverState.getGoogleOrderNumber());
if (risk != null) {
setRiskInformationNotification(risk);
}
String fin = proxyMessages.getFinancialState(
serverState.getGoogleOrderNumber());
if (fin != null) {
mendozaStatus.setFinancialStateChanged(fin);
}
String ful = proxyMessages.getFulfillmentState(
serverState.getGoogleOrderNumber());
if (ful != null) {
mendozaStatus.setFulfillmentStateChanged(ful);
}
log.trace("Leaving setNotifications");
}
/** Clears the messages received from Checkout.
*/
private void clearReceivedMessagesFromCheckout() {
log.trace("Entering clearReceivedMessagesFromCheckout");
mendozaStatus.clearReceivedCheckoutMessages();
proxyMessages = new TransportProxyMessages();
serverState.setGoogleOrderNumber(null);
log.trace("Leaving clearReceivedMessagesFromCheckout");
}
/** Sets the new order to the server state.
*
* @param order The new order.
*/
public void setCurrentOrder(final Order order) {
serverState.setOrder(order);
}
}