5.2 Processing the Auction XML

Now that you've described your auctions using XML, you need to process that information and generate the posts. An example of the output of the program is shown in Example 5-2. As you can see from the output, the application will read an XML file, retrieve the FedEx shipping quote, and then post an auction listing on eBay.

Example 5-2. Output from auction listing
Starting to process ./com/cascadetg/ch05/auctions.xml

Getting FedEx quotes for Wonderful Ancient Chinese Basket...done.

Wonderful Ancient Chinese Basket [4500404259] has been listed.

Getting FedEx quotes for Reproduction 1632 European World Map...done.

Reproduction 1632 European World Map [4500404260] has been listed.

Changes complete. (18546 ms elapsed)

Figure 5-2 is a class diagram that illustrates the application structure we'll create in this chapter. There are three classes: an Auction class parses the XML and generates the listings, a FedExShipping class encapsulates the FedEx interactivity, and a FedExTokens class contains identification information (analogous to the username and password for the FedEx account).

Figure 5-2. Auction listing classes
figs/rww_0502.gif


The class with main( ) is Auction; it expects an XML file to be passed as an argument, as shown in Example 5-3.

Example 5-3. Auction.java
package com.cascadetg.ch05;



import java.io.FileOutputStream;



import org.jdom.input.SAXBuilder;

import org.jdom.output.XMLOutputter;

import org.jdom.*;



import com.cascadetg.ch04.EbayAPISimpleCall;



public class Auction

{

    static boolean debug = false;



    /**

     * Use this method to list an item. Most of these values are

     * self-explanatory, except for category. Categories are integers

     * defined on a per-region basis by eBay. For the US list, see

     * 

     * http://listings.ebay.com/aw/listings/list/categories.html

     *  

     */

    public static String addItem(

        String category,

        String weight,

        String minimumBid,

        String title,

        String description)

    {



        StringBuffer newDescription = new StringBuffer(description);

        if (!description.startsWith("<![CDATA["))

        {

            newDescription.insert(0, "<![CDATA[");

        } else

        {

            newDescription.delete(

                newDescription.length( ) - 3,

                newDescription.length( ));

        }

        newDescription.append(

            "<BR><BR><B>Estimated Shipping Fees...</B>");



        try

        {

            System.out.print(

                "Getting FedEx quotes for " + title + "...");

            FedExShipping myShipper = new FedExShipping( );

            myShipper.setWeightLBS(weight);



            myShipper.setPostalCode("10002");

            myShipper.setState("NY");

            newDescription.append("<BR>New York, NY : US$");

            newDescription.append(myShipper.getRateRequest( ));



            myShipper.setPostalCode("96813");

            myShipper.setState("HI");

            newDescription.append("<BR>Honolulu, HI : US$");

            newDescription.append(myShipper.getRateRequest( ));



            myShipper.setPostalCode("94112");

            myShipper.setState("CA");

            newDescription.append("<BR>San Francisco, CA : US$");

            newDescription.append(myShipper.getRateRequest( ));



            newDescription.append("<BR><BR><B>Thanks for bidding!</B>");

            newDescription.append("]]>");

            System.out.println("done.");



        } catch (Exception e)

        {

            e.printStackTrace( );

            return null;



        }



        // Here, we use the same code as in Chapter 4 to

        // make the call to eBay. Note that we're passing in

        // the barest minimum arguments here to successfully

        // post an eBay auction - there is a *huge* list of

        // settings, including things like setting promotional

        // options (like listing with a bold title).

        EbayAPISimpleCall myCall = new EbayAPISimpleCall( );

        myCall.setApiVerb("AddItem");

        myCall.setArgument("Category", category);

        myCall.setArgument("CheckoutDetailsSpecified", "N");

        myCall.setArgument("Country", "US");

        myCall.setArgument("Currency", "1");

        myCall.setArgument("Description", newDescription.toString( ));

        myCall.setArgument("Duration", "7");

        myCall.setArgument(

            "Location",

            FedExTokens.fedExAddressCity

                + ", "

                + FedExTokens.fedExAddressState);

        myCall.setArgument("MinimumBid", minimumBid);

        myCall.setArgument("Quantity", "1");

        myCall.setArgument("Region", "0");

        myCall.setArgument("Title", title);

        myCall.setArgument("VisaMaster", "1");

        myCall.setArgument("PersonalCheck", "1");



        // After setting the call up, here we actually connect

        // to the eBay server.

        org.jdom.Document myResults = myCall.executeCall( );



        // Here we parse the XML returned by eBay, looking for

        // the Item ID and returning it if found.

        try

        {

            if (debug)

                new XMLOutputter( ).output(myResults, System.out);

            return myResults.getRootElement( ).getChild(

                "Item").getChildText(

                "Id");

        } catch (Exception e)

        {

            e.printStackTrace( );

        }

        return null;

    }



