As shown in Figure 9-1, you can see the results of running the application and adding a few CDs.
To add a new CD, simply insert a CD into the drive, and click the Add CD button. The application then reads the inserted CD, uses the native library to calculate the fingerprint for the CD, retrieves the information on the CD from freedb.org, and uses that information to load the image and pricing information from Amazon. It's easy to imagine a DJ loading in favorite CDs and posting a list of recommended disks, complete with links back to Amazon.
The JSP code for the interface, as shown in Example 9-1, is mainly concerned with retrieving the CD data from our Java code and formatting it in HTML. The small bit of logic at the top of the listing checks to see if the form submission button has been clicked by the user. If so, it calls a static method of a Java class to begin processing the newly inserted audio CD.
<%@ page contentType="text/html; charset=iso-8859-1" language="java" import="com.cascadetg.ch09.*" %> <% if(request.getParameter("Submit") != null) { CDManager.addCD( ); } %> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>CD List</title> <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" /> <link href="../ch04/www/default.css" rel="stylesheet" type="text/css" /> </head> <body> <% Object[] cds; cds = CDManager.getCDs( ).values( ).toArray( ); %><form name="form1" method="post" action=""> <table width="100%" border="0" cellpadding="0" cellspacing="0"> <tr valign="center"><td><strong>CD Collection List Value : $<%= CDManager.getListValue( ) %></strong></td> <td align="right" valign="center"> <input type="submit" name="Submit" value="Add CD" /></td></tr> <tr><td colspan="2"><hr /></td></tr></table></form> <% for(int i = 0; i < cds.length; i++) { CD current = (CD)cds[i];%> <table width="300"> <tr> <td align="center" width="140"><% if(current.amazonDetails != null) { %><img src="<%= current. amazonDetails.getImageUrlMedium( )%>"> <% } else { %><I>No Image</I><% } %></td> <% if(current.cddbDetails != null) { %> <td><b><%= current.cddbDetails.readArtist( )%></b><br> <%= current.cddbDetails.readCDTitle( )%><br> <%= current.cddbDetails.readGenre( )%><br> Tracks: <%= current.cddbDetails.readNumberOfTracks( )%><br> Released: <%= current.cddbDetails.readYear( )%><br><% } %> <% if(current.amazonDetails != null) { %>List Price: <%= current.amazonDetails.getListPrice( )%><br> <a href="<%= current.getAmazonLink( )%>" target="_blank">Amazon Page</a></td><% } %> </tr> </table><% } %> </body> </html>
The supporting Java class, shown in Example 9-2, serves as a data holder for the information returned from the Amazon web service (in particular, the image information) and the CDDB information. The Details object holds data returned by the Amazon web service. CDID is a com.antelmann class that holds the unique fingerprint of the CD, and the CDDBXmcdParser object holds the record data returned by the CDDB request. Finally, there's a utility method provided that creates a link back to Amazon based on the product ID returned by the Amazon web service.
package com.cascadetg.ch09; import com.amazon.soap.Details; import com.antelmann.cddb.CDDBXmcdParser; import com.antelmann.cddb.CDID; import com.cascadetg.ch04.DeveloperTokens; public class CD { public Details amazonDetails; public CDDBXmcdParser cddbDetails; public CDID cdID; public String getAmazonLink( ) { return "http://www.amazon.com/exec/obidos/ASIN/" + amazonDetails.getAsin( ) + "/" + DeveloperTokens.amazon_associates + "?creative=125581&camp=2321&link_code=as1"; } }
The real heart of the application can be found in Example 9-3. The JSP from Example 9-1 only used two static methods, both of which are fairly self-descriptive?addCD( ) and getCDs( ). Both are detailed in this class listing. The addCD( ) method kicks off a request to CDDB using the com.antelmann classes. After the results come back, an attempt is made to use the resulting information to look up the results from Amazon based on the artist and CD title.
|
package com.cascadetg.ch09; import com.amazon.soap.*; import com.cascadetg.ch04.*; import java.util.Enumeration; import java.util.Hashtable; public class CDManager { /** Connect to the FreeCDDB using the Antelmann library. */ public static void addCDDBInfo(CD newCD) { /* * Running in the Tomcat contain confuses the library about * where to load the properties configuration file. Therefore, * we'll just create a set of properties and feed them into the * library here. */ java.util.Properties newProperties = new java.util.Properties( ); newProperties.setProperty( "application.vendor.email", "info@antelmann.com"); newProperties.setProperty( "application.startCommand", "cmd.exe /c start %1"); newProperties.setProperty( "user.dir.media", "c\\:\\\\stuff\\\\media"); newProperties.setProperty( "cddb.client", "AntelmannJavaCDDBReader"); newProperties.setProperty( "cddb.local.dir", "c\\:\\\\stuff\\\\misc\\\\cddb"); newProperties.setProperty("cddb.client.version", "0.4.0"); com.antelmann.util.Settings.init(newProperties); try { /* * This is where we use the Windows-specific native code to * read the CD information. To run this on other platforms * (e.g. Linux or Mac OS X) we'd need to provide a new * implementation of this. */ com.antelmann.cddb.CDDriveWin myDrive = new com.antelmann.cddb.CDDriveWin( ); /* Given the drive, we get the CD identification. */ newCD.cdID = new com.antelmann.cddb.CDID(myDrive); /* * Next, we use the default FreeDB server to connect and * query for the available records. */ com.antelmann.cddb.FreeDB myDB = new com.antelmann.cddb.FreeDB( ); com.antelmann.cddb.CDDBRecord[] myRecords = myDB.queryCD(newCD.cdID); /* * For our purposes, we'll just accept the first record * that is returned and assume that it matches the inserted * CD. */ com.antelmann.cddb.CDInfo myCDInfo = myDB.readCDInfo(myRecords[0]); /* * Now, we stuff the data using the standard parser into * the CD object. */ newCD.cddbDetails = new com.antelmann.cddb.CDDBXmcdParser( myCDInfo.getXmcdContent( )); } catch (Exception e) { e.printStackTrace( ); } } public static void addAmazon(CD newCD) { try { AmazonSearchService myAmazonSearchService = new AmazonSearchServiceLocator( ); AmazonSearchPort myAmazonSearchPort = myAmazonSearchService.getAmazonSearchPort( ); ArtistRequest myArtistRequest = new ArtistRequest( ); // Use this to set your Amazon Associates ID // For more info on Amazon Associates, see... // http://www.amazon.com/associates myArtistRequest.setTag(DeveloperTokens.amazon_associates); myArtistRequest.setDevtag(DeveloperTokens.amazon_token); // Here, we pass in the Artist as read by the CDDB results. myArtistRequest.setArtist(newCD.cddbDetails.readArtist( )); myArtistRequest.setLocale("us"); myArtistRequest.setType("heavy"); ProductInfo myProductInfo = myAmazonSearchPort.artistSearchRequest(myArtistRequest); // All we have to do now is loop through the Amazon // results, looking for a title that matches. Details[] myDetailsArray = myProductInfo.getDetails( ); Details myDetail = null; for (int i = 0; i < myDetailsArray.length; i++) if (myDetailsArray != null) { myDetail = myDetailsArray[i]; if (myDetail .getProductName( ) .compareToIgnoreCase( newCD.cddbDetails.readCDTitle( )) == 0) newCD.amazonDetails = myDetail; } } catch (Exception e) { e.printStackTrace( ); } } public static CD addCD( ) { CD newCD = new CD( ); addCDDBInfo(newCD); addAmazon(newCD); cdList.put(newCD.cdID.getDiscID( ), newCD); return newCD; } private static Hashtable cdList = new Hashtable( ); /** * An example of how the loaded data can be useful - here we loop * through the returned Amazon results, looking for the list price. * We add the results to a single total. */ public static String getListValue( ) { float value = 0; Enumeration list = cdList.keys( ); while (list.hasMoreElements( )) { CD current = (CD)cdList.get(list.nextElement( )); if (current.amazonDetails != null) if (current.amazonDetails.getListPrice( ) != null) { String valueString = current.amazonDetails.getListPrice( ); valueString = valueString.substring(1, valueString.length( )); value = value + Float.parseFloat(valueString); } } return Float.toString(value); } public static java.util.Map getCDs( ) { java.util.TreeMap map = new java.util.TreeMap(java.text.Collator.getInstance( )); Enumeration loop = cdList.keys( ); while (loop.hasMoreElements( )) { String key = (String)loop.nextElement( ); if (((CD)cdList.get(key)).cddbDetails != null) map.put( ((CD)cdList.get(key)).cddbDetails.readArtist( ), cdList.get(key)); } return map; } public static CD getCD(String id) { return (CD)cdList.get(id); } public static void main(String[] args) { CD myCD = addCD( ); System.out.println(myCD.cddbDetails.readArtist( )); System.out.println(myCD.amazonDetails.getAsin( )); System.out.println(myCD.getAmazonLink( )); System.out.println(myCD.amazonDetails.getImageUrlLarge( )); System.out.println(myCD.amazonDetails.getImageUrlMedium( )); System.out.println(myCD.amazonDetails.getImageUrlSmall( )); System.out.println(getListValue( )); } }
It's worth taking a moment to think about how much easier this was to accomplish by leveraging the com.antelmann classes rather than developing a custom library to access the CDDB data. Previous chapters have already shown interaction with FedEx, eBay, and PayPal, and the CDDB1 protocol is in some ways even more complex (not counting the native code needed to access the CD drive). We're lucky enough to be using a fairly popular programming language (Java). Imagine if you were interested in using the system using a nonmainstream language; you'd be forced to write a lot of code the Antelmann classes already provide for Java.
It's likely that if the designers of the CDDB set up the service today, they'd use a system closer to the WSDL plus SOAP methodology (or even XML-RPC). These systems make it much easier to generate the bridge glue (akin to the bulk of the com.antelmann.* classes) for individual programming languages. The other complexity?that of the native code needed to access the CD drive?is one that lies beyond the realm of web services.
This is one more look at a web-service solution, provided this time by combining an existing library, a somewhat archaic protocol, and a modern SOAP interface to Amazon. A similar application might involve using a bar-code scanner to retrieve UPC codes and get competitive data from one or more web sites. Another example might use UPC code to instantly generate a used-item listing on eBay.