/* RJA 2000 January 23 modified for new data format 1998 September 06 this code taken from Apple Applet Runner Bar Chart example applet, plus some code from the Que book _Using Java, Special Edition_ (1996) */ /* * @(#)Chart.java 1.4 97/02/05 * * Copyright (c) 1994-1997 Sun Microsystems, Inc. All Rights Reserved. * * Sun grants you ("Licensee") a non-exclusive, royalty free, license to use, * modify and redistribute this software in source and binary code form, * provided that i) this copyright notice and license appear on all copies of * the software; and ii) Licensee does not utilize the software in a manner * which is disparaging to Sun. * * This software is provided "AS IS," without a warranty of any kind. ALL * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING ANY * IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR * NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS SHALL NOT BE * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING * OR DISTRIBUTING THE SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS * LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, * INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER * CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF * OR INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE * POSSIBILITY OF SUCH DAMAGES. * * This software is not designed or intended for use in on-line control of * aircraft, air traffic, aircraft navigation or aircraft communications; or in * the design, construction, operation or maintenance of any nuclear * facility. Licensee represents and warrants that it will not use or * redistribute the Software for such purposes. */ import java.awt.Graphics; import java.awt.Color; import java.awt.Font; import java.awt.FontMetrics; import java.io.*; import java.lang.*; import java.net.URL; // RJA added import java.net.MalformedURLException; import java.net.UnknownServiceException; public class MyWebVisitStatsChart extends java.applet.Applet implements Runnable { static final int VERTICAL = 0; static final int HORIZONTAL = 1; static final int SOLID = 0; static final int STRIPED = 1; int orientation; String title; Font titleFont; FontMetrics titleFontMetrics; int titleHeight = 15; int columns; int values[]; Object colors[]; Object labels[]; int styles[]; int scale = 10; // multiplier for bar size int maxLabelWidth = 0; int barWidth; int barSpacing = 10; int max = 0; // RJA added int myWIDTH; // will be read from params, then stays constant int myHEIGHT; // will be read from params, then stays constant // needed because Netscape doesn't like // getSize().width, getSize().height int mySHRINK; // divide the values by this value so they will // fit on the the screen; should be autocalculated final int DEFAULT_SHRINK = 4; final int DEFAULT_WIDTH = 500; final int DEFAULT_HEIGHT = 200; int max_paint = -1; // index of maximum value to paint // RJA add separate thread for continuous updating protected Thread urlEaterThread; URL[] webStatURL; /* *********** init ***************** */ // RJA this sets up the initial parameters public void init() { String paramString; titleFont = new java.awt.Font("Courier", Font.PLAIN, 10); titleFontMetrics = getFontMetrics(titleFont); title = getParameter("title"); if (title == null) { title = "Chart"; } paramString = getParameter("columns"); if (paramString == null) { columns = 5; } else { columns = Integer.parseInt(paramString); } System.out.println( "columns " + columns ); paramString = getParameter("scale"); if (paramString == null) { scale = 10; } else { scale = Integer.parseInt(paramString); } paramString = getParameter("orientation"); if (paramString == null) { orientation = VERTICAL; } else if (paramString.toLowerCase().equals("vertical")) { orientation = VERTICAL; } else if (paramString.toLowerCase().equals("horizontal")) { orientation = HORIZONTAL; } else { orientation = VERTICAL; } // RJA added size params paramString = getParameter("WIDTH"); if (paramString == null) { myWIDTH = DEFAULT_WIDTH; } else { myWIDTH = Integer.parseInt(paramString); } paramString = getParameter("HEIGHT"); if (paramString == null) { myHEIGHT = DEFAULT_HEIGHT; } else { myHEIGHT = Integer.parseInt(paramString); } paramString = getParameter("SHRINK"); if (paramString == null) { mySHRINK = DEFAULT_SHRINK; } else { mySHRINK = Integer.parseInt(paramString); } webStatURL = new URL[columns]; values = new int[columns]; colors = new Color[columns]; labels = new String[columns]; styles = new int[columns]; // RJA we can process all the styles and colors and stuff first for ( int i = 0; i < columns; i++) { // parse the bar style paramString = getParameter("C" + (i+1) + "_style"); if (paramString == null || paramString.toLowerCase().equals("solid")) { styles[i] = SOLID; } else if (paramString.toLowerCase().equals("striped")) { styles[i] = STRIPED; } else { styles[i] = SOLID; } // parse the color attribute for this column paramString = getParameter("C" + (i+1) + "_color"); if (paramString != null) { if (paramString.equals("red")) { colors[i] = Color.red; } else if (paramString.equals("green")) { colors[i] = Color.green; } else if (paramString.equals("blue")) { colors[i] = Color.blue; } else if (paramString.equals("pink")) { colors[i] = Color.pink; } else if (paramString.equals("orange")) { colors[i] = Color.orange; } else if (paramString.equals("magenta")) { colors[i] = Color.magenta; } else if (paramString.equals("cyan")) { colors[i] = Color.cyan; } else if (paramString.equals("white")) { colors[i] = Color.white; } else if (paramString.equals("yellow")) { colors[i] = Color.yellow; } else if (paramString.equals("gray")) { colors[i] = Color.gray; } else if (paramString.equals("darkGray")) { colors[i] = Color.darkGray; } else { colors[i] = Color.gray; } } else { colors[i] = Color.gray; } } // end for // RJA get data here /* RJA This is the format of the data returned Page Access Statistics