    public static void postAuction(Element current)

    {

        // First, we check to see if the auction has been

        // listed before. If so, print this out and then

        // return.

        if (current.getChild("AuctionID") != null)

        {

            System.out.println(

                current.getChildText("Title")

                    + " ["

                    + current.getChildText("AuctionID")

                    + "] already listed.");

            return;

        }



        // We try to post the item with the needed values from

        // the XML.

        String id =

            addItem(

                current.getChildText("Category"),

                current.getChildText("Weight"),

                current.getChildText("MinimumBid"),

                current.getChildText("Title"),

                current.getChildText("Description"));



        // If id is null, there was some sort of problem.

        if (id == null)

        {

            System.out.println("Error with auction.");

            return;

        }



        // Ok, everything looks good. We attach the new eBay listing

        // ID number to the Auction as an AuctionID and we're done.

        Element newID = new Element("AuctionID");

        newID.setText(id);

        current.addContent(newID);

        System.out.println(

            current.getChildText("Title")

                + " ["

                + current.getChildText("AuctionID")

                + "] has been listed.");



    }



    public static void main(String[] args)

    {

        if (args == null)

        {

            System.out.println("Must pass a file name to continue.");

            return;

        }



        if (args.length == 0)

        {

            System.out.println("Must pass a file name to continue.");

            return;

        }



        System.out.println("Starting to process " + args[0]);

        long timing = System.currentTimeMillis( );



        try

        {

            // Load the input file and process it as XML.

            java.io.File myFile = new java.io.File(args[0]);

            org.jdom.Document myDocument =

                new SAXBuilder( ).build(myFile);



            // Look at the XML and find all of the auctions

            myDocument.getRootElement( );

            java.util.List myAuctions =

                myDocument.getRootElement( ).getChildren("Auction");



            // Loop through the resulting auction list and post each

            // one.

            for (int i = 0; i < myAuctions.size( ); i++)

            {

                postAuction((Element)myAuctions.get(i));

            }



            // We'll be saving the output to disk as XML again.

            // Here, we set up the output to be nicely formatted

            // for a human reader.

            XMLOutputter myOutput = new XMLOutputter( );

            myOutput.setOmitDeclaration(false);

            myOutput.setTextNormalize(true);

            myOutput.setNewlines(true);

            myOutput.setIndent("   ");



            // Flush the changes made (the new auction listings) to

            // disk. Auctions with an AuctionID will not be processed

            // again to prevent duplicate listings.

            FileOutputStream myFileOS = new FileOutputStream(myFile);

            myOutput.output(myDocument, myFileOS);



            // Calculate how long this took in milliseconds

            long elapsed = System.currentTimeMillis( ) - timing;

            System.out.println(

                "Changes complete. (" + elapsed + " ms elapsed)");



        } catch (Exception e)

        {

            System.out.println("Unable to process.");

            e.printStackTrace( );

        }



    }

}

The code shown in Example 5-3 accepts a single command-line argument: the name of the XML file (auctions.xml) described in Example 5-1. The Auction.main( ) method loops through looking for auctions, and calling addItem( ) and postItem( ) to post the data.

As shown in the postAuction( ) method, the relevant details are extracted from the XML. From there, the addItem( ) method connects to the FedEx server to retrieve three example destinations. Three default locales (New York, Hawaii, and California) are used to generate approximate shipping fees using the FedExShipping object. This data is then appended to the end of the auction description, and the EbayAPISimpleCall class originally described in Chapter 4 is used to post the auction to eBay.

The connectivity to the FedEx web service is wrapped using the FedExShipping class. We'll look at this interface in more detail, but let's start with a bit of an overview of the FedEx web services.

FedEx Registration

You need to go through several steps before you can use the FedEx system. First, you need an account with FedEx. You can sign up for a FedEx account by clicking "Open an account" at http://www.fedex.com/.

Next, you need to have your account accepted for access to the test server, so you can get a meter number. You should send an email to the FedEx support staff at websupport@fedex.com specifically requesting that your account be added to the test server. FedEx requests that you send them your contact information, FedEx account number(s), and a bit of sample code to be granted access.

This is all you need to access the test server and run the code as shown here. For real-life use, however, you need to work with the folk at websupport@fedex.com to certify your application and move to the production server.