|
Advanced Software Perspectives
|
I am posting this thread because I found it difficult to find some of this information and so thought it might eventually be useful to someone else in the Google Checkout trenches.Â
 The main link for information is: http://code.google.com/apis/checkout/
at that link the main page is: http://code.google.com/apis/checkout/developer/index.html
SETTING UP SANDBOX ACCOUNTSÂ
One of the first things ya gotta do is setup three google accounts - one real and one sandbox seller (merchant account) and one sandbox buyer. In order to differentiate the sand box accounts from each other and from your real one you need to use different email addresses when you set them up. Yeah, so that means three email addresses are required, since that is what you use to log in to these accounts. I used real email addresses - and don’t know if fake ones will work just as well. Your page for your real account will have a link on it to your sandbox account(s) login.
 The pertinent paragraph in the docs is:Â
“You need to create two test accounts in the Sandbox. One of these accounts will function as a customer account and the other will function as your merchant account. Please note that Google Checkout does not allow a single account to function as both the customer and the merchant for the same transaction. In addition, the links in the previous sentence point to different signup URLs, and you will be asked for different information to create these two accounts.”
This link to create the sandbox customer account did not work for me, perhaps because I created the sandbox merchant account first [long story, suffice it to say that I incorrectly used my ‘real’ email address to create my first sandbox account]. A link that DID work for me is: http://sandbox.google.com/checkout/buy
SETTING UP A CART and HANDING THE USER OVER TO THEIR GOOGLE ACCOUNT SO THAT THEY CAN MAKE PAYMENT
 Here is the code as it stands now. Seems to me that taking their sample code and modifying it, [i.e. the MerchantConstants file and the event handlers] which is what a lot of people do, is not the best idea. What if google changes things later? Ya want to keep rewriting this stuff? Who wants to spend the time to setup and incorporate the building of this code into their app? Anyway, the following code uses what they call their example code in a minimal fashion, and will probably not use it at all next revision.
I chose to use the Java 1.4 version, since I use Jikes [a very fast compiler]Â and that is stuck at 1.4 [looks like we will have to abandon Jikes unless someone steps in and updates it real soon now]. But the example code, all that I’ve been able to find, is in the jsp fiels in the top level directory of the jdk 1.5 version WAR file that google has on their downloads page: http://code.google.com/apis/checkout/samplecode.html
The other part of this code, the asynchronous callback handler that lets goggle send us messages to let us know how the checkout process went, will be posted at a future date (aka after it works).
We are using resin-pro 3.x and had a little bit of a hard time getting it to see all of the classes this code references in the jaxb libraries that the google checkout sample code uses. One thing that I did to make sure Resin found some of the classes at runtime was to rename xsdlib.jar to axsdlib.jar, so that it would be loaded before libs that reference it. Shades of LD_LIBRARY_PATH…
Part II will be forthcoming after CES sometime… as will more comments here… Strings is our class here that manages lists of class String. EVerything else is a google checkout class provided by their example libraries. So, anyway, here is an example of how to create a cart and send it, and the user, off to Goggle after polling it for an address to send them to.
 Â
