- From: albert (a.x.) zhou <azhou@nortel.ca>
- Date: Thu, 29 Aug 1996 22:21:00 -0400
- To: www-jigsaw@w3.org
I wrote a resource, called YAACResource, to generate an XBM image for access counts (YAAC = Yet Another Access Count). Configuring YAACResource should be easy and straightforward (see the class description). Hope this is helpful and useful. Critical comments are appreciated. Cheers, Albert Albert X. Zhou ~{V\O~;*~} | Opinions expressed are my own, | Nortel Technology | not necessarily those of Nortel. | P.O. Box 3511, Station C, Ottawa, Canada K1Y 4H7 Tel: (613) 763-9702; Fax: (613) 765-4855; E-Mail: azhou@nortel.ca // $RCSfile: YAACResource.java,v $$Revision: 1.5 $$Date: 96/08/25 23:11:47 $ package w3c.jigsaw.contrib; import java.io.*; import java.net.*; import java.util.*; import w3c.jigsaw.auth.*; import w3c.jigsaw.http.*; import w3c.jigsaw.resources.*; /** * This resource class generates an access count in the form of an XBM * image for a configurable YAAC (yet another access count) tag embedded * in an HTML page. * <p>The steps to configure and use this graphical access counter are * shown as follows:</p> * <ol> * <li>Configure the YAAC resource in a server directory, say the * root. Attributes of the YAAC resource are rather self- * explanatory. The name of this resource could be any string, * eg, Yaac. * <li>Put an IMG tag in the HTML file where you want to show the * access count with the SRC value set to the URI where the YAAC * resource has been configured above. For instance, if you add * the YAAC resource with the name of Yaac to the root directory, * the src should be set to "/Yaac". * </ol> * <p>The part of generating XBM image is based on a perl script by * <a href="http://www.lerc.nasa.gov/people/OmarSyed/">Omar Syed</a>.</p> * @version 0.13, 1996.08.26 * @author Albert Zhou, azhou@nortel.ca */ public class YAACResource extends HTTPResource { protected static int ATTR_URLSTOCOUNT = -1; // URLs to count protected static int ATTR_IPSTOIGNORE = -1; // IPs to ignore protected static int ATTR_LEADINGZERO = -1; // show leading zeroes? protected static int ATTR_INVERSE = -1; // inverse the counter image? /** * The yaac is the hashtable storing the access count values for * those URLs registered via the YAAC resource. */ private static Hashtable yaac = new Hashtable(); /** * The class variable digits stores the bitmaps for digits 0 to 9. */ private static byte[] digits = { 0x00,0x00,0x00,0x3c,0x66,0x66,0x66,0x66, 0x66,0x66,0x66,0x66,0x3c,0x00,0x00,0x00, 0x00,0x00,0x00,0x30,0x38,0x30,0x30,0x30, 0x30,0x30,0x30,0x30,0x30,0x00,0x00,0x00, 0x00,0x00,0x00,0x3c,0x66,0x60,0x60,0x30, 0x18,0x0c,0x06,0x06,0x7e,0x00,0x00,0x00, 0x00,0x00,0x00,0x3c,0x66,0x60,0x60,0x38, 0x60,0x60,0x60,0x66,0x3c,0x00,0x00,0x00, 0x00,0x00,0x00,0x30,0x30,0x38,0x38,0x34, 0x34,0x32,0x7e,0x30,0x78,0x00,0x00,0x00, 0x00,0x00,0x00,0x7e,0x06,0x06,0x06,0x3e, 0x60,0x60,0x60,0x66,0x3c,0x00,0x00,0x00, 0x00,0x00,0x00,0x38,0x0c,0x06,0x06,0x3e, 0x66,0x66,0x66,0x66,0x3c,0x00,0x00,0x00, 0x00,0x00,0x00,0x7e,0x66,0x60,0x60,0x30, 0x30,0x18,0x18,0x0c,0x0c,0x00,0x00,0x00, 0x00,0x00,0x00,0x3c,0x66,0x66,0x66,0x3c, 0x66,0x66,0x66,0x66,0x3c,0x00,0x00,0x00, 0x00,0x00,0x00,0x3c,0x66,0x66,0x66,0x66, 0x7c,0x60,0x60,0x30,0x1c,0x00,0x00,0x00 }; static { Attribute a = null; Class cls = null; try { cls = Class.forName("w3c.jigsaw.contrib.YAACResource"); } catch (Exception e) { e.printStackTrace(); System.exit(1); } // declare/register the attributes a = new StringArrayAttribute("URLstocount", null, Attribute.EDITABLE); ATTR_URLSTOCOUNT = AttributeRegistery.registerAttribute(cls, a); a = new IPTemplatesAttribute("IPstoignore", null, Attribute.EDITABLE); ATTR_IPSTOIGNORE = AttributeRegistery.registerAttribute(cls, a); a = new BooleanAttribute("Leadingzero", Boolean.TRUE, Attribute.EDITABLE); ATTR_LEADINGZERO = AttributeRegistery.registerAttribute(cls, a); a = new BooleanAttribute("Inverse", Boolean.TRUE, Attribute.EDITABLE); ATTR_INVERSE = AttributeRegistery.registerAttribute(cls, a); } /** * Get the list of resource URLs that are configured to count. * @return the URL list (of strings). */ public String[] getURLs() { return (String[]) getValue(ATTR_URLSTOCOUNT, null); } /** * Get the list of IPs that should be ignored. * @return the IP list. */ public short[][] getIPs() { return (short[][]) getValue(ATTR_IPSTOIGNORE, null); } /** * Get the leading zero boolean. * @return the leading zero boolean. */ public boolean getLeadingZero() { return getBoolean(ATTR_LEADINGZERO, true); } /** * Get the inverse boolean. * @return the inverse boolean. */ public boolean getInverse() { return getBoolean(ATTR_INVERSE, true); } /** * Get the access count for a desired URL. * @return the access count. */ public synchronized int getCount(String url) { int count = 0; if (yaac.containsKey(url)) count = ((Integer)yaac.get(url)).intValue(); return count; } /** * Set the access count for a desired URL. */ public synchronized void setCount(String url, int count) { yaac.put(url, new Integer(count)); markModified(); // mark Yaac resource modified } /** * Is the requested URL configured for YAAC count? * @param url the requested URL * @return true if the URL is YAAC configured; false otherwise. */ public boolean YAACConfigured(String url) { boolean found = false; String urls[] = getURLs(); if (urls != null) { int i = 0; while (!found && i < urls.length) found = urls[i++].equals(url); } return found; } /** * Should the request host be ignored regarding the YAAC count? * @param ip the request host IP address in network bytes. * @return true if the host should be ignored; false otherwise. */ public boolean hostToIgnore(byte[] ip) { boolean found = false; short ips[][] = getIPs(); if (ips != null) { int i = 0; while (!found && i < ips.length) { found = true; for (int j = 0; j < ip.length; j++) { if (ips[i][j] != 256) // match/ignore the wild card found &= (byte)ips[i][j] == ip[j]; } i++; } } return found; } /** * Display the access count for the referer URL if it's configured. * @param request the original request * @exception HTTPException If processing fails. */ public Reply get(Request request) throws HTTPException { String referer = request.getField("referer"); if (YAACConfigured(referer)) { int count = getCount(referer); Client client = request.getClient(); InetAddress ipaddr = client.getInetAddress(); if (!hostToIgnore(ipaddr.getAddress())) setCount(referer, ++count); Reply reply = request.makeReply(HTTP.OK); reply.setContentType("image/xbm"); String image = createYAACImage(count, getLeadingZero(), getInverse()); reply.setContent(image); return reply; } else { Reply error = request.makeReply(HTTP.NOT_ALLOWED); error.setContentType("image/xbm"); throw new HTTPException(error); } } /** * Generate an XBM bitmap image for a YAAC access count. * @param count the access count * @param leadingzero the leading zeros desirable? * @param inverse the inverse display desirable? * @return the String containing the xbm image */ protected String createYAACImage(int count, boolean leadingzero, boolean inverse) { StringBuffer sb = new StringBuffer(Integer.toString(count)); int len = sb.length() > 7 ? sb.length() : 7; if (leadingzero) { int fill = len - sb.length(); for (int i = 0; i < fill; i++) sb = sb.insert(0, '0'); } StringBuffer image = new StringBuffer(); image.append("#define count_width " + len*8 + "\n"); image.append("#define count_height 16\n"); image.append("static char count_bits[] = {\n"); int digit; for (int y = 0; y < 16; y++) { for (int x = 0; x < len; x++) { digit = digits[((sb.charAt(x) - '0') * 16) + y]; if (inverse) { image.append(toHexString((((digit >> 4) ^ 0xf) & 0xf), ((digit ^ 0xf) & 0xf))); } else { image.append(toHexString(((digit >> 4) & 0xf), (digit & 0xf))); } if (x < len-1) image.append(','); } image.append((y == 15) ? "};" : ","); image.append('\n'); } return image.toString(); } /** * Convert an integer with high and low bytes to its equivalent Hex * representation starting with the hex indicator '0x'. * @param hi the high byte * @param low the low byte * @return the String containing the Hex string */ private String toHexString(int hi, int low) { return "0x" + Integer.toString(hi << 4 | low, 16); } /** * Convert an integer to its equivalent Hex representation starting * with the hex indicator '0x'. * @param i the integer * @return the String containing the Hex string */ private String toHexString(int i) { return "0x" + Integer.toHexString(i); } /** * Pickle a YAAC resource along with its associated counts. * @param out the data output stream to pickle to. */ public synchronized void pickle(DataOutputStream out) throws IOException { super.pickle(out); // pickle the yaac counts if (yaac.isEmpty()) { out.writeInt(0); } else { out.writeInt(yaac.size()); Enumeration urls = yaac.keys(); String url; int count; while (urls.hasMoreElements()) { url = (String) urls.nextElement(); count = getCount(url); out.writeUTF(url); out.writeInt(count); } } } /** * Unpickle a YAAC resource. * @param in the input stream to unpickle from. * @param defs the default attributes for the unpickled resource. */ public AttributeHolder unpickleInstance(DataInputStream in, Hashtable defs) throws IOException { super.unpickleInstance(in, defs); // unpickle the yaac counts int size = in.readInt(); if (size > 0) { yaac = new Hashtable(); String url; int count; for (int i = 0; i < size; i++) { url = in.readUTF(); count = in.readInt(); setCount(url, count); } } return this; } }
Received on Thursday, 29 August 1996 22:23:13 UTC