Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: org/apache/taglibs/rdc/sampleapps/musicstore/ws/MusicStore.java


1   /*
2    *    
3    *   Copyright 2004 The Apache Software Foundation.
4    *
5    *  Licensed under the Apache License, Version 2.0 (the "License");
6    *  you may not use this file except in compliance with the License.
7    *  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   *  Unless required by applicable law or agreed to in writing, software
12   *  distributed under the License is distributed on an "AS IS" BASIS,
13   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   *  See the License for the specific language governing permissions and
15   *  limitations under the License.
16   *
17   */
18  package org.apache.taglibs.rdc.sampleapps.musicstore.ws;
19  
20  import java.io.IOException;
21  import java.text.ParseException;
22  import java.util.Date;
23  import javax.xml.parsers.DocumentBuilder;
24  import javax.xml.parsers.DocumentBuilderFactory;
25  import javax.xml.parsers.ParserConfigurationException;
26  import javax.xml.transform.TransformerException;
27  
28  import org.apache.commons.logging.Log;
29  import org.apache.commons.logging.LogFactory;
30  import org.apache.xpath.XPathAPI;
31  import org.w3c.dom.CharacterData;
32  import org.w3c.dom.Document;
33  import org.w3c.dom.Element;
34  import org.w3c.dom.Node;
35  import org.w3c.dom.NodeList;
36  import org.xml.sax.InputSource;
37  
38  /**
39   * Class representing an Amazon Web Services music store.
40   * Contains necessary AWS queries needed by the music store application.
41   * 
42   * @author Jaroslav Gergic
43   * @author Rahul Akolkar
44   * @author Thomas Ling
45   */
46  public class MusicStore {
47  
48      protected static final String MERCHANT_ID = "Featured";
49      protected static final String XMLNS_NS = "http://www.w3.org/2000/xmlns/";
50      protected static final String RESPONSE_GRP = "ItemAttributes,Images,SalesRank,OfferSummary";
51  
52    protected String subscriptionId;
53    
54      private static Log log = LogFactory.getLog(MusicStore.class);
55      private static final boolean info = false;
56  
57    /**
58     * @param subscriptionId Amazon ECS subscription ID
59     */
60    public MusicStore(String subscriptionId) {
61      if (subscriptionId == null || subscriptionId.trim().length() == 0) {
62        String errDescription = "RDC MusicStore instantiated without an " +
63          "Amazon web services subscription ID. Read application " +
64          "README file.";
65        log.error(errDescription);
66        throw new IllegalArgumentException(errDescription);
67      }
68      this.subscriptionId = subscriptionId;   
69    }
70  
71      /**
72       * Retrurns an array of music genres (styles) listed on Amazon
73       * 
74       * @param parent parent music style
75       * @return int[]
76       * @throws IOException
77       * @throws java.io.IOException
78       */
79      public int[] getGenres(int parent) throws IOException {
80          int results[] = null;
81          StringBuffer sb = new StringBuffer();
82          sb.append("http://webservices.amazon.com/onca/xml");
83          sb.append("?Service=AWSECommerceService");
84          sb.append("&SubscriptionId=").append(subscriptionId);
85          sb.append("&Operation=BrowseNodeLookup");
86          sb.append("&BrowseNodeId=").append(parent);
87          String qs = sb.toString();
88          if (info) { log.info(qs); }
89          InputSource is = new InputSource(qs);
90          DocumentBuilder parser = getSimpleDOMBuilder();
91          if (parser != null) {
92              try {
93                  Document doc = parser.parse(is);
94                  Element root = (Element) doc.getDocumentElement();
95                  //Amazon NS changes quite frequently, let's get the latest one
96                  String ecs_ns = root.getAttribute("xmlns");
97                  log.debug("xmlns = " + ecs_ns);
98                  //Let's define a prefix required by XPath
99                  root.setAttributeNS(XMLNS_NS, "xmlns:ecs", ecs_ns);
100                 String xpath = "/ecs:BrowseNodeLookupResponse/ecs:BrowseNodes/ecs:BrowseNode/ecs:Children/ecs:BrowseNode";
101                 NodeList lst = XPathAPI.selectNodeList(root, xpath, root);
102                 int sz = lst.getLength();
103                 results = new int[sz];
104                 for (int i = 0; i < sz; i++) {
105                     Element bnode = (Element) (lst.item(i));
106                     NodeList nms = bnode.getElementsByTagNameNS(ecs_ns, "Name");
107                     NodeList ids = bnode.getElementsByTagNameNS(ecs_ns,
108                             "BrowseNodeId");
109                     String name = xGetVal(nms.item(0));
110                     String ndid = xGetVal(ids.item(0));
111                     results[i] = Integer.parseInt(ndid);
112                 }
113             } catch (Exception e) {
114                 log.error("error parsing result set", e);
115                 throw new IOException("error parsing result set");
116             }
117         }
118         return results;
119     }
120 
121     /**
122      * @param genre
123      * @return org.apache.taglibs.rdc.sampleapps.musicstore.ws.MusicAlbum[]
124      */
125     public MusicAlbum[] getTopSellers(int genre) throws IOException {
126         StringBuffer sb = new StringBuffer();
127         sb.append("http://webservices.amazon.com/onca/xml");
128         sb.append("?Service=AWSECommerceService");
129         sb.append("&SubscriptionId=").append(subscriptionId);
130         sb.append("&MerchantId=").append(MERCHANT_ID);
131         sb.append("&Operation=").append("ItemSearch");
132         sb.append("&BrowseNode=").append(genre);
133         sb.append("&SearchIndex=").append("Music");
134         sb.append("&Condition=").append("New");
135         sb.append("&ResponseGroup=").append(RESPONSE_GRP);
136         sb.append("&Sort=").append("salesrank"); //Top Sellers
137         String qs = sb.toString();
138         if (info) { log.info(qs); }
139         return doAlbumQuery(qs, genre);
140     }
141 
142     /**
143      * @param genre
144      * @return org.apache.taglibs.rdc.sampleapps.musicstore.ws.MusicAlbum[]
145      */
146     public MusicAlbum[] getNewReleases(int genre) throws IOException {
147         StringBuffer sb = new StringBuffer();
148         sb.append("http://webservices.amazon.com/onca/xml");
149         sb.append("?Service=AWSECommerceService");
150         sb.append("&SubscriptionId=").append(subscriptionId);
151         sb.append("&MerchantId=").append(MERCHANT_ID);
152         sb.append("&Operation=").append("ItemSearch");
153         sb.append("&BrowseNode=").append(genre);
154         sb.append("&SearchIndex=").append("Music");
155         sb.append("&Condition=").append("New");
156         sb.append("&ResponseGroup=").append(RESPONSE_GRP);
157         sb.append("&Sort=").append("-orig-rel-date"); //Reveresed Release Date
158         String qs = sb.toString();
159         if (info) { log.info(qs); }
160         return doAlbumQuery(qs, genre);
161     }
162 
163     /**
164      * @param genre
165      * @return org.apache.taglibs.rdc.sampleapps.musicstore.ws.MusicAlbum[]
166      */
167     public MusicAlbum[] getFeaturedItems(int genre) throws IOException {
168         StringBuffer sb = new StringBuffer();
169         sb.append("http://webservices.amazon.com/onca/xml");
170         sb.append("?Service=AWSECommerceService");
171         sb.append("&SubscriptionId=").append(subscriptionId);
172         sb.append("&MerchantId=").append(MERCHANT_ID);
173         sb.append("&Operation=").append("ItemSearch");
174         sb.append("&BrowseNode=").append(genre);
175         sb.append("&SearchIndex=").append("Music");
176         sb.append("&Condition=").append("New");
177         sb.append("&ResponseGroup=").append(RESPONSE_GRP);
178         sb.append("&Sort=").append("psrank"); //Featured Items
179         String qs = sb.toString();
180         if (info) { log.info(qs); }
181         return doAlbumQuery(qs, genre);
182     }
183 
184     /**
185      * @param album
186      * @return org.apache.taglibs.rdc.sampleapps.musicstore.ws.MusicAlbum[]
187      */
188     public MusicAlbum[] getSimilarItems(MusicAlbum album) throws IOException {
189         StringBuffer sb = new StringBuffer();
190         sb.append("http://webservices.amazon.com/onca/xml");
191         sb.append("?Service=AWSECommerceService");
192         sb.append("&SubscriptionId=").append(subscriptionId);
193         sb.append("&MerchantId=").append(MERCHANT_ID);
194         sb.append("&Operation=").append("SimilarityLookup");
195         sb.append("&ItemId=").append(album.getASIN());
196         sb.append("&SimilarityType=").append("Intersection");
197         sb.append("&ResponseGroup=").append(RESPONSE_GRP);
198         String qs = sb.toString();
199         if (info) { log.info(qs); }
200         MusicAlbum results[] = null;
201         InputSource is = new InputSource(qs);
202         DocumentBuilder parser = getSimpleDOMBuilder();
203         if (parser != null) {
204             try {
205                 Document doc = parser.parse(is);
206                 Element root = (Element) doc.getDocumentElement();
207                 //Amazon NS changes quite frequently, let's get the latest one
208                 String ecs_ns = root.getAttribute("xmlns");
209                 log.debug("xmlns = " + ecs_ns);
210                 //Let's define a prefix required by XPath
211                 root.setAttributeNS(XMLNS_NS, "xmlns:ecs", ecs_ns);
212                 //all items
213                 String xpath = "/ecs:SimilarityLookupResponse/ecs:Items/ecs:Item";
214                 NodeList items = XPathAPI.selectNodeList(root, xpath, root);
215                 int sz = items.getLength();
216                 results = new MusicAlbum[sz];
217                 for (int i = 0; i < sz; i++) {
218                     results[i] = parseAlbum(root, items.item(i), album
219                             .getGenres()[0]);
220                 }
221             } catch (Exception e) {
222                 log.error("error parsing result set", e);
223                 throw new IOException("error parsing result set");
224             }
225         }
226         return results;
227     }
228 
229     /**
230      * @param album
231      * @return org.apache.taglibs.rdc.sampleapps.musicstore.ws.MusicAlbum[]
232      */
233     public Cart createCart(MusicAlbum album, int quantity) throws IOException {
234         StringBuffer sb = new StringBuffer();
235         sb.append("http://webservices.amazon.com/onca/xml");
236         sb.append("?Service=AWSECommerceService");
237         sb.append("&SubscriptionId=").append(subscriptionId);
238         sb.append("&Operation=").append("CartCreate");
239         sb.append("&Item.1.ASIN=").append(album.getASIN());
240         sb.append("&Item.1.Quantity=").append(quantity);
241         String qs = sb.toString();
242         if (info) { log.info(qs); }
243         Cart cart = doCartOperation(qs, "CartCreate");
244         return cart;
245     }
246 
247     /**
248      * @param album
249      * @return org.apache.taglibs.rdc.sampleapps.musicstore.ws.MusicAlbum[]
250      */
251     public Cart addToCart(Cart cart, MusicAlbum album, int quantity)
252             throws IOException {
253         StringBuffer sb = new StringBuffer();
254         sb.append("http://webservices.amazon.com/onca/xml");
255         sb.append("?Service=AWSECommerceService");
256         sb.append("&SubscriptionId=").append(subscriptionId);
257         sb.append("&Operation=").append("CartAdd");
258         sb.append("&CartId=").append(cart.getCartId());
259         sb.append("&HMAC=").append(cart.getHMAC());
260         sb.append("&Item.1.ASIN=").append(album.getASIN());
261         sb.append("&Item.1.Quantity=").append(quantity);
262         String qs = sb.toString();
263         if (info) { log.info(qs); }
264         Cart newCart = doCartOperation(qs, "CartAdd");
265         return newCart;
266     }
267 
268     /**
269      * a helper method - parser factory
270      * 
271      * @return DocumentBuilder
272      */
273     protected static DocumentBuilder getSimpleDOMBuilder() {
274         try {
275             DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
276             dbf.setNamespaceAware(true);
277             dbf.setValidating(false);
278             return dbf.newDocumentBuilder();
279         } catch (ParserConfigurationException e) {
280             log.fatal("can not instanitate XML parser", e);
281         }
282         return null;
283     }
284 
285     /**
286      * retrieve a DOM node value as a string depending on Node type.
287      * 
288      * @param target a node to be retreived
289      * @return node value as a string
290      */
291     protected static String xGetVal(Node target) {
292         String result = "";
293         if (target == null)
294             return result;
295         switch (target.getNodeType()) {
296         case Node.ATTRIBUTE_NODE:
297             result = target.getNodeValue();
298             break;
299         case Node.ELEMENT_NODE:
300             if (target.hasChildNodes()) {
301                 Node chld = target.getFirstChild();
302                 StringBuffer buf = new StringBuffer();
303                 while (chld != null) {
304                     if (chld.getNodeType() == Node.TEXT_NODE)
305                         buf.append(((CharacterData) chld).getData());
306                     chld = chld.getNextSibling();
307                 }
308                 result = buf.toString();
309             }
310             break;
311         case Node.TEXT_NODE:
312         case Node.CDATA_SECTION_NODE:
313             result = ((CharacterData) target).getData();
314             break;
315         default: {
316             String err = "Trying to get value of a strange Node type: ";
317             err += target.getNodeType();
318             throw new IllegalArgumentException(err);
319         }
320         }
321         return result.trim();
322     }
323 
324     protected static MusicAlbum[] doAlbumQuery(String request, int genre)
325             throws IOException {
326         MusicAlbum results[] = null;
327         InputSource is = new InputSource(request);
328         DocumentBuilder parser = getSimpleDOMBuilder();
329         if (parser != null) {
330             try {
331                 Document doc = parser.parse(is);
332                 Element root = (Element) doc.getDocumentElement();
333                 //Amazon NS changes quite frequently, let's get the latest one
334                 String ecs_ns = root.getAttribute("xmlns");
335                 log.debug("xmlns = " + ecs_ns);
336                 //Let's define a prefix required by XPath
337                 root.setAttributeNS(XMLNS_NS, "xmlns:ecs", ecs_ns);
338                 //all items
339                 String xpath = "/ecs:ItemSearchResponse/ecs:Items/ecs:Item";
340                 NodeList items = XPathAPI.selectNodeList(root, xpath, root);
341                 int sz = items.getLength();
342                 results = new MusicAlbum[sz];
343                 for (int i = 0; i < sz; i++) {
344                     results[i] = parseAlbum(root, items.item(i), genre);
345                 }
346             } catch (Exception e) {
347                 log.error("error parsing result set", e);
348                 throw new IOException("error parsing result set");
349             }
350         }
351         return results;
352     }
353 
354     protected static Cart doCartOperation(String request, String cartOp)
355             throws IOException {
356         Cart cart = null;
357         InputSource is = new InputSource(request);
358         DocumentBuilder parser = getSimpleDOMBuilder();
359         if (parser != null) {
360             try {
361                 Document doc = parser.parse(is);
362                 Element root = (Element) doc.getDocumentElement();
363                 //Amazon NS changes quite frequently, let's get the latest one
364                 String ecs_ns = root.getAttribute("xmlns");
365                 log.debug("xmlns = " + ecs_ns);
366                 //Let's define a prefix required by XPath
367                 root.setAttributeNS(XMLNS_NS, "xmlns:ecs", ecs_ns);
368                 String cartPath = "/ecs:" + cartOp + "Response/ecs:Cart";
369                 String xpath = cartPath + "/ecs:CartId";
370                 String cartId = xmlGet(root, xpath, root);
371                 xpath = cartPath + "/ecs:HMAC";
372                 String hMAC = xmlGet(root, xpath, root);
373                 xpath = cartPath + "/ecs:PurchaseURL";
374                 String purchaseURL = xmlGet(root, xpath, root);
375 
376                 cart = new Cart(cartId, hMAC, purchaseURL);
377                 xpath = cartPath + "/ecs:CartItems/ecs:CartItem";
378                 NodeList items = XPathAPI.selectNodeList(root, xpath, root);
379                 int sz = items.getLength();
380                 CartItem cartItems[] = new CartItem[sz];
381                 for (int i = 0; i < sz; i++) {
382                     cartItems[i] = parseCartItem(root, items.item(i));
383                 }
384                 cart.setCartItems(cartItems);
385                 if (info) { log.info(cart); }  
386             } catch (Exception e) {
387                 log.error("error parsing result set", e);
388                 throw new IOException("error parsing result set");
389             }
390         }
391 
392         return cart;
393     }
394 
395     protected static MusicAlbum parseAlbum(Element root, Node album, int genre) {
396         String asin = xmlGet(album, "ecs:ASIN", root);
397         String group = 
398             xmlGet(album, "ecs:ItemAttributes/ecs:ProductGroup", root);
399         String title = xmlGet(album, "ecs:ItemAttributes/ecs:Title", root);
400         String artist = xmlGet(album, "ecs:ItemAttributes/ecs:Artist", root);
401         
402         int listPrice = 0;
403         String sPrice = 
404             xmlGet(album,"ecs:ItemAttributes/ecs:ListPrice/ecs:Amount", root);        
405         try {
406             listPrice = Integer.parseInt(sPrice);
407         } catch (NumberFormatException numEx) {
408             log.warn("error parsing list price " + sPrice);
409         }
410  
411         int rank = 0;
412         String sRank = xmlGet(album, "ecs:SalesRank", root);       
413         try {
414             Integer.parseInt(sRank);
415         } catch (NumberFormatException numEx) {
416             log.warn("error parsing rank " + sRank);
417         }
418 
419         Date relDate = null;
420         String sDate = "";
421         try {
422             sDate = xmlGet(album, "ecs:ItemAttributes/ecs:ReleaseDate", root);
423             relDate = MusicAlbum.DATE_FORMAT.parse(sDate);
424         } catch (ParseException e) {
425             log.warn("error parsing date: " + sDate);
426         }
427         
428         String label = xmlGet(album, "ecs:ItemAttributes/ecs:Label", root);
429         int genres[] = new int[] { genre };
430         
431         Image smallImage = null;
432         try {
433           Node imageNode = 
434               XPathAPI.selectSingleNode(album, "ecs:SmallImage", root);
435           smallImage = parseImage(root, imageNode);
436         } catch (TransformerException e) {
437             log.warn("error evaluating XPath: ecs:SmallImage" +  e);
438         }
439  
440         OfferSummary offerSummary = null;
441         try {
442           Node offerSummaryNode =
443               XPathAPI.selectSingleNode(album, "ecs:OfferSummary", root);
444           offerSummary = parseOfferSummary(root, offerSummaryNode); 
445         } catch (TransformerException e) {
446             log.warn("error evaluating XPath: ecs:OfferSummary" +  e);
447         }
448         
449         MusicAlbum ma = 
450             new MusicAlbum(asin, group, title, listPrice, artist,
451                 relDate, label, rank);
452         ma.setGenres(genres);
453         ma.setSmallImage(smallImage);
454         ma.setOfferSummary(offerSummary);
455         
456         return ma;
457     }
458 
459     protected static Image parseImage(Element root, Node imageNode) {
460         Image image = null;
461         try {
462             String imageURL = xmlGet(imageNode, "ecs:URL", root);
463             int height = 
464                 Integer.parseInt(xmlGet(imageNode, "ecs:Height", root));
465             int width = 
466                 Integer.parseInt(xmlGet(imageNode, "ecs:Width", root));
467             image = new Image(imageURL, height, width);
468         } catch (Exception e) {
469             log.warn("error parsing item's image");
470         }
471         
472         return image;
473     }
474     
475     protected static OfferSummary parseOfferSummary(Element root, Node offerSummary) {
476         int totalNew = 0;
477         String sTotalNew = xmlGet(offerSummary, "ecs:TotalNew", root);       
478         try {
479             totalNew = Integer.parseInt(sTotalNew);
480         } catch (NumberFormatException numEx) {
481             log.warn("error parsing total new offer " + sTotalNew);
482         }
483         
484         int totalUsed = 0;
485         String sTotalUsed = xmlGet(offerSummary, "ecs:TotalUsed", root);        
486         try {
487             totalUsed = Integer.parseInt(sTotalUsed);
488         } catch (NumberFormatException numEx) {
489             log.warn("error parsing total used offer " + sTotalUsed);
490         }
491         
492         int totalCollect = 0;
493         String sTotalCollect = xmlGet(offerSummary, "ecs:TotalCollectible", root);       
494         try {
495             totalCollect = Integer.parseInt(sTotalCollect);
496         } catch (NumberFormatException numEx) {
497             log.warn("error parsing total collectible offer " + sTotalCollect);
498         }
499 
500         int newPrice = 0;
501         if (totalNew > 0) {
502             String sNewPrice = 
503                 xmlGet(offerSummary, "ecs:LowestNewPrice/ecs:Amount", root);
504             try {
505                 newPrice = Integer.parseInt(sNewPrice);
506             } catch (NumberFormatException numEx) {
507                 log.warn("error parsing lowest new price " + sNewPrice);
508             }
509         }
510 
511         int usedPrice = 0;
512         if (totalUsed > 0) {
513             String sUsedPrice = 
514                 xmlGet(offerSummary, "ecs:LowestUsedPrice/ecs:Amount", root);       
515             try {
516                 usedPrice = Integer.parseInt(sUsedPrice);
517             } catch (NumberFormatException numEx) {
518                 log.warn("error parsing lowest ued price " + sUsedPrice);
519             }
520         }
521         
522         int collectPrice = 0;
523         if (totalCollect > 0) {
524             String sCollectPrice = 
525                 xmlGet(offerSummary, "ecs:LowestCollectiblePrice/ecs:Amount", root);        
526             try {
527                 collectPrice = Integer.parseInt(sCollectPrice);
528             } catch (NumberFormatException numEx) {
529                 log.warn("error parsing lowest collectible price " + sCollectPrice);
530             }
531         }
532                 
533         return new OfferSummary(newPrice, usedPrice, collectPrice, 
534                                 totalNew, totalUsed, totalCollect);
535     }
536     
537     protected static CartItem parseCartItem(Element root, Node cartItem) {
538         String cartItemId = xmlGet(cartItem, "ecs:CartItemId", root);
539         String asin = xmlGet(cartItem, "ecs:ASIN", root);
540         String merchantId = xmlGet(cartItem, "ecs:MerchantId", root);
541         int quantity = Integer.parseInt(xmlGet(cartItem, "ecs:Quantity", root));
542         String title = xmlGet(cartItem, "ecs:Title", root);
543         String group = xmlGet(cartItem, "ecs:ProductGroup", root);
544         int listPrice = Integer.parseInt(xmlGet(cartItem,
545                 "ecs:Price/ecs:Amount", root));
546 
547         CartItem item = new CartItem(cartItemId, asin, merchantId, quantity,
548                 title, group, listPrice);
549         return item;
550     }
551 
552     protected static final String xmlGet(Node node, String xpath, Node xmlnsNode) {
553         String rslt = "";
554         try {
555             rslt = xGetVal(XPathAPI.selectSingleNode(node, xpath, xmlnsNode));
556         } catch (TransformerException e) {
557             log.warn("error evaluating XPath: " + xpath, e);
558         }
559         return rslt;
560     }
561 
562 }