import javax.xml.bind.JAXBException;
import com.sun.msv.datatype.xsd.DoubleType;
import com.google.checkout.sample.util.StringUtil;
import com.google.checkout.sample.protocol.CheckoutCartBuilder;
import com.google.checkout.schema._2.impl.AnyTypeImpl;
import com.google.checkout.schema._2.USStateArea;
import com.google.checkout.schema._2.Item;
import com.google.checkout.schema._2.ShoppingCart;
import com.google.checkout.schema._2.ShippingRestrictions;
import com.google.checkout.schema._2.DefaultTaxTable;
import com.google.checkout.schema._2.DefaultTaxRule;
import com.google.checkout.schema._2.MerchantCheckoutFlowSupport;
import com.google.checkout.schema._2.CheckoutRedirect;
import com.google.checkout.sample.crypto.CryptUtil;
//import com.google.checkout.sample.MerchantConstants;
import org.w3c.dom.Document;
import org.xml.sax.InputSource;
import javax.net.ssl.HttpsURLConnection;
/**----------------------------------------------------------------------------------------------
* This class
*
* @author Michael L. Davis
*----------------------------------------------------------------------------------------------*/
public class NzGoogleCheckoutOperations implements NziBillingMethodWorkflow
{
private static final String sandboxMerchantId = "xxxxxxxxxxxxxxxx";
private static final String sandboxMerchantKey = "xxxxxxxxxxxxxxxxxxxxxxx";
private static final String sandboxRequestUrl = "https://sandbox.google.com/cws/v2/Merchant/" + sandboxMerchantId + "/request";
private static final String sandboxCheckoutButtonUrl= "http://sandbox.google.com/buttons/checkout.gif?merchant_id=" + sandboxMerchantId; // "http://sandbox.google.com/checkout/" after 1/3/07
private static final String merchantId = "xxxxxxxxxxxxxxxxxxxxx";
private static final String merchantKey = "xxxxxxxxxxxxxxxxxxxxxxxx";
private static final String requestUrl = "https://checkout.google.com/cws/v2/Merchant/" + merchantId + "/request";
private static final String checkoutButtonUrl = "http://checkout.google.com/buttons/checkout.gif?merchant_id=" + merchantId;
public NzGoogleCheckoutOperations()
{
}
public static String getMerchantID()
{
if (Utility.toBoolean(NzConfigurationResources.get(NziConstants.NZ_GOOGLE_CHECKOUT_USING_SANDBOX)))
{
return(sandboxMerchantId);
}
return(merchantId);
}
private static String getMerchantKey()
{
if (Utility.toBoolean(NzConfigurationResources.get(NziConstants.NZ_GOOGLE_CHECKOUT_USING_SANDBOX)))
{
return(sandboxMerchantKey);
}
return(merchantKey);
}
private static String getRequestUrl()
{
if (Utility.toBoolean(NzConfigurationResources.get(NziConstants.NZ_GOOGLE_CHECKOUT_USING_SANDBOX)))
{
return(sandboxRequestUrl);
}
return(requestUrl);
}
public static String getCheckoutButtonUrl()
{
if (Utility.toBoolean(NzConfigurationResources.get(NziConstants.NZ_GOOGLE_CHECKOUT_USING_SANDBOX)))
{
return(sandboxCheckoutButtonUrl);
}
return(checkoutButtonUrl);
}
public static String getHttpAuth()
{
if (Utility.toBoolean(NzConfigurationResources.get(NziConstants.NZ_GOOGLE_CHECKOUT_USING_SANDBOX)))
{
String combinedKey = sandboxMerchantId + ":" + sandboxMerchantKey;
return(CryptUtil.base64Encode(combinedKey));
}
String combinedKey = merchantId + ":" + merchantKey;
return(CryptUtil.base64Encode(combinedKey));
}
public boolean billCustomer(
String accountId,
String pendindOrderId,
Strings orderItemIds,
String cost,
String taxAmount,
String discount,
String totalAmount,
Strings itemizedCosts,
Strings itemizedCostsDescriptions,
Strings itemizedDiscountIds,
Strings itemizedDiscounts,
Strings itemizedDiscountsDescriptions,
String customerReference,
String generalDescription,
Strings errors,
HttpServletRequest request, HttpServletResponse response ) throws ServletException, IOException
{
// Google
String[] signature = new String[1];
String cart = null;
try {
cart = buildEncodedCart(
accountId,
pendindOrderId,
orderItemIds,
cost,
taxAmount + "",
discount,
totalAmount,
itemizedCosts,
itemizedCostsDescriptions,
itemizedDiscountIds,
itemizedDiscounts,
itemizedDiscountsDescriptions,
customerReference);
}
catch (Throwable t)
{
NzLog.logException("Unable to build google cart for account: " + accountId, t);
}
try {
URL url = new URL(getRequestUrl());
HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
conn.setDoOutput(true);
conn.setDoInput(true);
conn.setRequestMethod("POST");
conn.setRequestProperty("Authorization","Basic " + getHttpAuth());
conn.setRequestProperty("Content-Type","application/xml");
conn.setRequestProperty("Accept","application/xml");
conn.setRequestProperty("Host", conn.getURL().getHost());
conn.setUseCaches (false);
conn.setInstanceFollowRedirects(true);
conn.connect();
OutputStreamWriter wr = new OutputStreamWriter(conn.getOutputStream());
wr.write(cart);
wr.flush();
//wr.close();
CheckoutRedirect redirect = null;
try {
String responseCode = "" + conn.getResponseCode();
String responseMessage = "" + conn.getResponseMessage();
//Get the response
InputSource source = new InputSource(conn.getInputStream());
redirect = (CheckoutRedirect)CheckoutCartBuilder.getInstance().parseToJAXB(source);
response.setStatus(302);
response.sendRedirect(redirect.getRedirectUrl());
return(true);
}
catch (Throwable t)
{
t.printStackTrace();
NzLog.logException("Unable to redirect to google cart for account: " + accountId + ", to address: " + (redirect != null ? redirect.getRedirectUrl() : "null"), t);
}
}
catch (Throwable t)
{
NzLog.logException("Unable to send request for google cart address message for account: " + accountId, t);
}
return(false);
}
/**
* Does this billing handler handle checkout synchronously, or must we wait for
* some kind of asynchronous message indicating the success of failure of the
& checkout proocess?
**/
public boolean isSynchronous()
{
return(false);
}
/**
* There is a little example code for building carts, but for
* alternative 1, in the jsp files found in the top
* diretory of the example War file for java 1.5 on
* google's site
**/
private String buildEncodedCart(
String accountId,
String pendingOrderId,
Strings orderItemIds,
String cost,
String taxAmount,
String discount,
String totalAmount,
Strings itemizedCosts,
Strings itemizedCostsDescriptions,
Strings itemizedDiscountIds,
Strings itemizedDiscounts,
Strings itemizedDiscountsDescriptions,
String customerReference) throws JAXBException, Exception
{
String mKey = getMerchantKey();
String mId = getMerchantID();
CheckoutCartBuilder pBuilder = null;
pBuilder = CheckoutCartBuilder.getInstance();
List itemList = new ArrayList();
for (int i = 0; i < itemizedCosts.size(); ++i)
{
Item item = pBuilder.createShoppingItem(itemizedCostsDescriptions.get(i), NzOrderItemOperations.getOrderItemDescription(orderItemIds.get(i)), 1, Utility.toFloat(itemizedCosts.get(i)), null, null, null);
itemList.add(item);
}
for (int i = 0; i < itemizedDiscounts.size(); ++i)
{
Item item = pBuilder.createShoppingItem(itemizedDiscountIds.get(i), itemizedDiscountsDescriptions.get(i), 1, -Utility.toFloat(itemizedDiscounts.get(i)), null, null, null);
itemList.add(item);
}
ShoppingCart cart = pBuilder.createShoppingCart(itemList, null, null);
// Unfortunately there is no programmatic way to create an empty MerchantCheckoutFlowSupport
// taxTable = null;
USStateArea stateArea = pBuilder.createStateArea("CO");
DefaultTaxRule taxRule = pBuilder.createDefaultTaxRule(stateArea, 0.0F, false);
List ruleList = new ArrayList();
ruleList.add(taxRule);
DefaultTaxTable taxTable = pBuilder.createDefaultTaxTable(ruleList);
MerchantCheckoutFlowSupport flowSupport = pBuilder.createMerchantSupport(null, taxTable, null, null, null, null);
flowSupport.setContinueShoppingUrl("http://" + NzConfigurationResources.get(NziConstants.NZ_APPLICATION_DOMAIN_NAME) + "/nav?action=portfolio-statements");
AnyTypeImpl pendingOrderIdHolder = new AnyTypeImpl();
pendingOrderIdHolder.setAny(pendingOrderId);
cart.setMerchantPrivateData(pendingOrderIdHolder);
Document cartDom = pBuilder.createCheckoutCart(cart, flowSupport);
String clearXml = pBuilder.unmarshal(cartDom);
return(clearXml);
}
}
Discussion
No comments for “Interfacing to Google Checkout - Java 1.4, Linux (CentOS) - using the XML, Level 2, Alternative Method (programmatic) API - Part 1”
Post a comment
You must be logged in to post a comment.