/*
* Created on Dec 10, 2003
*
* To change the template for this generated file go to
* Window - Preferences - Java - Code Generation - Code and Comments
*/
package com.spun.util.ups;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.FactoryConfigurationError;
import javax.xml.parsers.ParserConfigurationException;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.velocity.context.Context;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import com.spun.util.NumberUtils;
import com.spun.util.logger.SimpleLogger;
import com.spun.util.parser.MassAmount;
import com.spun.util.velocity.ContextAware;
import com.spun.util.velocity.VelocityParser;
/**
* @author Llewellyn Falco
*
* To change the template for this generated type comment go to
* Window - Preferences - Java - Code Generation - Code and Comments
**/
public class UPSUtils
{
static final String UPS_URL = "https://wwwcie.ups.com/ups.app/xml/Rate";
private static String HEADER = "<?xml version=\"1.0\"?><AccessRequest xml:lang=\"en-US\"><AccessLicenseNumber>$config.getAccessLicenseNumber()</AccessLicenseNumber><UserId>$config.getUserId()</UserId><Password>$config.getPassword()</Password></AccessRequest>";
private static String REQUEST = "<?xml version=\"1.0\"?><RatingServiceSelectionRequest xml:lang=\"en-US\"><Request><TransactionReference><CustomerContext>Rating and Service</CustomerContext><XpciVersion>1.0001</XpciVersion></TransactionReference><RequestAction>Rate</RequestAction><RequestOption>shop</RequestOption></Request><PickupType><Code>01</Code></PickupType><Shipment><Shipper><Address><PostalCode>$shipment.getMainPackage().getOriginatingZipCode()</PostalCode></Address></Shipper><ShipTo><Address><PostalCode>$shipment.getMainPackage().getToZipCode()</PostalCode><CountryCode>$shipment.getMainPackage().getToCountryCode()</CountryCode>#if ($shipment.getMainPackage().isResidential())<ResidentialAddressIndicator/>#end</Address></ShipTo><Service><Code>11</Code></Service>#foreach ($package in $shipment.getPackages())<Package><PackagingType><Code>02</Code><Description>Package</Description></PackagingType><Description>Rate Shopping</Description><PackageWeight><Weight>$package.getPackageWeightInPounds()</Weight></PackageWeight>#if ($package.getPackageLength() != 0)<Dimensions><UnitOfMeasurement><Code>IN</Code></UnitOfMeasurement><Length>$package.getPackageLength()</Length><Width>$package.getPackageWidth()</Width><Height>$package.getPackageHeight()</Height></Dimensions>#end</Package>#end<ShipmentServiceOptions/></Shipment></RatingServiceSelectionRequest>";
private static UPSQuoteRetriever quoteRetriever = new UPSQuoteRetriever();
/***********************************************************************/
public static void setUPSQuoteRetriever(UPSQuoteRetriever quoteRetriever)
{
UPSUtils.quoteRetriever = quoteRetriever;
}
/***********************************************************************/
public static UPSQuote[] getQuote(UPSConfig config, UPSPackage package1)
throws SAXException, IOException, ParserConfigurationException, FactoryConfigurationError
{
return getQuote(config, new UPSPackage[]{package1});
}
/***********************************************************************/
public static UPSQuote[] getQuote(UPSConfig config, UPSPackage packages[])
throws SAXException, ParserConfigurationException, FactoryConfigurationError, HttpException, IOException
{
packages = createAcceptablePackages(packages);
String reqbody = constructRequestBody(config, packages);
return getQuote(config, reqbody);
}
/***********************************************************************/
public static UPSQuote[] getQuote(UPSConfig config, String reqbody)
throws SAXException, ParserConfigurationException, FactoryConfigurationError, HttpException, IOException
{
HttpClient client = new HttpClient();
PostMethod post = new PostMethod(UPS_URL);
post.setRequestBody(reqbody);
InputStream response = quoteRetriever.getResponse(client, post);
UPSQuote[] quotes = extractQuotes(response);
return quotes;
}
/***********************************************************************/
private static UPSPackage[] createAcceptablePackages(UPSPackage[] packages)
{
ArrayList<UPSPackage> list = new ArrayList<UPSPackage>();
for (int i = 0; i < packages.length; i++)
{
UPSPackage pack = packages[i];
if (pack.getPackageWeightInPounds() < 1)
{
pack = new UPSPackage(pack.getOriginatingZipCode(), pack.getToZipCode(), pack.getToCountryCode(), 1,
MassAmount.POUNDS, pack.getPackageLength(), pack.getPackageWidth(), pack.getPackageHeight(),
pack.isResidential());
}
if (pack.getPackageWeightInPounds() > 150)
{
double weight = pack.getPackageWeightInPounds();
while (weight > 150)
{
UPSPackage newPack = new UPSPackage(pack.getOriginatingZipCode(), pack.getToZipCode(),
pack.getToCountryCode(), 150, MassAmount.POUNDS, pack.getPackageLength(), pack.getPackageWidth(),
pack.getPackageHeight(), pack.isResidential());
list.add(newPack);
weight -= 150;
}
pack = new UPSPackage(pack.getOriginatingZipCode(), pack.getToZipCode(), pack.getToCountryCode(), weight,
MassAmount.POUNDS, pack.getPackageLength(), pack.getPackageWidth(), pack.getPackageHeight(),
pack.isResidential());
}
list.add(pack);
}
return UPSPackage.toArray(list);
}
/***********************************************************************/
private static UPSQuote[] extractQuotes(InputStream response)
throws SAXException, IOException, ParserConfigurationException, FactoryConfigurationError
{
Document document = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(response);
ArrayList<UPSQuote> quotes = new ArrayList<UPSQuote>();
NodeList list = document.getDocumentElement().getElementsByTagName("RatedShipment");
for (int i = 0; i < list.getLength(); i++)
{
quotes.add(extractQuote(list.item(i)));
}
if (quotes.size() == 0)
{
SimpleLogger.warning("Couldn't find quote in response " + getDocument(document));
}
return UPSQuote.toArray(quotes);
}
/***********************************************************************/
private static Node getDocument(Document document)
{
return document != null ? document.getChildNodes().item(0) : null;
}
/***********************************************************************/
private static UPSQuote extractQuote(Node node)
{
String service;
double cost = 0.0;
Node serviceNode = getNodeByName(node, "Service");
Node code = getNodeByName(serviceNode, "Code");
service = code.getFirstChild().getNodeValue();
Node totalCharges = getNodeByName(node, "TotalCharges");
Node monetaryValue = getNodeByName(totalCharges, "MonetaryValue");
cost = NumberUtils.load(monetaryValue.getFirstChild().getNodeValue(), 0.0);
return new UPSQuote(UPSServiceType.getForCode(service), cost);
}
/***********************************************************************/
private static Node getNodeByName(Node node, String childNode)
{
NodeList list = node.getChildNodes();
for (int i = 0; i < list.getLength(); i++)
{
if (list.item(i).getNodeName().equals(childNode)) { return list.item(i); }
}
return null;
}
/***********************************************************************/
private static String constructRequestBody(UPSConfig config, UPSPackage packages[])
{
UPSRequest req = new UPSRequest(config, packages);
String header = VelocityParser.parseString(HEADER, req);
String main = VelocityParser.parseString(REQUEST, req);
return header + main;
}
/***********************************************************************/
public static void main(String[] args)
{
SimpleLogger.variable(HEADER);
SimpleLogger.variable(REQUEST);
}
/***********************************************************************/
public static class UPSRequest implements ContextAware
{
private UPSConfig config;
private UPSShipment shipment;
public UPSRequest(UPSConfig config, UPSPackage packages[])
{
this.config = config;
this.shipment = new UPSShipment(packages);
}
public void setupContext(Context context)
{
context.put("config", config);
context.put("shipment", shipment);
}
}
}