From 597ebadf35e89f20426d83d5d3dacb1b4d04fda2 Mon Sep 17 00:00:00 2001 From: "Eric J. Bowersox" Date: Wed, 31 Oct 2001 19:38:40 +0000 Subject: [PATCH] cleaned up some code - replaced a bunch of copy loops with calls to the new IOUtil class methods, added some javadocs to IOUtil, StringUtil, and AnyCharMatcher --- src/com/silverwrist/util/AnyCharMatcher.java | 77 +++++++ src/com/silverwrist/util/IOUtil.java | 194 +++++++++++++++++- .../util/ServletMultipartHandler.java | 24 +-- src/com/silverwrist/util/StringUtil.java | 99 +++++++-- src/com/silverwrist/util/package.html | 27 +++ .../venice/core/impl/ImageStore.java | 20 +- .../impl/TopicMessageUserContextImpl.java | 18 +- .../venice/servlets/format/RenderConfig.java | 2 +- .../venice/servlets/format/RenderData.java | 12 +- .../venice/servlets/format/StaticRender.java | 16 +- 10 files changed, 391 insertions(+), 98 deletions(-) create mode 100644 src/com/silverwrist/util/package.html diff --git a/src/com/silverwrist/util/AnyCharMatcher.java b/src/com/silverwrist/util/AnyCharMatcher.java index 6deca12..8cac779 100644 --- a/src/com/silverwrist/util/AnyCharMatcher.java +++ b/src/com/silverwrist/util/AnyCharMatcher.java @@ -17,6 +17,16 @@ */ package com.silverwrist.util; +/** + * A class which performs the equivalent of String.indexOf(char), but using + * multiple characters. It locates the first instance within a string of any of + * the specified characters. + * + * @author Eric J. Bowersox <erbo@silcom.com> + * @version X + * @see java.lang.String#indexOf(char) + * @see java.lang.String#lastIndexOf(char) + */ public final class AnyCharMatcher { /*-------------------------------------------------------------------------------- @@ -32,6 +42,11 @@ public final class AnyCharMatcher *-------------------------------------------------------------------------------- */ + /** + * Creates a new character matcher that matches the specified characters. + * + * @param charset The set of characters to be matched by this object, expressed as a character array. + */ public AnyCharMatcher(char[] charset) { this.charset = charset; @@ -39,6 +54,11 @@ public final class AnyCharMatcher } // end constructor + /** + * Creates a new character matcher that matches the specified characters. + * + * @param charset The set of characters to be matched by this object, expressed as a string. + */ public AnyCharMatcher(String charset) { this.charset = charset.toCharArray(); @@ -51,8 +71,20 @@ public final class AnyCharMatcher *-------------------------------------------------------------------------------- */ + /** + * Returns the offset within the string of the first instance of any character in this + * character set. + * + * @param str The string to look through. If this parameter is null, + * the method returns -1. + * @return The 0-based index of the first instance of any character from this character + * matcher within str. If str contains no instances of + * any character from this character matcher, -1 is returned. + */ public final int get(String str) { + if (str==null) + return -1; int numindexes = 0; int i; for (i=0; inull, + * the method returns -1. + * @return The 0-based index of the last instance of any character from this character + * matcher within str. If str contains no instances of + * any character from this character matcher, -1 is returned. + */ + public final int getLast(String str) + { + if (str==null) + return -1; + + int numindexes = 0; + int i; + for (i=0; i=0) + locs[numindexes++] = tmp; + + } // end for + + if (numindexes==0) + return -1; // no characters found + else if (numindexes==1) + return locs[0]; // only one found + + int rc = locs[0]; + int limit = str.length() - 1; + for (i=1; irc) + rc = locs[i]; // this is now the highest + + } // end for + + return rc; + + } // end getLast + } // end class AnyCharMatcher diff --git a/src/com/silverwrist/util/IOUtil.java b/src/com/silverwrist/util/IOUtil.java index 140dc97..74fd12b 100644 --- a/src/com/silverwrist/util/IOUtil.java +++ b/src/com/silverwrist/util/IOUtil.java @@ -19,8 +19,13 @@ package com.silverwrist.util; import java.io.*; -/* Some concepts in here borrowed from Apache Jakarta Avalon Excalibur 4.0 */ - +/** + * A collection of IO-related static methods which are useful in various contexts.

+ * Some of the concepts in this class have been borrowed from Apache Jakarta Avalon Excalibur 4.0. + * + * @author Eric J. Bowersox <erbo@silcom.com> + * @version X + */ public class IOUtil { /*-------------------------------------------------------------------------------- @@ -28,6 +33,9 @@ public class IOUtil *-------------------------------------------------------------------------------- */ + /** + * The default buffer size to use for copying, if none is specified. + */ public static int DEFAULT_BUFSIZE = 4096; /*-------------------------------------------------------------------------------- @@ -35,6 +43,11 @@ public class IOUtil *-------------------------------------------------------------------------------- */ + /** + * Closes an input stream cleanly, without throwing an exception. + * + * @param stm The stream to be closed. + */ public static void shutdown(InputStream stm) { try @@ -48,6 +61,11 @@ public class IOUtil } // end shutdown + /** + * Closes an output stream cleanly, without throwing an exception. + * + * @param stm The stream to be closed. + */ public static void shutdown(OutputStream stm) { try @@ -61,6 +79,11 @@ public class IOUtil } // end shutdown + /** + * Closes an input reader cleanly, without throwing an exception. + * + * @param stm The stream to be closed. + */ public static void shutdown(Reader rdr) { try @@ -74,6 +97,11 @@ public class IOUtil } // end shutdown + /** + * Closes an output reader cleanly, without throwing an exception. + * + * @param stm The stream to be closed. + */ public static void shutdown(Writer wr) { try @@ -87,6 +115,14 @@ public class IOUtil } // end shutdown + /** + * Copies the contents of the given input stream to the given output stream. + * + * @param input The stream to copy binary data from. + * @param output The stream to copy binary data to. + * @param bufsize The size of the buffer to allocate for copying. + * @exception java.io.IOException If an exception occurred while reading or writing data. + */ public static void copy(InputStream input, OutputStream output, int bufsize) throws IOException { byte[] buffer = new byte[bufsize]; @@ -101,12 +137,113 @@ public class IOUtil } // end copy + /** + * Copies the contents of the given input stream to the given output stream. Uses a default + * buffer size. + * + * @param input The stream to copy binary data from. + * @param output The stream to copy binary data to. + * @exception java.io.IOException If an exception occurred while reading or writing data. + * @see #DEFAULT_BUFSIZE + * @see #copy(java.io.InputStream,java.io.OutputStream,int) + */ public static void copy(InputStream input, OutputStream output) throws IOException { copy(input,output,DEFAULT_BUFSIZE); } // end copy + /** + * Takes the contents of an input stream and returns it as an array of bytes. + * + * @param input The stream to load binary data from. + * @param bufsize The size of the buffer to allocate for copying. + * @return A new byte array containing the contents of the specified input stream. + * @exception java.io.IOException If an exception occurred while reading data. + * @see #copy(java.io.InputStream,java.io.OutputStream,int) + */ + public static byte[] load(InputStream input, int bufsize) throws IOException + { + ByteArrayOutputStream stm = new ByteArrayOutputStream(); + try + { // copy the data to the input stream + copy(input,stm,bufsize); + return stm.toByteArray(); + + } // end try + finally + { // close our byte array stream before we go + shutdown(stm); + + } // end finally + + } // end load + + /** + * Takes the contents of an input stream and returns it as an array of bytes. Uses a default + * buffer size. + * + * @param input The stream to load binary data from. + * @return A new byte array containing the contents of the specified input stream. + * @exception java.io.IOException If an exception occurred while reading data. + * @see #DEFAULT_BUFSIZE + * @see #load(java.io.InputStream,int) + */ + public static byte[] load(InputStream input) throws IOException + { + return load(input,DEFAULT_BUFSIZE); + + } // end load + + /** + * Takes the contents of a binary file and returns it as an array of bytes. + * + * @param file The file to load binary data from. + * @param bufsize The size of the buffer to allocate for copying. + * @return A new byte array containing the contents of the specified file. + * @exception java.io.IOException If an exception occurred while reading data. + * @see #load(java.io.InputStream,int) + */ + public static byte[] loadBinary(File file, int bufsize) throws IOException + { + FileInputStream stm = new FileInputStream(file); + try + { // now just load from the stream + return load(stm,bufsize); + + } // end try + finally + { // close the file before we leave + shutdown(stm); + + } // end finally + + } // end loadBinary + + /** + * Takes the contents of a binary file and returns it as an array of bytes. Uses a default + * buffer size. + * + * @param file The file to load binary data from. + * @return A new byte array containing the contents of the specified file. + * @exception java.io.IOException If an exception occurred while reading data. + * @see #DEFAULT_BUFSIZE + * @see #loadBinary(java.io.File,int) + */ + public static byte[] loadBinary(File file) throws IOException + { + return loadBinary(file,DEFAULT_BUFSIZE); + + } // end loadBinary + + /** + * Copies the contents of the given input reader to the given output writer. + * + * @param input The reader to copy character data from. + * @param output The writer to copy character data to. + * @param bufsize The size of the buffer to allocate for copying. + * @exception java.io.IOException If an exception occurred while reading or writing data. + */ public static void copy(Reader input, Writer output, int bufsize) throws IOException { char[] buffer = new char[bufsize]; @@ -121,12 +258,31 @@ public class IOUtil } // end copy + /** + * Copies the contents of the given input reader to the given output writer. Uses a default + * buffer size. + * + * @param input The reader to copy character data from. + * @param output The writer to copy character data to. + * @exception java.io.IOException If an exception occurred while reading or writing data. + * @see #DEFAULT_BUFSIZE + * @see #copy(java.io.Reader,java.io.Writer,int) + */ public static void copy(Reader input, Writer output) throws IOException { copy(input,output,DEFAULT_BUFSIZE); } // end copy + /** + * Takes the contents of an input reader and returns it as a StringBuffer. + * + * @param input The reader to copy character data from. + * @param bufsize The size of the buffer to allocate for copying. + * @return A new StringBuffer containing the contents of the specified reader. + * @exception java.io.IOException If an exception occurred while reading data. + * @see #copy(java.io.Reader,java.io.Writer,int) + */ public static StringBuffer load(Reader input, int bufsize) throws IOException { StringWriter wr = new StringWriter(); @@ -144,13 +300,32 @@ public class IOUtil } // end load + /** + * Takes the contents of an input reader and returns it as a StringBuffer. Uses a + * default buffer size. + * + * @param input The reader to copy character data from. + * @return A new StringBuffer containing the contents of the specified reader. + * @exception java.io.IOException If an exception occurred while reading data. + * @see #DEFAULT_BUFSIZE + * @see #load(java.io.Reader,int) + */ public static StringBuffer load(Reader input) throws IOException { return load(input,DEFAULT_BUFSIZE); } // end load - public static StringBuffer load(File file, int bufsize) throws IOException + /** + * Takes the contents of a text file and returns it as a StringBuffer. + * + * @param file The file to copy text from. + * @param bufsize The size of the buffer to allocate for copying. + * @return A new StringBuffer containing the contents of the specified text file. + * @exception java.io.IOException If an exception occurred while reading data. + * @see #load(java.io.Reader,int) + */ + public static StringBuffer loadText(File file, int bufsize) throws IOException { FileReader rdr = new FileReader(file); try @@ -166,9 +341,18 @@ public class IOUtil } // end load - public static StringBuffer load(File file) throws IOException + /** + * Takes the contents of a text file and returns it as a StringBuffer. + * + * @param file The file to copy text from. + * @return A new StringBuffer containing the contents of the specified text file. + * @exception java.io.IOException If an exception occurred while reading data. + * @see #DEFAULT_BUFSIZE + * @see #loadText(java.io.File,int) + */ + public static StringBuffer loadText(File file) throws IOException { - return load(file,DEFAULT_BUFSIZE); + return loadText(file,DEFAULT_BUFSIZE); } // end load diff --git a/src/com/silverwrist/util/ServletMultipartHandler.java b/src/com/silverwrist/util/ServletMultipartHandler.java index 4862389..d0e631f 100644 --- a/src/com/silverwrist/util/ServletMultipartHandler.java +++ b/src/com/silverwrist/util/ServletMultipartHandler.java @@ -84,8 +84,6 @@ public class ServletMultipartHandler static class MultipartDataValue implements Blob { - private static final int BLKSIZE = 4096; - private byte[] actual_data; // the actual data we contain public MultipartDataValue(MimeBodyPart part) throws MessagingException, IOException @@ -93,26 +91,8 @@ public class ServletMultipartHandler if (logger.isDebugEnabled()) logger.debug("creating new MultipartDataValue"); - // set up the streams to copy between - InputStream in = part.getInputStream(); - ByteArrayOutputStream out = new ByteArrayOutputStream(); - byte[] copybuf = new byte[BLKSIZE]; - - // begin the copy loop - int ct = in.read(copybuf,0,BLKSIZE); - while (ct>=0) - { // do a simple read and write - if (logger.isDebugEnabled()) - logger.debug("read blksize = " + ct); - if (ct>0) - out.write(copybuf,0,ct); - ct = in.read(copybuf,0,BLKSIZE); - - } // end while - - in.close(); - actual_data = out.toByteArray(); - out.close(); + // load actual data + actual_data = IOUtil.load(part.getInputStream()); if (logger.isDebugEnabled()) logger.debug("finished copying, " + actual_data.length + " bytes transferred"); diff --git a/src/com/silverwrist/util/StringUtil.java b/src/com/silverwrist/util/StringUtil.java index 583421d..5b4cc9c 100644 --- a/src/com/silverwrist/util/StringUtil.java +++ b/src/com/silverwrist/util/StringUtil.java @@ -19,6 +19,12 @@ package com.silverwrist.util; import java.util.*; +/** + * A collection of string-related static methods which are useful in various contexts. + * + * @author Eric J. Bowersox <erbo@silcom.com> + * @version X + */ public class StringUtil { /*-------------------------------------------------------------------------------- @@ -35,10 +41,18 @@ public class StringUtil *-------------------------------------------------------------------------------- */ + /** + * Performs SQL encoding of an arbitrary string. When a string is SQL-encoded, all single-quote + * characters are doubled, and all other characters are left untouched. + * + * @param str The string to be SQL-encoded. May be null. + * @return The SQL-encoded equivalent of str. If str is + * null, returns null. + */ public static String encodeStringSQL(String str) { if (str==null) - return null; + return null; // safety feature int ndx = str.indexOf('\''); if (ndx<0) return str; @@ -58,10 +72,19 @@ public class StringUtil } // end encodeStringSQL + /** + * Performs HTML encoding of an arbitrary string. When a string is HTML encoded, the double-quote ("), + * ampersand (&), less-than (<), and greater-than (>) characters are transformed to their HTML + * entity equivalents; all other characters are left untouched. + * + * @param str The string to be HTML-encoded. May be null. + * @return The HTML-encoded equivalent of str. If str is + * null, returns null. + */ public static String encodeHTML(String str) { if (str==null) - return null; + return null; // safety feature AnyCharMatcher nhc = new AnyCharMatcher(HTML_ENCODE_CHARS); int ndx = nhc.get(str); if (ndx<0) @@ -103,46 +126,92 @@ public class StringUtil } // end encodeHTML + /** + * Returns true if the given string is null or a string of + * length 0, false otherwise. + * + * @param s The string to be tested. + * @return true if the given string is null or a string of + * length 0, false otherwise. + */ public static boolean isStringEmpty(String s) { return ((s==null) || (s.length()==0)); } // end isStringEmpty + /** + * Replaces all instances of a particular substring within a string with another substring. + * For example:

+ * replaceAllInstances("blahdeeblah","blah","hoo") + * returns "hoodeehoo"
+ * replaceAllInstances("blahdeebleh","blah","hoo") + * returns "hoodeebleh" + * + * @param base The string to be operated on. If this parameter is null, the + * method will return null. + * @param find The substring to find in the base string. If this parameter is + * null or an empty string, no replacing will be done. + * @param replace The substring to replace instances of the find string with in the + * base string. If this parameter is null, instances + * of the find string will be deleted. + * @return The base string with all replacements made as detailed above. + */ public static String replaceAllInstances(String base, String find, String replace) { - String work = base; - int ndx = work.indexOf(find); + if ((base==null) || isStringEmpty(find)) + return base; // safety feature + int ndx = base.indexOf(find); if (ndx<0) - return work; // trivial case + return base; // trivial case StringBuffer b = new StringBuffer(); while (ndx>=0) { // break off the first part of the string, then insert the replacement if (ndx>0) - b.append(work.substring(0,ndx)); - b.append(replace); + b.append(base.substring(0,ndx)); + if (replace!=null) + b.append(replace); // break off the tail end ndx += find.length(); - if (ndx==work.length()) + if (ndx==base.length()) return b.toString(); // entire string munched - we're done! - work = work.substring(ndx); - ndx = work.indexOf(find); + base = base.substring(ndx); + ndx = base.indexOf(find); } // end while - // append the unmatched "tail" of the work string and then return result - b.append(work); + // append the unmatched "tail" of the string and then return result + b.append(base); return b.toString(); } // end replaceAllInstances + /** + * Replaces variable substitutions in a string. Variable substitutions are strings of the form + * ${varname}. The varname names are looked up in the supplied + * Map, and the values of variables in that map are substituted.

+ * Only variable names that exist in the Map are replaced; other variable strings + * in the supplied string are left untouched. Variable substitution values may themselves contain + * variables; those variables are recursively replaced. (Caution: The code cannot + * detect variable substitutions that contain themselves, or two variables that contain each other. + * Avoid these situations.) + * + * @param base The string to be operated on. If this parameter is null, the + * method will return null. + * @param vars The mapping of variable name to value substitutions. If this parameter is + * null or an empty map, no substitutions will be performed on + * base. + * @return The base string with all variable substitutions made as detailed above. + */ public static String replaceAllVariables(String base, Map vars) { - String work = base; - boolean did_replace, retest; + if ((base==null) || (vars==null) || (vars.size()==0)) + return base; // safety feature - retest = true; + String work = base; + boolean did_replace; + boolean retest = true; do { // main loop for replacing all variables did_replace = false; diff --git a/src/com/silverwrist/util/package.html b/src/com/silverwrist/util/package.html new file mode 100644 index 0000000..1cc2c7d --- /dev/null +++ b/src/com/silverwrist/util/package.html @@ -0,0 +1,27 @@ + + + + + +Provides a number of "utility" functions used by various parts of the Venice code. + + + + + diff --git a/src/com/silverwrist/venice/core/impl/ImageStore.java b/src/com/silverwrist/venice/core/impl/ImageStore.java index 7374549..5d18b37 100644 --- a/src/com/silverwrist/venice/core/impl/ImageStore.java +++ b/src/com/silverwrist/venice/core/impl/ImageStore.java @@ -21,6 +21,7 @@ import java.io.*; import java.sql.*; import java.util.*; import org.apache.log4j.*; +import com.silverwrist.util.IOUtil; import com.silverwrist.venice.db.*; import com.silverwrist.venice.core.*; @@ -107,23 +108,8 @@ class ImageStore implements BinaryData } // end if // Since the InputStream we get from JDBC will probably go away when the connection is dropped, we - // need to make a temporary copy of it, to a ByteArrayOutputStream. - InputStream sqldata = rs.getBinaryStream(1); - ByteArrayOutputStream copy = new ByteArrayOutputStream(length); - byte[] buffer = new byte[4096]; - int rd = sqldata.read(buffer); - while (rd>=0) - { // write, then read again - if (rd>0) - copy.write(buffer,0,rd); - rd = sqldata.read(buffer); - - } // end while - - // Close both our streams, making sure we create the stream we need for the return value. - sqldata.close(); - rc = new ByteArrayInputStream(copy.toByteArray()); - copy.close(); + // need to make a temporary copy of it. + rc = new ByteArrayInputStream(IOUtil.load(rs.getBinaryStream(1))); } // end try catch (SQLException e) diff --git a/src/com/silverwrist/venice/core/impl/TopicMessageUserContextImpl.java b/src/com/silverwrist/venice/core/impl/TopicMessageUserContextImpl.java index b1c4311..2c9d0f5 100644 --- a/src/com/silverwrist/venice/core/impl/TopicMessageUserContextImpl.java +++ b/src/com/silverwrist/venice/core/impl/TopicMessageUserContextImpl.java @@ -22,6 +22,7 @@ import java.sql.*; import java.util.*; import java.util.zip.*; import org.apache.log4j.*; +import com.silverwrist.util.IOUtil; import com.silverwrist.util.StringUtil; import com.silverwrist.venice.db.*; import com.silverwrist.venice.security.AuditRecord; @@ -432,21 +433,8 @@ class TopicMessageUserContextImpl implements TopicMessageContext } // end switch - ByteArrayOutputStream copy = new ByteArrayOutputStream(datalen); - byte[] buffer = new byte[4096]; - int rd = real_input.read(buffer); - while (rd>=0) - { // write, then read again - if (rd>0) - copy.write(buffer,0,rd); - rd = real_input.read(buffer); - - } // end while - - // Close both our streams, making sure we create the stream we need for the return value. - real_input.close(); - rc = new ByteArrayInputStream(copy.toByteArray()); - copy.close(); + // Copy to a new stream. + rc = new ByteArrayInputStream(IOUtil.load(real_input)); } // end try catch (SQLException e) diff --git a/src/com/silverwrist/venice/servlets/format/RenderConfig.java b/src/com/silverwrist/venice/servlets/format/RenderConfig.java index 617527b..fa17121 100644 --- a/src/com/silverwrist/venice/servlets/format/RenderConfig.java +++ b/src/com/silverwrist/venice/servlets/format/RenderConfig.java @@ -555,7 +555,7 @@ public class RenderConfig implements ColorSelectors synchronized String loadStyleSheetData() throws IOException { // Load the stylesheet data. - StringBuffer raw_data = IOUtil.load(stylesheet); + StringBuffer raw_data = IOUtil.loadText(stylesheet); stylesheet_time = stylesheet.lastModified(); // Set up the replacements map to replace the various parameters. diff --git a/src/com/silverwrist/venice/servlets/format/RenderData.java b/src/com/silverwrist/venice/servlets/format/RenderData.java index 41204ed..be9f941 100644 --- a/src/com/silverwrist/venice/servlets/format/RenderData.java +++ b/src/com/silverwrist/venice/servlets/format/RenderData.java @@ -23,6 +23,7 @@ import java.text.DateFormat; import javax.servlet.*; import javax.servlet.http.*; import org.apache.log4j.*; +import com.silverwrist.util.IOUtil; import com.silverwrist.util.StringUtil; import com.silverwrist.venice.core.DataException; import com.silverwrist.venice.core.IDUtils; @@ -462,16 +463,7 @@ public class RenderData implements ColorSelectors response.setHeader("Content-Disposition","attachment; filename=\"" + filename + "\";"); // Copy the contents of the "data" stream to the output. - ServletOutputStream stm = response.getOutputStream(); - byte[] buffer = new byte[4096]; - int rd = data.read(buffer); - while (rd>=0) - { // simple read-write loop to shove data out the door - if (rd>0) - stm.write(buffer,0,rd); - rd = data.read(buffer); - - } // end while + IOUtil.copy(data,response.getOutputStream()); } // end sendBinaryData diff --git a/src/com/silverwrist/venice/servlets/format/StaticRender.java b/src/com/silverwrist/venice/servlets/format/StaticRender.java index d9b2fc8..4571790 100644 --- a/src/com/silverwrist/venice/servlets/format/StaticRender.java +++ b/src/com/silverwrist/venice/servlets/format/StaticRender.java @@ -18,6 +18,7 @@ package com.silverwrist.venice.servlets.format; import java.io.*; +import com.silverwrist.util.IOUtil; import com.silverwrist.util.cachemap.CacheMap; public class StaticRender implements ContentRender @@ -94,21 +95,10 @@ public class StaticRender implements ContentRender } // end if // Read in the whole thing. - StringBuffer raw_file = new StringBuffer(); + StringBuffer raw_file; try { // read in from the file - FileReader rdr = new FileReader(real_path); - char[] buffer = new char[4096]; - int rd = rdr.read(buffer); - while (rd>=0) - { // read in the raw characters - if (rd>0) - raw_file.append(buffer,0,rd); - rd = rdr.read(buffer); - - } // end while - - rdr.close(); + raw_file = IOUtil.loadText(new File(real_path)); } // end try catch (IOException ioe)