/* * DataLoader.java 1.3 04/06/98 * * Copyright (c) 1997, 1998 by Kevin Swan. All rights reserved. * * I reserve all rights to this software. You may use it and * distribute it freely, provided you do not remove this header * and attribute partial credit to the author, Kevin Swan. * * 14 Apr 1998 Created. * Released as version 1.0. * 20 Apr 1998 Added the refreshing ability. * Increased its responsibilities to include text * wrapping. Now, all data returned from the * DataLoader will be already line wrapped. * Released as version 1.1. * 21 Apr 1998 Corrected a bug in the Thread management. * Expanded variable documentation, added DELAY constant * Released as version 1.2. * 04 Jun 1998 Added ability to specify not to apply line wrapping. * Added constructor * public DataLoader (URL, Font, int width, boolean) * The default is that it will wrap text. If the * new constructor is used with a boolean argument of * false, then no line wrapping is applied. * Released as version 1.3. */ /* * Commented out for unbundled distribution. * * package kevin.applets.textscroll; */ import java.net.URL; import java.awt.Font; import java.net.URLConnection; import java.io.DataInputStream; import java.io.IOException; import java.util.Vector; /** * This class is used to load the text data for TextScroll in an * asynchronous way. It will also apply the automatic line wrapping * to the data. It provides a refresh() method which * can be used to force this DataLoader to reload * the data from the URL it was given when it was constructed. * * @version 1.3, 04 Jun 1998 * @author Kevin Swan, 013639s@dragon.acadiau.ca */ public class DataLoader implements Runnable { /** * The current version of this class. */ public static final String VERSION = "1.3"; /** * This is how long the thread should sleep when waiting * for a refresh() request or a stop() * request. Default is half a second. */ private static final int DELAY = 500; /** The thread of execution. This allows it to run asynchronously. */ private Thread thread = null; /** The URL to load the data from. */ private URL url = null; /** The array to store the data in. */ private String[] textData = null; /** Variable used to flag if the data is ready or not. */ private boolean dataReady = false; /** Variable used to flag if an error occurred. */ private boolean errorOccurred = false; /** * Variable used to indicate that this DataLoader * should reload the data from the URL it was given in the * constructor. */ private boolean shouldRefresh = true; /** * Variable used to indicate that this DataLoader * should apply line wrapping to the text after it is loaded * before delivering it to the caller. */ private boolean shouldWrap; /** * Variable used to flag when the DataLoader should terminate * its thread. */ private boolean isAlive = false; /** The starting font to use when applying line wrapping. */ private Font startingFont; /** The width to assume when applying line wrapping. */ private int width; /** * Constructor. It expects the URL of the data file to load from. * The constructed DataLoader will apply line * wrapping to the retrieved data. * * @param url The URL to load the data from. * @param startingFont The starting Font, used for line wrapping. * @param width The width of the starting font, use for line * wrapping. */ public DataLoader (URL url, Font startingFont, int width) { this (url, startingFont, width, true); } /** * Constructor. It expects the URL of the data file to load from. * It returns immediately. * * @param url The URL to load the data from. * @param startingFont The starting Font, used for line wrapping. * @param width The width of the starting font, use for line * wrapping. * @param shouldWrap A boolean indicating whether or not this * DataLoader should apply line * wrapping or not. */ public DataLoader (URL url, Font startingFont, int width, boolean shouldWrap) { this.url = url; this.dataReady = false; this.shouldRefresh = true; this.shouldWrap = shouldWrap; this.errorOccurred = false; this.startingFont = startingFont; this.width = width; this.isAlive = true; this.thread = new Thread (this); this.thread.start (); } /** * This method is called to reload the data from the URL. It returns * immediately. It performs automatic line wrapping based on the * width and Font given in the constructor. */ public void refresh () { this.shouldRefresh = true; } /** * This method actually loads the data. It sets the internal flags * appropriately, such that calls to dataReady() and * errorOccurred will always return correct information. */ public void run () { outer: while (isAlive) { while (!shouldRefresh) { try { this.thread.sleep (DataLoader.DELAY); if (!isAlive) { break outer; } } catch (InterruptedException ie) { isAlive = false; break outer; } } URLConnection dataConnection = null; DataInputStream dis = null; try { dataConnection = this.url.openConnection (); } catch (IOException ioe) { this.errorOccurred = true; return; } try { dis = new DataInputStream (dataConnection.getInputStream ()); } catch (IOException ioe) { this.errorOccurred = true; return; } String line = null; Vector data = new Vector (); int index; while (true) { try { line = dis.readLine (); } catch (IOException ioe) { this.errorOccurred = true; return; } if (line == null) break; data.addElement (line + "\n"); } /* while */ this.textData = new String[data.size ()]; for (int i = 0 ; i < data.size () ; i++) this.textData[i] = new String ((String) data.elementAt (i)); try { dis.close (); } catch (IOException ioe) { System.err.println ("IOException closing DataInputStream on text data."); /* At this point, we can keep going. Consider this non-fatal. */ } /* Apply line wrapping, if we should. */ if (this.shouldWrap) { LineWrapManager wrapManager = new LineWrapManager (this.textData, this.startingFont); String[] tmpArr = wrapManager.wrapForWidth (this.width); this.textData = new String [tmpArr.length]; System.arraycopy (tmpArr, 0, this.textData, 0, tmpArr.length); } /* Finally, get rid of any newlines that made it past the line wrapper. */ for (int i = 0 ; i < this.textData.length ; i++) this.textData [i] = this.textData [i].trim (); this.dataReady = true; this.shouldRefresh = false; } } /* run () */ /** * Method called to terminate the Thread. */ public void stop () { this.isAlive = false; } /** * Method called when the thread is started. */ public void start () { if (this.isAlive) return; this.isAlive = true; this.thread = new Thread (this); this.thread.start (); } /** * Method for determining when the data has arrived. * * @return true if the data is ready, false * otherwise. */ public boolean dataReady () { return this.dataReady; } /** * Method for determining if an error has occurred. * * @return true if an error occurred, and the data is never * going to arrive, false if no error has occurred. */ public boolean errorOccurred () { return this.errorOccurred; } /** * Method for getting the actual data. If it hasn't arrived yet, this * method returns null. * * @return The array of Strings which are the data, if it * is here, or null if it is still loading or if an * error occurred. */ public String[] getData () { if (!this.dataReady () || this.errorOccurred ()) return null; else return textData; } }