Java tutorial
/******************************************************************************* * Copyright 2007 Amazon Technologies, Inc. * Licensed under the Apache License, Version 2.0 (the "License"); * * You may not use this file except in compliance with the License. * You may obtain a copy of the License at: http://aws.amazon.com/apache2.0 * This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR * CONDITIONS OF ANY KIND, either express or implied. See the License for the * specific language governing permissions and limitations under the License. * ***************************************************************************** * __ _ _ ___ * ( )( \/\/ )/ __) * /__\ \ / \__ \ * (_)(_) \/\/ (___/ * * Amazon A2S Java Library * API Version: 2007-10-29 * Generated: Thu Jan 10 05:27:32 PST 2008 * */ package com.amazonaws.a2s; import com.amazonaws.a2s.*; import com.amazonaws.a2s.model.*; import java.io.BufferedReader; import java.util.Map; import java.util.Iterator; import java.util.regex.Pattern; import java.util.regex.Matcher; import javax.xml.bind.JAXBContext; import javax.xml.bind.Unmarshaller; import javax.xml.bind.JAXBException; import org.apache.commons.httpclient.HttpClient; import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager; import org.apache.commons.httpclient.methods.PostMethod; import org.apache.commons.httpclient.HttpMethodRetryHandler; import org.apache.commons.httpclient.params.HttpMethodParams; import org.apache.commons.httpclient.params.HttpClientParams; import org.apache.commons.httpclient.params.HttpConnectionManagerParams; import org.apache.commons.httpclient.HttpMethod; import org.apache.commons.httpclient.NoHttpResponseException; import org.apache.commons.httpclient.HostConfiguration; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import java.io.InputStream; import java.io.IOException; import java.io.StringReader; import java.io.InputStreamReader; import java.io.Reader; import javax.xml.transform.stream.StreamSource; /** * * Amazon Associates Web Service (A2S) is the best way to make money on the Internet. * Amazon has spent ten years and hundreds of millions of dollars developing a * world-class web service that millions of customers use every day. As a developer, * you can build A2S applications that leverage this robust, scalable, and reliable * technology. You get access to much of the data that is used by Amazon, * including the items for sale, customer reviews, seller reviews, as well as most * of the functionality that you see on www.amazon.com, such as finding items, * finding similar items, displaying customer reviews, and product promotions. * In short, A2S operations open the doors to Amazon's databases so that you can * take advantage of Amazon's sophisticated E-commerce data and functionality. * Build your own web store to sell Amazon items or your own items. * <br><br> * Best of all, A2S is free. By signing up to become a A2S developer, you join the * tens of thousands of developers who are already realizing financial gains by * creating A2S-driven applications and web stores. In 2006, A2S developers sold well * over $600 million worth of items. Would you like a percentage of that revenue? * <br><br> * E-commerce is the practice of conducting business over the Internet. This guide * explains in detail how you can use A2S operations to create storefronts in which * you enable Internet customers to search for your items, see pictures of them, find * related items, get customer reviews, and purchase items. * <br><br> * With e-commerce, the barrier of distance between the shopper and the store goes away: * the local video store must compete with stores across the country. E-commerce levels * the playing field: the web site of an individual seller can appear as sophisticated * and intoxicating as that of a major retailer. A2S is your opportunity to enter the * world market where patronage is not limited by the size of your storefront, foot traffic * or locality. Welcome to the world of A2S E-commerce. * * * * AmazonA2SClient is the implementation of AmazonA2S based on the * Apache <a href="http://jakarta.apache.org/commons/httpclient/">HttpClient</a>. * */ public class AmazonA2SClient implements AmazonA2S { private final Log log = LogFactory.getLog(AmazonA2SClient.class); private String awsAccessKeyId = null; private String associateTag = null; private AmazonA2SConfig config = null; private HttpClient httpClient = null; private static JAXBContext jaxbContext; private static ThreadLocal<Unmarshaller> unmarshaller; /** Initialize JAXBContext and Unmarshaller **/ static { try { jaxbContext = JAXBContext.newInstance("com.amazonaws.a2s.model", AmazonA2S.class.getClassLoader()); } catch (JAXBException ex) { throw new ExceptionInInitializerError(ex); } unmarshaller = new ThreadLocal<Unmarshaller>() { @Override protected synchronized Unmarshaller initialValue() { try { return jaxbContext.createUnmarshaller(); } catch (JAXBException e) { throw new ExceptionInInitializerError(e); } } }; } /** * Constructs AmazonA2SClient with AWS Access Key ID and Accociate Tag * * @param awsAccessKeyId * AWS Access Key ID * @param associateTag * Associate Tag */ public AmazonA2SClient(String awsAccessKeyId, String associateTag) { this(awsAccessKeyId, associateTag, AmazonA2SLocale.US); } /** * Constructs AmazonA2SClient with AWS Access Key ID, Associate Tag * and specific service locale * * @param awsAccessKeyId * AWS Access Key ID * @param associateTag * Associate Tag * @param locale * Locale you wish to invoke the service call at. * * Supported Locales are: US, UK, DE, FR, CA, JP. Note, not all operations * supported by all locales. Please refer to Amazon A2S documentation for * more information * */ public AmazonA2SClient(String awsAccessKeyId, String associateTag, AmazonA2SLocale locale) { this.awsAccessKeyId = awsAccessKeyId; this.associateTag = associateTag; this.config = locale.getConfig(); this.httpClient = configureHttpClient(); } // Public API ------------------------------------------------------------// /** * Help Request * * <br><br> * The Help operation provides information about A2S operations and * response groups. For operations, Help lists required and optional * request parameters, as well as default and optional response groups the * operation can use. For response groups, Help lists the operations that can * use the response group as well as the response tags returned by the * response group in the XML response. * <br><br> * The Help operation is not often used in customer applications. It can, however, be * used to help the developer in the following ways: * <br><br> * <ul> * <li>Provide contextual help in an interactive development environment (IDE) for developerst</li> * <li>Automate documentation creation as part of a developer's toolkit. </li> * </ul> * <br><br> * <b>Available Response Groups</b>: * <ul> * <li>Request</li> * <li>Help</li> * </ul> * * @param request * Help Request * @return * Help Response from the service * * @throws AmazonA2SException */ public HelpResponse help(HelpRequest... request) throws AmazonA2SException { Help action = new Help(); return invoke(HelpResponse.class, action.withRequest(request).toMap()); } /** * Item Search Request * * <br><br> * The ItemSearch operation returns items that satisfy the search * criteria, including one or more search indices * <br><br> * ItemSearch returns up to ten search results at a time. When condition * equals "All," ItemSearch returns up to three offers per condition (if they exist), * for example, three new, three used, three refurbished, and three collectible items. * Or, for example, if there are no collectible or refurbished offers, ItemSearch * returns three new and three used offers. * <br><br> * Because there are thousands of items in each search index, ItemSearch requires * that you specify the value for at least one parameter in addition to a search index. * The additional parameter value must reference items within the specified search index. * For example, you might specify a browse node (BrowseNode is an ItemSearch parameter), * Harry Potter Books, within the Books product category. You would not get results, * for example, if you specified the search index to be Automotive and the browse node * to be Harry Potter Books. In this case, the parameter value is not associated with * the search index value. * <br><br> * The ItemPage parameter enables you to return a specified page of results. The maximum * ItemPage number that can be returned is 400. An error is returned if you try to access * higher numbered pages. If you do not include ItemPage in your request, the first page * will be returned by default. There can be up to ten items per page. * <br><br> * ItemSearch is the operation that is used most often in requests. In general, * when trying to find an item for sale, you use this operation. * <br><br> * <b>Available Response Groups</b>: * <ul> * <li>Request</li> * <li>Small</li> * <li>Accessories</li> * <li>BrowseNodes</li> * <li>EditorialReview</li> * <li>Images</li> * <li>ItemAttributes</li> * <li>ItemIds</li> * <li>Large</li> * <li>ListmaniaLists</li> * <li>Medium</li> * <li>MerchantItemAttributes</li> * <li>OfferFull</li> * <li>Offers</li> * <li>OfferSummary</li> * <li>Reviews</li> * <li>SalesRank</li> * <li>SearchBins</li> * <li>Similarities</li> * <li>Subjects</li> * <li>Tracks</li> * <li>TagsSummary</li> * <li>Tags</li> * <li>VariationImages</li> * <li>VariationMinimum</li> * <li>Variations</li> * <li>VariationSummary</li> * </ul> * * @param request * ItemSearch Request * @return * ItemSearch Response from the service * * @throws AmazonA2SException */ public ItemSearchResponse itemSearch(ItemSearchRequest... request) throws AmazonA2SException { ItemSearch action = new ItemSearch(); return invoke(ItemSearchResponse.class, action.withRequest(request).toMap()); } /** * Item Lookup Request * * <br><br> * Given an Item identifier, the ItemLookup operation returns some or all * of the item attributes, depending on the response group specified in the request. * By default, ItemLookup returns an item's ASIN, DetailPageURL, Manufacturer, * ProductGroup, and Title of the item. * <br><br> * ItemLookup supports many response groups, so you can retrieve many different * kinds of product information, called item attributes, including product reviews, * variations, similar products, pricing, availability, images of products, accessories, * and other information. * <br><br> * To look up more than one item at a time, separate the item identifiers by commas. * <br><br> * <b>Available Response Groups</b>: * <ul> * <li>Request</li> * <li>Small</li> * <li>Accessories</li> * <li>BrowseNodes</li> * <li>EditorialReview</li> * <li>Images</li> * <li>ItemAttributes</li> * <li>ItemIds</li> * <li>Large</li> * <li>ListmaniaLists</li> * <li>Medium</li> * <li>MerchantItemAttributes</li> * <li>OfferFull</li> * <li>Offers</li> * <li>OfferSummary</li> * <li>Reviews</li> * <li>SalesRank</li> * <li>Similarities</li> * <li>Subjects</li> * <li>Tracks</li> * <li>TagsSummary</li> * <li>Tags</li> * <li>VariationImages</li> * <li>VariationMinimum</li> * <li>Variations</li> * <li>VariationSummary</li> * </ul> * * @param request * ItemLookup Request * @return * ItemLookup Response from the service * * @throws AmazonA2SException */ public ItemLookupResponse itemLookup(ItemLookupRequest... request) throws AmazonA2SException { ItemLookup action = new ItemLookup(); return invoke(ItemLookupResponse.class, action.withRequest(request).toMap()); } /** * Browse Node Lookup Request * * <br><br> * Given a browse node ID, BrowseNodeLookup returns the specified browse node's name, children, and ancestors. * The names and browse node IDs of the children and ancestor browse nodes are also returned. * BrowseNodeLookup enables you to traverse the browse node hierarchy to find a browse node. * As you traverse down the hierarchy, you refine your search and limit the number of items returned. * For example, you might traverse the following hierarchy: DVD Used DVDs Kids and Family, * to select out of all the DVDs offered by Amazon only those that are appropriate for family viewing. * Returning the items associated with Kids and Family produces a much more targeted result than a search * based at the level of Used DVDs. * <br><br> * Alternatively, by traversing up the browse node tree, you can determine the root category of an item. * You might do that, for example, to return the top seller of the root product category using the * TopSeller response group in an ItemSearch request. * <br><br> * You can use BrowseNodeLookup iteratively to navigate through the browse node hierarchy to * reach the node that most appropriately suits your search. Then you can use the browse node ID in * an ItemSearch request. This response would be far more targeted than, for example, * searching through all of the browse nodes in a search index. * <br><br> * <b>Available Response Groups</b>: * <ul> * <li>Request</li> * <li>BrowseNodeInfo</li> * </ul> * * @param request * BrowseNodeLookup Request * @return * BrowseNodeLookup Response from the service * * @throws AmazonA2SException */ public BrowseNodeLookupResponse browseNodeLookup(BrowseNodeLookupRequest... request) throws AmazonA2SException { BrowseNodeLookup action = new BrowseNodeLookup(); return invoke(BrowseNodeLookupResponse.class, action.withRequest(request).toMap()); } /** * List Search Request * * <br><br> * Given a customer name or Email address, the ListSearch operation * returns the associated list ID(s) but not the list items. To find those, * use the list ID returned by ListSearch with ListLookup . * <br><br> * Specifying a full name or just a first or last name in the request typically * returns multiple lists belonging to different people. Using Email as the * identifier produces more filtered results. * <br><br> * <b>Available Response Groups</b>: * <ul> * <li>Request</li> * <li>ListInfo</li> * <li>ListMinimum</li> * </ul> * * @param request * ListSearch Request * @return * ListSearch Response from the service * * @throws AmazonA2SException */ public ListSearchResponse listSearch(ListSearchRequest... request) throws AmazonA2SException { ListSearch action = new ListSearch(); return invoke(ListSearchResponse.class, action.withRequest(request).toMap()); } /** * List Lookup Request * * <br><br> * The ListLookup operation returns, by default, summary information about a * list that you specify in the request. The summary information includes the: * <br><br> * <ul> * <li>Creation date of the list</li> * <li>Name of the list's creator</li> * </ul> * <br><br> * The operation returns up to ten sets of summary information per page. * <br><br> * Lists are specified by list type and list ID, which can be found using ListSearch. * <br><br> * You cannot lookup more than one list at a time in a single request. * You can, however, make a batch request to look for more than one list simultaneously. * <br><br> * <b>Available Response Groups</b>: * <ul> * <li>Request</li> * <li>ListInfo</li> * <li>Accessories</li> * <li>BrowseNodes</li> * <li>EditorialReview</li> * <li>Images</li> * <li>ItemAttributes</li> * <li>ItemIds</li> * <li>Large</li> * <li>ListFull</li> * <li>ListItems</li> * <li>ListmaniaLists</li> * <li>Medium</li> * <li>Offers</li> * <li>OfferSummary</li> * <li>Reviews</li> * <li>SalesRank</li> * <li>Similarities</li> * <li>Small</li> * <li>Subjects</li> * <li>Tracks</li> * <li>VariationMinimum</li> * <li>Variations</li> * <li>VariationSummary</li> * </ul> * * @param request * ListLookup Request * @return * ListLookup Response from the service * * @throws AmazonA2SException */ public ListLookupResponse listLookup(ListLookupRequest... request) throws AmazonA2SException { ListLookup action = new ListLookup(); return invoke(ListLookupResponse.class, action.withRequest(request).toMap()); } /** * Customer Content Search Request * * <br><br> * For a given customer Email address or name, the CustomerContentSearch * operation returns matching customer IDs, names, nicknames, and residence * information (city, state, and country). In general, supplying an Email * address returns unique results whereas supplying a name more often * returns multiple results. * <br><br> * Often you use CustomerContentSearch to find a customer ID that you can * use in the CustomerContentLookup operation, which returns more * extensive customer information. * <br><br> * <b>Available Response Groups</b>: * <ul> * <li>Request</li> * <li>CustomerInfo</li> * </ul> * * @param request * CustomerContentSearch Request * @return * CustomerContentSearch Response from the service * * @throws AmazonA2SException */ public CustomerContentSearchResponse customerContentSearch(CustomerContentSearchRequest... request) throws AmazonA2SException { CustomerContentSearch action = new CustomerContentSearch(); return invoke(CustomerContentSearchResponse.class, action.withRequest(request).toMap()); } /** * Customer Content Lookup Request * * <br><br> * For a given customer ID, the CustomerContentLookup operation * retrieves all of the information a customer has made public about * themselves on Amazon. Such information includes some or all of the following: * <br><br> * <ul> * <li>AboutMe</li> * <li>Birthday</li> * <li>City, State and Country</li> * <li>Customer Reviews</li> * <li>Customer ID</li> * <li>Name</li> * <li>Nickname</li> * <li>Wedding Registry</li> * <li>WishList</li> * </ul> * <br><br> * To find a customer ID, use the CustomerContentSearch operation. * <br><br> * <b>Available Response Groups</b>: * <ul> * <li>Request</li> * <li>CustomerInfo</li> * <li>CustomerReviews</li> * <li>CustomerLists</li> * <li>CustomerFull</li> * <li>TaggedGuides</li> * <li>TaggedItems</li> * <li>TaggedListmaniaLists</li> * <li>TagsSummary</li> * <li>Tags</li> * </ul> * * @param request * CustomerContentLookup Request * @return * CustomerContentLookup Response from the service * * @throws AmazonA2SException */ public CustomerContentLookupResponse customerContentLookup(CustomerContentLookupRequest... request) throws AmazonA2SException { CustomerContentLookup action = new CustomerContentLookup(); return invoke(CustomerContentLookupResponse.class, action.withRequest(request).toMap()); } /** * Similarity Lookup Request * * <br><br> * The SimilarityLookup operation returns up to ten products per page that are * similar to one or more items specified in the request. This operation is * typically used to pique a customer's interest in buying something similar to what they've already ordered. * <br><br> * If you specify more than one item, SimilarityLookup returns the intersection of similar * items each item would return separately. Alternatively, you can use the SimilarityType * parameter to return the union of items that are similar to any of the specified items. * A maximum of ten similar items are returned; the operation does not return additional * pages of similar items. if there are more than ten similar items, running the same * request can result in different answers because the ten that are included in the * response are picked randomly. * <br><br> * <b>Available Response Groups</b>: * <ul> * <li>Request</li> * <li>Small</li> * <li>Accessories</li> * <li>BrowseNodes</li> * <li>EditorialReview</li> * <li>Images</li> * <li>Large</li> * <li>ItemAttributes</li> * <li>ItemIds</li> * <li>ListmaniaLists</li> * <li>Medium</li> * <li>Offers</li> * <li>OfferSummary</li> * <li>PromotionDetails</li> * <li>PromotionSummary</li> * <li>Reviews</li> * <li>SalesRank</li> * <li>Similarities</li> * <li>Tracks</li> * <li>VariationMinimum</li> * <li>Variations</li> * <li>VariationSummary</li> * </ul> * * @param request * SimilarityLookup Request * @return * SimilarityLookup Response from the service * * @throws AmazonA2SException */ public SimilarityLookupResponse similarityLookup(SimilarityLookupRequest... request) throws AmazonA2SException { SimilarityLookup action = new SimilarityLookup(); return invoke(SimilarityLookupResponse.class, action.withRequest(request).toMap()); } /** * Seller Lookup Request * * <br><br> * The SellerLookup operation returns detailed information about sellers and, * in the US locale, merchants. To lookup a seller, you must use their seller ID. * The information returned includes the seller's name, location, average rating by * customers, and the first five customer feedback entries. SellerLookup will not, * however, return the seller's Email or business addresses. * <br><br> * <b>Available Response Groups</b>: * <ul> * <li>Request</li> * <li>Seller</li> * </ul> * * @param request * SellerLookup Request * @return * SellerLookup Response from the service * * @throws AmazonA2SException */ public SellerLookupResponse sellerLookup(SellerLookupRequest... request) throws AmazonA2SException { SellerLookup action = new SellerLookup(); return invoke(SellerLookupResponse.class, action.withRequest(request).toMap()); } /** * Cart Get Request * * <br><br> * The CartGet operation enables you to retrieve the IDs, quantities, * and prices of all of the items, including SavedForLater items in a * remote shopping cart. * <br><br> * Because the contents of a cart can change for different reasons, * such as availability, you should not keep a copy of a cart locally. * Instead, use CartGet to retrieve the items in a remote shopping cart. * <br><br> * To retrieve the items in a cart, you must specify the cart using the * CartId and HMAC values, which are returned in the CartCreate operation. * A value similar to HMAC, URLEncodedHMAC, is also returned. This value is the * URL encoded version of the HMAC. This encoding is necessary because some * characters, such as + and /, cannot be included in a URL. Rather than * encoding the HMAC yourself, use the URLEncodedHMAC value for the HMAC parameter. * <br><br> * CartGet does not work after the customer has used the PurchaseURL to either * purchase the items or merge them with the items in their Amazon cart. * <br><br> * If the associated CartCreate request specified an AssociateTag, all CartGet * requests must also include a value for AssociateTag otherwise the request will fail. * <br><br> * <b>Available Response Groups</b>: * <ul> * <li>Request</li> * <li>Cart</li> * <li>CartSimilarities</li> * <li>CartTopSellers</li> * <li>CartNewReleases</li> * </ul> * * @param request * CartGet Request * @return * CartGet Response from the service * * @throws AmazonA2SException */ public CartGetResponse cartGet(CartGetRequest... request) throws AmazonA2SException { CartGet action = new CartGet(); return invoke(CartGetResponse.class, action.withRequest(request).toMap()); } /** * Cart Add Request * * <br><br> * The CartAdd operation enables you to add items to an existing remote shopping cart. * CartAdd can only be used to place a new item in a shopping cart. It cannot be used to increase * the quantity of an item already in the cart. If you would like to increase the quantity of * an item that is already in the cart, you must use the CartModify operation. * <br><br> * You add an item to a cart by specifying the item's OfferListingId, or ASIN and ListItemId. * Once in a cart, an item can only be identified by its CartItemId. That is, an item in a cart * cannot be accessed by its ASIN or OfferListingId. CartItemId is returned by CartCreate, CartGet, and CartAdd. * <br><br> * To add items to a cart, you must specify the cart using the CartId and HMAC values, which are * returned by the CartCreate operation. * <br><br> * If the associated CartCreate request specified an AssociateTag, all CartAdd requests must * also include a value for Associate Tag otherwise the request will fail. * <br><br> * <b>Available Response Groups</b>: * <ul> * <li>Request</li> * <li>Cart</li> * <li>CartSimilarities</li> * <li>CartTopSellers</li> * <li>CartNewReleases</li> * </ul> * * @param request * CartAdd Request * @return * CartAdd Response from the service * * @throws AmazonA2SException */ public CartAddResponse cartAdd(CartAddRequest... request) throws AmazonA2SException { CartAdd action = new CartAdd(); return invoke(CartAddResponse.class, action.withRequest(request).toMap()); } /** * Cart Create Request * * <br><br> * The CartCreate operation enables you to create a remote shopping cart. * A shopping cart is the metaphor used by most e-commerce solutions. It is a * temporary data storage structure that resides on Amazon servers. The * structure contains the items a customer wants to buy. In A2S, the shopping * cart is considered remote because it is hosted by Amazon servers. * In this way, the cart is remote to the vendor's web site where the customer * views and selects the items they want to purchase. * <br><br> * Once you add an item to a cart by specifying the item's ListItemId and ASIN, * or OfferListing ID, the item is assigned a CartItemId and accessible only * by that value. That is, in subsequent requests, an item in a cart cannot * be accessed by its ListItemId and ASIN, or OfferListingId. CartItemId is * returned by CartCreate , CartGet , and CartAdd . * <br><br> * Because the contents of a cart can change for different reasons, such as * item availability, you should not keep a copy of a cart locally. Instead, * use the other cart operations to modify the cart contents. For example, * to retrieve contents of the cart, which are represented by CartItemIds, * use CartGet . * <br><br> * Available products are added as cart items. Unavailable items, for example, * items out of stock, discontinued, or future releases, are added as SaveForLaterItems. * No error is generated. The Amazon database changes regularly. You may find a product * with an offer listing ID but by the time the item is added to the cart the product * is no longer available. The checkout page in the Order Pipeline clearly lists * items that are available and those that are SaveForLaterItems. * <br><br> * It is impossible to create an empty shopping cart. You have to add at least one * item to a shopping cart using a single CartCreate request. You can add specific * quantities (up to 999) of each item. * <br><br> * CartCreate can be used only once in the life cycle of a cart. To modify the * contents of the cart, use one of the other cart operations. * <br><br> * Carts cannot be deleted. They expire automatically after being unused for 7 days. * The lifespan of a cart restarts, however, every time a cart is modified. * In this way, a cart can last for more than 7 days. If, for example, on day 6, * the customer modifies a cart, the 7 day countdown starts over. * <br><br> * <b>Available Response Groups</b>: * <ul> * <li>Request</li> * <li>Cart</li> * <li>CartSimilarities</li> * <li>CartTopSellers</li> * <li>CartNewReleases</li> * </ul> * * @param request * CartCreate Request * @return * CartCreate Response from the service * * @throws AmazonA2SException */ public CartCreateResponse cartCreate(CartCreateRequest... request) throws AmazonA2SException { CartCreate action = new CartCreate(); return invoke(CartCreateResponse.class, action.withRequest(request).toMap()); } /** * Cart Modify Request * * <br><br> * The CartModify operation enables you to: * <br><br> * <ul> * <li>Change the quantity of items that are already in a remote shopping cart.</li> * <li>Move items from the active area of a cart to the SaveForLater area or the reverse</li> * <li>Change the MergeCart setting. </li> * </ul> * <br><br> * To modify the number of items in a cart, you must specify the * cart using the CartId and HMAC values that are returned in the * CartCreate operation. A value similar to HMAC, URLEncodedHMAC, * is also returned. This value is the URL encoded version of the HMAC. * This encoding is necessary because some characters, such as + and /, * cannot be included in a URL. Rather than encoding the HMAC yourself, * use the URLEncodedHMAC value for the HMAC parameter. * <br><br> * You can use CartModify to modify the number of items in a remote shopping * cart by setting the value of the Quantity parameter appropriately. You can * eliminate an item from a cart by setting the value of the Quantity parameter * to zero. Or, you can double the number of a particular item in the cart by * doubling its Quantity . You cannot, however, use CartModify to add new items to a cart. * <br><br> * If the associated CartCreate request specified an AssociateTag, all * CartModify requests must also include a value for Associate Tag * otherwise the request will fail. * <br><br> * <b>Available Response Groups</b>: * <ul> * <li>Request</li> * <li>Cart</li> * <li>CartSimilarities</li> * <li>CartTopSellers</li> * <li>CartNewReleases</li> * </ul> * * @param request * CartModify Request * @return * CartModify Response from the service * * @throws AmazonA2SException */ public CartModifyResponse cartModify(CartModifyRequest... request) throws AmazonA2SException { CartModify action = new CartModify(); return invoke(CartModifyResponse.class, action.withRequest(request).toMap()); } /** * Cart Clear Request * * <br><br> * The CartClear operation enables you to remove all of the items in a remote shopping cart, including * SavedForLater items. To remove only some of the items in a cart or to reduce the quantity * of one or more items, use CartModify . * <br><br> * To delete all of the items from a remote shopping cart, you must specify the cart using the * CartId and HMAC values, which are returned by the CartCreate operation. A value similar * to the HMAC, URLEncodedHMAC, is also returned. This value is the URL encoded version * of the HMAC. This encoding is necessary because some characters, such as + and /, * cannot be included in a URL. Rather than encoding the HMAC yourself, use the * URLEncodedHMAC value for the HMAC parameter. * <br><br> * CartClear does not work after the customer has used the PurchaseURL to either purchase the * items or merge them with the items in their Amazon cart. * <br><br> * Carts exist even though they have been emptied. The lifespan of a cart is 7 days since the * last time it was acted upon. For example, if a cart created 6 days ago is modified, * the cart lifespan is reset to 7 days. * <br><br> * <b>Available Response Groups</b>: * <ul> * <li>Request</li> * <li>Cart</li> * </ul> * * @param request * CartClear Request * @return * CartClear Response from the service * * @throws AmazonA2SException */ public CartClearResponse cartClear(CartClearRequest... request) throws AmazonA2SException { CartClear action = new CartClear(); return invoke(CartClearResponse.class, action.withRequest(request).toMap()); } /** * Transaction Lookup Request * * <br><br> * The TransactionLookup operation returns information about up to ten purchases * that have already taken place. Transaction IDs are created whenever a purchase * request is made by a customer. * <br><br> * For a specified transaction ID, TransactionLookup returns: * <ul> * <li>Price details</li> * <li>Sale date</li> * <li>Shipping details</li> * <li>Seller details</li> * <li>Item's condition </li> * </ul> * <br><br> * For privacy reasons, this operation does not return information about the customer * who purchased the items. * <br><br> * <b>Available Response Groups</b>: * <ul> * <li>Request</li> * <li>TransactionDetails</li> * </ul> * * @param request * TransactionLookup Request * @return * TransactionLookup Response from the service * * @throws AmazonA2SException */ public TransactionLookupResponse transactionLookup(TransactionLookupRequest... request) throws AmazonA2SException { TransactionLookup action = new TransactionLookup(); return invoke(TransactionLookupResponse.class, action.withRequest(request).toMap()); } /** * Seller Listing Search Request * * <br><br> * The SellerListingSearch operation enables you to search for items offered * by specific sellers. You cannot use SellerListingSearch to look up items sold by merchants. * To look up an item sold by a merchant, use ItemLookup or ItemSearch * along with the MerchantId parameter. * <br><br> * SellerListingSearch returns the listing ID or exchange ID of an item. * Typically, you use those values with SellerListingLookup to find out more about those items. * <br><br> * Each SellerListingSearch request returns up to ten items. By default, the first ten * items are returned. You can use the ListingPage parameter to retrieve additional pages * of (up to) ten listings. * <br><br> * To use A2S, sellers must have less than 100,000 items for sale. Sellers that have more * items for sale should use, instead of A2S, other seller APIs, including the Amazon * Inventory Management System, and the Merchant@ API. * <br><br> * <b>Available Response Groups</b>: * <ul> * <li>Request</li> * <li>SellerListing</li> * </ul> * * @param request * SellerListingSearch Request * @return * SellerListingSearch Response from the service * * @throws AmazonA2SException */ public SellerListingSearchResponse sellerListingSearch(SellerListingSearchRequest... request) throws AmazonA2SException { SellerListingSearch action = new SellerListingSearch(); return invoke(SellerListingSearchResponse.class, action.withRequest(request).toMap()); } /** * Seller Listing Lookup Request * * <br><br> * The SellerListingLookup operation enables you to return information * about a seller's listings, including product descriptions, availability, * condition, and quantity available. The response also includes the seller's nickname. * Each request requires a seller ID. * <br><br> * You can also find a seller's items using ItemLookup. There are, however, * some reasons why it is better to use SellerListingLookup: * <br><br> * <ul> * <li>SellerListingLookup enables you to search by seller ID.</li> * <li>SellerListingLookup returns much more information than ItemLookup.</li> * </ul> * <br><br> * This operation only works with sellers who have less than 100,000 items for sale. * Sellers that have more items for sale should use, instead of A2S, other APIs, * including the Amazon Inventory Management System, and the Merchant@ API. * <br><br> * <b>Available Response Groups</b>: * <ul> * <li>Request</li> * <li>SellerListing</li> * </ul> * * @param request * SellerListingLookup Request * @return * SellerListingLookup Response from the service * * @throws AmazonA2SException */ public SellerListingLookupResponse sellerListingLookup(SellerListingLookupRequest... request) throws AmazonA2SException { SellerListingLookup action = new SellerListingLookup(); return invoke(SellerListingLookupResponse.class, action.withRequest(request).toMap()); } /** * Tag Lookup Request * * <br><br> * The TagLookup operation returns entities based on specifying one to five tags. * A tag is a descriptive word that a customer uses to label entities on Amazon's retail website. * Entities can be items for sale, Listmania lists, guides, and so forth. For example, a customer might tag a * given entity with the phrase, "BestCookbook." For more information, see Tags. * <br><br> * In the tag-related response groups, Tags and TagSummary specify the amount of informtion returned. The * other tag-related response groups, TaggedGuides, TaggedItems, and Tagged listmaniaLists, * specify the kind of entity tagged. * <br><br> * <b>Available Response Groups</b>: * <ul> * <li>Request</li> * <li>Small</li> * <li>Accessories</li> * <li>AlternateVersions</li> * <li>BrowseNodes</li> * <li>Collections</li> * <li>EditorialReview</li> * <li>Images</li> * <li>ItemAttributes</li> * <li>ItemIds</li> * <li>Large</li> * <li>ListmaniaLists</li> * <li>Medium</li> * <li>MerchantItemAttributes</li> * <li>OfferFull</li> * <li>OfferListings</li> * <li>Offers</li> * <li>OfferSummary</li> * <li>PromotionDetails</li> * <li>PromotionSummary</li> * <li>Reviews</li> * <li>SalesRank</li> * <li>ShippingCharges</li> * <li>Similarities</li> * <li>Subjects</li> * <li>TaggedGuides</li> * <li>TaggedItems</li> * <li>TaggedListmaniaLists</li> * <li>TagsSummary</li> * <li>Tags</li> * <li>Tracks</li> * </ul> * * @param request * TagLookup Request * @return * TagLookup Response from the service * * @throws AmazonA2SException */ public TagLookupResponse tagLookup(TagLookupRequest... request) throws AmazonA2SException { TagLookup action = new TagLookup(); return invoke(TagLookupResponse.class, action.withRequest(request).toMap()); } // Private API ------------------------------------------------------------// /** * Configure HttpClient with set of defaults as well as configuration * from AmazonA2SConfig instance * */ private HttpClient configureHttpClient() { /* Set http client parameters */ HttpClientParams httpClientParams = new HttpClientParams(); httpClientParams.setParameter(HttpMethodParams.USER_AGENT, config.getUserAgent()); httpClientParams.setParameter(HttpClientParams.RETRY_HANDLER, new HttpMethodRetryHandler() { public boolean retryMethod(HttpMethod method, IOException exception, int executionCount) { if (executionCount > 3) { log.debug("Maximum Number of Retry attempts reached, will not retry"); return false; } log.debug("Retrying request. Attempt " + executionCount); if (exception instanceof NoHttpResponseException) { log.debug("Retrying on NoHttpResponseException"); return true; } if (!method.isRequestSent()) { log.debug("Retrying on failed sent request"); return true; } return false; } }); /* Set host configuration */ HostConfiguration hostConfiguration = new HostConfiguration(); /* Set connection manager parameters */ HttpConnectionManagerParams connectionManagerParams = new HttpConnectionManagerParams(); connectionManagerParams.setConnectionTimeout(50000); connectionManagerParams.setSoTimeout(50000); connectionManagerParams.setStaleCheckingEnabled(true); connectionManagerParams.setTcpNoDelay(true); connectionManagerParams.setMaxTotalConnections(3); connectionManagerParams.setMaxConnectionsPerHost(hostConfiguration, 3); /* Set connection manager */ MultiThreadedHttpConnectionManager connectionManager = new MultiThreadedHttpConnectionManager(); connectionManager.setParams(connectionManagerParams); /* Set http client */ httpClient = new HttpClient(httpClientParams, connectionManager); /* Set proxy if configured */ if (config.isSetProxyHost() && config.isSetProxyPort()) { log.info("Configuring Proxy. Proxy Host: " + config.getProxyHost() + "Proxy Port: " + config.getProxyPort()); hostConfiguration.setProxy(config.getProxyHost(), config.getProxyPort()); } httpClient.setHostConfiguration(hostConfiguration); return httpClient; } /** * Invokes request using parameters from parameters map. * Returns response of the T type passed to this method */ @SuppressWarnings("unchecked") private <T> T invoke(Class<T> responseClass, Map<String, String> parameters) throws AmazonA2SException { String actionName = parameters.get("Operation"); T response = null; String responseBody = null; PostMethod method = new PostMethod(config.getServiceURL()); int status = -1; log.debug("Invoking " + actionName + " request. Current parameters: " + parameters); try { /* Add required request parameters and set request body */ log.debug("Adding required parameters..."); addRequiredParametersToRequest(method, parameters); log.debug("Done adding additional required parameteres. Parameters now: " + parameters); log.debug("Sending Request to host: " + config.getServiceURL()); /* Submit request */ status = httpClient.executeMethod(method); /* Consume response stream */ responseBody = readStream(method.getResponseBodyAsStream()); log.debug("Received Response. Status: " + status + ". " + "Response Body: " + responseBody); log.debug("Checking for errors in the response..."); throwIfErrors(responseBody, status); log.debug("Attempting to unmarshal into the " + actionName + "Response type..."); response = (T) getUnmarshaller().unmarshal(new StreamSource(new StringReader(responseBody))); log.debug("Unmarshalled response into " + actionName + "Response type."); } catch (JAXBException je) { /* Response cannot be unmarshalled as <Action>Response */ log.error("Caught JAXBException exception", je); } catch (IOException ioe) { log.error("Caught IOException exception", ioe); throw new AmazonA2SException("Internal Error", ioe); } catch (Exception e) { log.error("Caught Exception", e); throw new AmazonA2SException(e); } finally { method.releaseConnection(); } return response; } /** * Add parameters and set request body * with all of the parameters */ private void addRequiredParametersToRequest(PostMethod method, Map<String, String> parameters) { parameters.put("Version", config.getServiceVersion()); parameters.put("AWSAccessKeyId", this.awsAccessKeyId); parameters.put("AssociateTag", this.associateTag); Iterator it = parameters.keySet().iterator(); while (it.hasNext()) { String parameterName = (String) it.next(); method.addParameter(parameterName, parameters.get(parameterName)); } } /** * Reads stream into String */ private String readStream(InputStream input) throws IOException { StringBuffer stringBuffer = new StringBuffer(); Reader reader = new BufferedReader(new InputStreamReader(input, "UTF8")); int ch; while ((ch = reader.read()) > -1) { stringBuffer.append((char) ch); } reader.close(); input.close(); return stringBuffer.toString(); } /** * Checks for presense of the Errors in the response * If errors found, constructs and throws AmazonA2SException * with information from the Errors * */ private void throwIfErrors(String responseString, int status) throws AmazonA2SException { Pattern errorPattern = Pattern.compile( ".*\\<RequestId>(.*)\\</RequestId>.*" + "(\\<Error>\\<Code>(.*)\\</Code>\\<Message>(.*)\\</Message>\\</Error>).*(\\<Error>)?.*", Pattern.MULTILINE | Pattern.DOTALL); Matcher errorMatcher = errorPattern.matcher(responseString); if (errorMatcher.matches()) { String requestId = errorMatcher.group(1); String xml = errorMatcher.group(2); String code = errorMatcher.group(3); String message = errorMatcher.group(4); AmazonA2SException exception = new AmazonA2SException(message, status, code, requestId, xml); log.debug("Error found in the response: " + "Error code: " + code + "; " + "Error message: " + message + "; " + "Response XML: " + xml + "; " + "Request ID : " + requestId + "; "); throw exception; } } /** * Get unmarshaller for current thread */ private Unmarshaller getUnmarshaller() { return unmarshaller.get(); } }