In this case, a standalone application with a standard main() method will talk to Google and make the posts. All that is needed to run the application is to launch the main class, com.cascadetg.ch11.PostGenerator, with no arguments.
As shown in the code starting with Example 11-1, the built-in Java facility for timers (java.util.Timer) generates the posts on a regular schedule. The main loop just sits idle. It's easy to imagine incorporating this application into another application, such as a desktop client weblog application.
Example 11-1's application uses the Amazon web service connectivity as shown in Chapter 4, as well a single utility method (NewsSheet.replaceToken()) from Chapter 11.
package com.cascadetg.ch11; import java.util.Date; import java.util.Hashtable; import java.util.Timer; import com.google.soap.search.*; import com.cascadetg.ch04.DeveloperTokens; import com.cascadetg.ch10.NewsSheet; public class PostGenerator extends java.util.TimerTask { /** * These constants are used to describe the frequency at which * posts should be made */ static final long MINUTE = 60L * 1000L; static final long HOUR = 60L * 60L * 1000L; static final long DAY = 24L * 60L * 60L * 1000L; static final long WEEK = 7L * 24L * 60L * 60L * 1000L; /** * The defined frequency. For a "real" system, you'd likely want to * set this to DAY - MINUTE is only appropriate for debugging (and * some vendors have implemented policies that won't allow for * sustained posts at this frequency. */ long frequency = MINUTE; /** * This Hashtable is used to store the list of URLs that we have * retrieved from Google and (at least tried) to post. In the real * world, you'd want to persist this to a database. */ Hashtable postedStories = new Hashtable( ); /** * This is the search term we'll be sending to Google as the basis * for our posts. */ String search_term; /** This is used to specify the weblog we will be posting to. */ WeblogDriverInterface weblog; public static void main(String[] args) { PostGenerator myPoster = new PostGenerator( ); // This is where we choose which weblog we will be posting to. myPoster.setWeblog(new LiveJournalDriver( )); // myPoster.setWeblog(new BloggerDriver( )); myPoster.setSearchTerm("Java XML"); myPoster.init( ); // This is just a dummy loop which allows the program to run // for a while before exiting. boolean done = false; while (!done) { try { Thread.sleep(1000L * 10L); } catch (Exception e) { e.printStackTrace( ); } } System.out.println("Program complete."); }
The retrieval of data from Google's search web service is performed by the getGoogleResults() method in Example 11-2. The returned data is formatted into a human-readable post (with some light HTML formatting) in the getGoogleStory( ) method. You may wish to provide some additional logic for your own site; for example, you might write five different bits of text introducing the search results and rotate between them to keep the site fresh.
/** Uses the Google web service interface to get the search results */ GoogleSearchResultElement[] getGoogleResults( ) { GoogleSearch search = new GoogleSearch( ); // Set mandatory attributes search.setKey(DeveloperTokens.googleKey); search.setQueryString(search_term); // Set optional attributes search.setSafeSearch(true); // Invoke the actual search GoogleSearchResult result = null; try { result = search.doSearch( ); } catch (GoogleSearchFault e) { e.printStackTrace( ); } GoogleSearchResultElement[] mySearchElements = result.getResultElements( ); return mySearchElements; } /** * Gets the search results, loops through them, finds a result that * hasn't been posted yet, formats, and then returns the discussion * text as a single formatted HTML string. */ String getGoogleStory( ) { StringBuffer post = new StringBuffer( ); GoogleSearchResultElement[] mySearchElements = getGoogleResults( ); for (int i = 0; i < mySearchElements.length; i++) { if (!postedStories .containsKey(mySearchElements[i].getURL( ))) { post.append("As of "); post.append(new Date( ).toLocaleString( )); post.append(" Google thinks that "); post.append(" <a href='"); post.append(mySearchElements[i].getURL( )); post.append("' target='_blank'>this website"); post.append("</a> on '"); post.append(mySearchElements[i].getTitle( )); post.append("' is a relevant to "); post.append(search_term); post.append(". <BR /><BR /><I>"); post.append(mySearchElements[i].getSummary( )); post.append(" "); post.append( NewsSheet.replaceToken( mySearchElements[i].getSnippet( ), "<br>", " ")); post.append("</I><BR /><BR /> What do you think?"); postedStories.put( mySearchElements[i].getURL( ), new java.util.Date( )); return post.toString( ); } } String defaultString = "It would seem that Google can't find " + "anything new on the topic " + search_term + ". Why do you think that is?"; return defaultString; }
As shown in Example 11-3, the code for generating the post generates them at regular intervals. A simple java.util.Timer invokes the task and thereby generates a post on a regular frequency. The remainder of the class is concerned with bookkeeping.
/** * This method takes the formatted text from the Google search and * then generates a post. */ public void makePost( ) { String postText = getGoogleStory( ); java.util.Date now = new Date( ); weblog.setPost(postText); weblog.setTitle( "Discussion Topic for " + (now.getMonth( ) + 1) + "/" + now.getDate( )); if (!weblog.post( )) { System.out.println("Unable to make post."); } else { System.out.println("Post made."); } } /** Sets up the timer for this object. */ public synchronized void init( ) { Timer myTimer = new Timer(true); myTimer.schedule(this, 0, frequency); } /** * The required method by the Timer interface. This method is * triggered as indicated by the Timer thread. */ public void run( ) { System.out.print( new java.util.Date( ).toString( ) + " refreshing..."); makePost( ); System.out.println("Done"); } // The remainder of this class is the usual JavaBean // getters/setters. public WeblogDriverInterface getWeblog( ) { return weblog; } public void setWeblog(WeblogDriverInterface weblog) { this.weblog = weblog; } public void setSearchTerm(String search) { search_term = search; } public String getSearchTerm( ) { return search_term; } }
The code shown in Example 11-4 shows how a weblog is presented to the post generation class. Two standard JavaBean-style properties set the post title and content, and a single post( ) method submits the post to the weblog.
package com.cascadetg.ch11; public interface WeblogDriverInterface { String getPost( ); void setPost(String post); String getTitle( ); void setTitle(String title); /** Return true if the post is successful, false if not */ boolean post( ); }