Number of visits to URLs that match URL

Yesterday: #

This month: #

Last month: # We want to provide an array of URLs to check. For each URL an array will hold the values for yesterday, this month, and last month. Then they will be plotted in a bar graph. Then these numbers will be displayed in a table. Currently the code just does a bar graph for last month's values */ // RJA this code based in part on _Using Java, Special Edition_ // Chapter 27 - Content Handlers, pp. 587-588 "Reading the InputStream" String baseURL; baseURL = getParameter("BASE_URL"); if (baseURL == null) { System.err.println("no base url!"); // do we need more error handling here? } for ( int i = 0; i < columns; i++ ) { System.out.println("in get url loop, i = " + i); paramString = getParameter("C" + (i+1) + "_URL"); if (paramString != null) { try { webStatURL[i] = new URL( baseURL + paramString ); // RJA we can do the labels first // RJA hack to remove base URL to make short label labels[i] = webStatURL[i].toString().substring(baseURL.length()); maxLabelWidth = Math.max(titleFontMetrics.stringWidth((String)(labels[i])), maxLabelWidth); } catch (MalformedURLException e) { System.err.println( "Caught Malformed URL Exception" ); // should die here } catch (Exception e) { System.err.println( "Caught exception: " + e.toString() ); // should die here } // RJA can't resize panel within browser switch (orientation) { case VERTICAL: default: barWidth = maxLabelWidth; //resize(Math.max(columns * (barWidth + barSpacing), // titleFontMetrics.stringWidth(title)) + // titleFont.getSize() + 5, // (max * scale) + (2 * titleFont.getSize()) + 5 + titleFont.getSize()); break; case HORIZONTAL: barWidth = titleFont.getSize(); //resize(Math.max((max * scale) + titleFontMetrics.stringWidth("" + max), // titleFontMetrics.stringWidth(title)) + maxLabelWidth + 5, // (columns * (barWidth + barSpacing)) + titleFont.getSize() + 10); break; } // end switch } else { System.err.println("no urls to process"); // should die here } // end if } // end for } // end init /* *** start ***/ public void start() { urlEaterThread = new Thread(this); urlEaterThread.start(); } /* *** stop *** */ public void stop() { urlEaterThread.stop(); urlEaterThread = null; } /* *** run *** */ // RJA this guy eats the URLs one by one and updates the display as it gets // each data value public void run() { Thread.currentThread().setPriority(Thread.NORM_PRIORITY); Object contentObject; InputStream pageContent; StringBuffer outStringBuffer; String outString; // outString will contain the full data returned // we want to parse out the numbers for yesterday, this month, and last month // (should be using arrays) String lastMonthString; int urlmatchindex; int lastmonthindex; int endbodyindex; int endhtmlindex; Integer[] lastMonthCount = new Integer[columns]; int inputByte; // RJA this is the slow part for ( int i = 0; i < columns; i++ ) { try { contentObject = webStatURL[i].getContent(); // RJA used to check class of contentObject but // crusty Netscape gives a URLInputStream pageContent = (InputStream) contentObject; inputByte = pageContent.read(); outStringBuffer = new StringBuffer(); while( inputByte != -1 ) // end of stream is -1 { outStringBuffer.append( (char) inputByte ); inputByte = pageContent.read(); } pageContent.close(); outString = outStringBuffer.toString(); // take the substring starting at "Number of visits to URLs that match" urlmatchindex = outString.indexOf("Number of visits to URLs that match"); endhtmlindex = outString.indexOf(""); outString = outString.substring( urlmatchindex, endhtmlindex ); lastmonthindex = outString.indexOf("Last month:"); endbodyindex = outString.indexOf(""); lastMonthString = outString.substring( lastmonthindex, endbodyindex ); try { lastMonthCount[i] = new Integer(lastMonthString.substring( lastMonthString.indexOf(":") + 1 ).trim()); System.out.println("lastMonthCount " + lastMonthCount[i]); } catch (NumberFormatException e) { lastMonthCount[i] = new Integer(0); System.err.println("number format exception " + e); } } catch (UnknownServiceException e) { System.err.println( "Caught Unknown Service Exception" ); // should die here } catch (Exception e) { System.err.println( "Caught exception: " + e.toString() ); // should die here } // RJA removed parameters // RJA get values from data above values[i] = lastMonthCount[i].intValue() / mySHRINK; if (values[i] > max) { max = values[i]; } // RJA should be able to call paint now, but want to limit value of i max_paint = i+1; repaint(); } // end for } // end run /* ************** paint ************************ */ public void paint(Graphics g) { int i, j; int cx, cy; char l[] = new char[1]; // RJA replaced getSize() calls with constants because of Netscape // draw the title centered at the bottom of the bar graph g.setColor(Color.black); i = titleFontMetrics.stringWidth(title); g.setFont(titleFont); //g.drawString(title, Math.max((getSize().width - i)/2, 0), // getSize().height - titleFontMetrics.getDescent()); g.drawString(title, Math.max((myWIDTH - i)/2, 0), myHEIGHT - titleFontMetrics.getDescent()); for (i=0; i < max_paint; i++) { switch (orientation) { case VERTICAL: default: // set the next X coordinate to account for the label // being wider than the bar size().width. cx = (Math.max((barWidth + barSpacing),maxLabelWidth) * i) + barSpacing; // center the bar chart //cx += Math.max((getSize().width - (columns * // (barWidth + (2 * barSpacing))))/2,0); cx += Math.max((myWIDTH - (columns * (barWidth + (2 * barSpacing))))/2,0); // set the next Y coordinate to account for the size().height // of the bar as well as the title and labels painted // at the bottom of the chart. //cy = getSize().height - (values[i] * scale) - 1 - (2 * titleFont.getSize()); cy = myHEIGHT - (values[i] * scale) - 1 - (2 * titleFont.getSize()); // draw the label g.setColor(Color.black); //g.drawString((String)labels[i], cx, // getSize().height - titleFont.getSize() - titleFontMetrics.getDescent()); g.drawString((String)labels[i], cx, myHEIGHT - titleFont.getSize() - titleFontMetrics.getDescent()); // RJA no shadow // draw the shadow bar //if (colors[i] == Color.black) { // g.setColor(Color.gray); //} //g.fillRect(cx + 5, cy - 3, barWidth, (values[i] * scale)); // draw the bar with the specified color g.setColor((Color)(colors[i])); switch (styles[i]) { case SOLID: default: g.fillRect(cx, cy, barWidth, (values[i] * scale)); break; case STRIPED: { int steps = (values[i] * scale) / 2; int ys; for (j=0; j < steps; j++) { ys = cy + (2 * j); g.drawLine(cx, ys, cx + barWidth, ys); } } break; } g.drawString("" + values[i], cx, cy - titleFontMetrics.getDescent()); break; case HORIZONTAL: // set the Y coordinate cy = ((barWidth + barSpacing) * i) + barSpacing; // set the X coordinate to be the size().width of the widest // label cx = maxLabelWidth + 1; //cx += Math.max((getSize().width - (maxLabelWidth + 1 + // titleFontMetrics.stringWidth("" + // max) + // (max * scale))) / 2, 0); cx += Math.max((myWIDTH - (maxLabelWidth + 1 + titleFontMetrics.stringWidth("" + max) + (max * scale))) / 2, 0); // draw the labels and the shadow g.setColor(Color.black); g.drawString((String)labels[i], cx - maxLabelWidth - 1, cy + titleFontMetrics.getAscent()); // RJA no shadow //if (colors[i] == Color.black) { // g.setColor(Color.gray); //} //g.fillRect(cx + 3, // cy + 5, // (values[i] * scale), // barWidth); // draw the bar in the current color g.setColor((Color)(colors[i])); switch (styles[i]) { case SOLID: default: g.fillRect(cx, cy, (values[i] * scale), barWidth); break; case STRIPED: { int steps = (values[i] * scale) / 2; int ys; for (j=0; j < steps; j++) { ys = cx + (2 * j); g.drawLine(ys, cy, ys, cy + barWidth); } } break; } g.drawString("" + values[i] * mySHRINK, cx + (values[i] * scale) + 3, cy + titleFontMetrics.getAscent()); break; } } } // end paint } // end MyWebVisitStatsChart