|
SYS-CON.TV Webcasts
Comments
Did you read today's front page stories & breaking news?
SYS-CON.TV
|
Top Links You Must Click On
General Java Creating Newsfeeds Using Java Applets
Creating Newsfeeds Using Java Applets
By: John Keogh
Oct. 1, 1999 12:00 AM
The conventional way to present up-to-date information is to keep it on your Web site or a Web site you have some access to or control over so you can modify the information as needed. This article describes a way to create newsfeeds using Java applets so that the applet can be embedded anywhere in any page, and the applet distributor can keep the presented information up to date by modifying information on the site. Ways to extend the ability of the applet using CGI programming are also examined. This solves problems for theaters, clubs and other organizations that want their information on many pages but want to maintain it in just one spot. Establishments that want to distribute information about sales and events, and, of course, news organizations, can also benefit from distributing newsfeeds. This article also discusses a way to ensure that the information isn't loaded from cache (anticaching). Conceptually, this applet connects back to the server and retrieves information - from a flat file or a script - as a stream of bytes that are cast to chars and appended to a StringBuffer. The toString() method in StringBuffer is called, and the resulting string is parsed to create a Vector containing the news and any other information returned by the server. When you want to use the applet as a newsfeed, you can permit other sites to embed the applet in their pages (using the CODEBASE="URL" attribute, with the URL being the directory on your server where the class files are, just as you can embed an image loaded from another server in another page, as shown in Figure 1). The applet then connects back to the server from which it was downloaded and gets the information, irrespective of the page in which it's embedded.
The Code
The included packages and classes are needed for painting (awt.*), storing information in a vector (Vector), parsing the information returned from the server (StringTokenizer), networking (net.*), input/output classes and required exceptions (io.*), and working with dates (Date). The integer variables that have global scope within the class -speed, iHeight, iTimesThrough and iCurrentPosition -store the speed of the thread and the font height and keep track of the number of times the retrieved news has been presented and the current position in the list of news items. The initial value of iTimesThrough, 11, is explained in the paint() method. The Thread variable, called newsthread, is used to implement the Runnable interface. An Image object is used for the background image. The String objects - strCurrentString and strCurrentURL - are used to store the current news item and the associated URL. The boolean bCalledFromRun, if true, increments iCurrentPosition when paint() is called. The Vector veInformation is used to contain the news items retrieved from the server. The class extends Applet and can be run either in a browser or in AppletViewer. Implementing Runnable permits the class to spawn and run in its own thread. To implement the Runnable interface, we need to implement start(), stop(), and run() methods (discussed below). Unlike most applets, newsfeed doesn't override init(); all the initialization is done in the initialize() method. This method is called from paint() the first time that paint() is called and every 10 times thereafter to refresh the news. The initialize() method is the key method of the applet. The Date object that's created is used to get the current time in milliseconds (stored in lUnique), which is used to circumvent caching (anticaching is discussed later in this article). The passed-in graphics object is used to draw a string indicating that the news is being downloaded and to get the font metrics, from which the font height is determined and stored in iHeight. The strType variable stores the type of news that's going to be requested. This information is used only if a script will process the request. Setting iCurrentPosition and strCurrentURL variables to 0 and ".", respectively, clears them. Listings 1 contains five examples of URLs that can be read from. If you're experimenting with the applet using AppletViewer, you'd include the file called news.txt in the same directory as the applet (the file format of the news file is discussed later) and then run the applet in AppletViewer. Remember, when running in a browser, an applet can generally connect back only to the server from which it was downloaded. The URL string to use depends on whether you're using a flat file or a script, and the sophistication of the script. If you're using a flat file, you'd use "/news/news.txt". The applet gets the host name using getCodeBase().getHost() and creates a URL with the returned host and the path "/news/news.txt". If the applet was downloaded from www.lithic.com and you used the path "/news/news.txt", the URL would be http://www.lithic.com/news/news.txt. The "?"+lUnique circumvents caching. You can, of course, use other paths and file names, but the file must be a publicly accessible ASCII file in the correct format. The last three examples of URL are scripts, discussed later in this article. One problem in retrieving the current news is that the requested URL may be loaded from cache. This can be overcome by creating a unique URL each time, which can be done by including a unique number in the query string. One way to accomplish this is to include the current time in the query string. If the time between queries is greater than the resolution of the system clock, this should overcome the caching problem. Using a Date to get the current time in milliseconds and appending it to the query strings of the script URLs is an effective anticaching strategy. The same strategy can be used with URLs that are not scripts, because they generally ignore the query string (an HTTP server will generally serve the same page if you type in index.html or index.html?123). The key thing is to present the browser with a URL that is unique so it won't find it in cache. After the URL object is instantiated, openStream() is called, which returns an InputStream for reading from that connection. The InputStream object is used to instantiate a DataInputStream, which we read from until we reach the end of file, represented by an EOFException. The bytes returned from the DataInputStream are cast to chars, then appended to a StringBuffer. The string representing the contents of the URL is recovered by using the toString() method in StringBuffer. This is a general-purpose method for creating a string from the content of a URL - if you try this using (String)url.getContent(), you may get a ClassCastException. The vectorize() method takes the retrieved String and a token String as arguments and returns a Vector containing the news. In the information retrieved from the file or script, we expect the zeroth line - which becomes the zeroth node in veInformation - to be the name of an image stored in the codebase. After this image name is stored in strImage, the zeroth is removed, leaving as many nodes in the Vector as there are news items. After the image is loaded, the variable that tracks the number of times the new items have been presented is set to 0. To simplify working with the information returned from the server, the vectorize() method creates a Vector from it. The two parameters passed in are the String to parse and the String on which to tokenize it. If the String to parse ended with the token used to parse, we'd end up with a final piece of zero length. To avoid this, if the string ends with the parse character, it's pulled off. Because most files or streams of bytes sent via a server are punctuated by a <cr><lf>, both are checked for and removed if they end the strIn. Most of the work is done using a stringTokenizer. After a Vector is instantiated, the stringTokenizer is instantiated with the string to parse on and the string to parse. In our model the string to parse on is always a new line, but passing in the string to parse on makes the method more flexible. The code then tokenizes the string, adding each token to the Vector. The code that handles tokenizing by "\n" checks to see if a \r or \n is present and pulls them off the end of each token (they're assumed to be on the end; if your code needs these characters for anything, you may need to modify this code). The Vector is then trimmed to size and returned. The paint() method, which is called repeatedly from run(), is used as the engine of this applet. The size of the applet is determined first, to be used to clear the applet's graphics context. If this is the first time through (iTimesthrough variable is initially set to 11, so initialize() will be called the first time through paint()), or if the number of times the news has been presented exceeds some arbitrary number of times (here 10), the news is refreshed using the initialize() method. If an image is available, it's drawn on the background. The text is offset 45 pixels to be to the left of the image (it could also be drawn on top of the image). The examples in Figures 2 and 3 are just names for a company or club, but in practice they could be an advertisement or something associated with the news item. The image name is downloaded with the news, so it can be changed with each refresh. Each line of news is in two parts: the URL is everything up to the first space, and the news item is everything after. After the current line of news is retrieved, the iCurrentPosition variable is incremented if bCalledFromRun is true. Initially the paint method is called repeatedly as the background image is drawn. To prevent an initial race through the news, the current position increments only if the paint() method was called from run(). New news is then drawn, in blue, 45 pixels from the left side of the applet and iHeight down (the iHeight variable was set to the font height in the initialize() method). Checking on whether the iCurrentPosition variable is bigger than veInformation, the Vector, which holds all the news items, permits the news to "wrap" back to the first news item if the current news item is the last. The iTimesThrough variable is incremented if the news wrapped, tracking the number of times that the current news has been displayed. The mouseDown(), mouseEnter() and mouseExit() methods work together to create a mouse interface for the applet. In mouseDown(), if the current URL (set in paint()) isn't a ".", a URL object is instantiated and passed to the showDocument() method in the applet context for this applet. Using a "." permits presenting news items for which there is no link. The mouseEnter() method draws the current news item in red and shows the link in the status bar with showStatus(), both of which are common in applets that show menus or image maps. The thread is stopped in mouseEnter() so the current news item will remain displayed. The mouseExit() method undoes what the mouseEnter() method did by converting the text color back to blue, clearing the status and then starting the thread again. The start(), stop() and run() methods are used to implement the runnable interface. A Thread object called newsthread is instantiated and started in the start() method. The run() method is called repeatedly, and the thread is paused for speed milliseconds; then repaint() is called. The stop() method is called when the applet stops. To update the news in real time, just upload a new flat file or change the data in the database if you're using a database with a script. Flat files can also be changed by using CGI scripts that allow an authenticated user to modify, delete or add to the contents of the flat file. The next time the applet accesses the flat file or script, it'll get the current information (sometimes flat files are cached by the server, but in our experience this hasn't been a problem).
Working with CGI Scripts vs Flat Files
line1: Image<optional \r><\n > Any data source that can supply text in this format can act as a data source for the newsfeed. In practice, the designer would probably choose something with more flexibility and capability, but this works fine for our example. In any case, if you use a flat file, remember to upload it using ASCII mode. The news.txt file has information in the format above, so it can be parsed directly by the applet. The information in cginews.txt must be supplied to the applet via newsfeed.pl, a Perl script. If you use the script and the cginews.txt, be sure that the permission of the script is executable, the path to the Perl interpreter is correct and the cginews.txt is world readable. Note that \n is read from the cginews.txt file; if the terminal character on each line is not a \n , the information won't parse correctly when it's received by the applet. (Perl programming is beyond the scope of this article, but if you have some experience, these scripts should be a starting point. If not, the flat file can provide most of the same functionality.) The Perl script newsfeed.pl first retrieves the query string (this is what's after the "?"). If the URL accessed was http://www.lithic.com/cgi-local/newsfeed.pl?ls930353830, the query string would be ls930353830. The numbers after the Is represent the anticaching strategy discussed above. The first two characters are passed to the PrintNews function, which prints characters 2 through the last character of every line in the cginews.txt file that start with these two letters. In the example case the two letters are "ls". The first two characters of each line, which are the code compared to the type passed in, are removed before the line is printed. Using a code permits a single applet with a single data source to supply different news depending on the query string. This could be combined with cookies on the page the applet was embedded in, so user preferences could dictate what news was sent. A guardian is set so that if no lines were printed for a given two-letter combination, a "." and a line indicating there was no news would be printed out. Modifications to the Perl script and minor modifications to the applet would permit a more sophisticated interaction with the user. For example, if the URL http://www.lithic,com/cgi-local/moresubstantialnewsfeed.pl?type=Is&docbase=[doc base]&time=[time] were constructed and opened, where [doc base] and [time] are understood to be the page that the applet is embedded in and the current time, and the information was parsed by the script, the type and codebase would be known (knowing the codebase would permit returning an appropriate message to unauthorized newsfeeds, rather than the news). The time is still used for anticaching, but it may also be interesting statistically.
Conclusion
This implementation of a newsfeed, though limited, created a very small class file that displays news, responds to button clicks when there is a link associated with a news event, and circumvents caching. Many improvements are possible: adding more colors, offsets, speed, audio clips and so forth. Additionally, double buffering would offer smoother graphics. The applet offers a functional framework in a small package. Using a newsfeed solves many of the problems associated with the static nature of Web pages and solves access issues. For example, a document on a CD-ROM could present current information (provided that the person reading the HTML document in which the newsfeed was embedded was attached to the Internet). Used correctly, newsfeeds based on the applet described in this article can be a way to make the net more relevant, provide better service to your customers and substantially decrease the time it takes to disseminate information. Reader Feedback: Page 1 of 1
Enterprise Open Source Magazine Latest Stories . . .
Subscribe to the World's Most Powerful Newsletters
Subscribe to Our Rss Feeds & Get Your SYS-CON News Live!
|
SYS-CON Featured Whitepapers
Most Read This Week |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||