Java tutorial
/* */ package com.adito.boot; import java.io.BufferedReader; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.PrintWriter; import java.io.StringReader; import java.io.StringWriter; import java.io.UnsupportedEncodingException; import java.net.URL; import java.net.URLClassLoader; import java.net.URLDecoder; import java.net.URLEncoder; import java.util.Calendar; import java.util.Enumeration; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.StringTokenizer; import java.util.Vector; import javax.servlet.ServletContext; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** * Utilities used throughout the Adito boot environment, server * implementation and web application. */ public class Util { final static Log log = LogFactory.getLog(Util.class); /** * Default buffer size for stream utility methods */ public static int BUFFER_SIZE = 8192; /* * Prevent instantiation */ private Util() { super(); } /** * Get the statement from the current stack trace given its depth. I.e, a * depth of 0 will return this method, a depth of 1 will return the method * that called this method etc. * * @param depth depth * @return statement as string */ public static String getCurrentStatement(int depth) { try { throw new Exception(); } catch (Exception e) { try { StringWriter sw = new StringWriter(); e.printStackTrace(new PrintWriter(sw)); BufferedReader reader = new BufferedReader(new StringReader(sw.toString())); reader.readLine(); reader.readLine(); sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw, true); for (int i = 0; i < depth; i++) { String s = reader.readLine(); pw.println(s.substring(7)); } return sw.toString(); } catch (Throwable t) { return "Unknown."; } } } /** * Trim spaces from both ends of string * * @param string string to trim * @return trimmed string */ public static String trimBoth(String string) { string = string.trim(); for (int i = 0; i < string.length(); i++) { if (string.charAt(i) != ' ') { return string.substring(i); } } return string; } /** * Close an output stream, ignoing any exceptions. No error will be thrown * if the provided stream is <code>null</code> * * @param outputStream stream to close */ public static void closeStream(OutputStream outputStream) { if (outputStream != null) { try { outputStream.close(); } catch (IOException ioe) { } } } /** * Close an input stream, ignoing any exceptions. No error will be thrown if * the provided stream is <code>null</code> * * @param inputStream stream to close */ public static void closeStream(InputStream inputStream) { if (inputStream != null) { try { inputStream.close(); } catch (IOException ioe) { } } } /** * Extract the value portion of a string in the format of a named value pair * i.e. <i>[name]=[value]</i>. * * @param nameEqualsValue string * @return value portion of name / value pair */ public static String valueOfNameValuePair(String nameEqualsValue) { String value = nameEqualsValue.substring(nameEqualsValue.indexOf('=') + 1).trim(); int i = value.indexOf(';'); if (i > 0) value = value.substring(0, i); if (value.startsWith("\"")) { value = value.substring(1, value.indexOf('"', 1)); } else { i = value.indexOf(' '); if (i > 0) value = value.substring(0, i); } return value; } /** * Convert a byte array to a hex string * * @param data * @return hex string */ public static String toHexString(byte[] data) { return toHexString(data, 0, data.length); } /** * Convert a byte array to a hex string * * @param data bytes to convert * @param offset offset in array to start from * @param len number of bytes to convert * @return hex string */ public static String toHexString(byte[] data, int offset, int len) { StringBuffer buf = new StringBuffer(); for (int i = offset; i < len; i++) { String s = Integer.toHexString(((byte) data[i] & 0xFF)); if (s.length() < 2) { buf.append("0"); } buf.append(s); } return buf.toString(); } /** * Rebuild the URI of the request by concatenating the servlet path and and * request parameters * * @param request request to extra path from * @return path */ public static String getOriginalRequest(HttpServletRequest request) { StringBuffer req = new StringBuffer(request.getServletPath()); if (request.getQueryString() != null && request.getQueryString().length() > 0) { req.append("?"); req.append(request.getQueryString()); } return req.toString(); } /** * Read an input stream and load it into a string. * * @param in input stream * @param charsetName encoding or <code>null</code> for default * @return string * @throws IOException on any error */ public static String loadStreamToString(InputStream in, String charsetName) throws IOException { StringBuffer licenseText = new StringBuffer(); BufferedReader br = new BufferedReader( charsetName == null ? new InputStreamReader(in) : new InputStreamReader(in, charsetName)); try { char[] buf = new char[65536]; int r = 0; while ((r = br.read(buf)) != -1) licenseText.append(buf, 0, r); } finally { br.close(); } return licenseText.toString(); } /** * Dump all session attributes to {@link System#err}. * * @param session session to get attributes from */ public static void dumpSessionAttributes(HttpSession session) { System.err.println("Session attributes for " + session.getId()); for (Enumeration e = session.getAttributeNames(); e.hasMoreElements();) { String n = (String) e.nextElement(); System.err.println(" " + n + " = " + session.getAttribute(n)); } } /** * Dump all request attributes to {@link System#err}. * * @param request request to get attributes from */ public static void dumpRequestAttributes(HttpServletRequest request) { System.err.println("Request attributes for " + request.getPathTranslated()); for (Enumeration e = request.getAttributeNames(); e.hasMoreElements();) { String n = (String) e.nextElement(); System.err.println(" " + n + " = " + request.getAttribute(n)); } } /** * Dump all request headers to {@link System#err}. * * @param request request to get headers from */ public static void dumpRequestHeaders(HttpServletRequest request) { System.err.println("Request headers for " + request.getPathTranslated()); for (Enumeration e = request.getHeaderNames(); e.hasMoreElements();) { String n = (String) e.nextElement(); for (Enumeration e2 = request.getHeaders(n); e2.hasMoreElements();) { String v = (String) e2.nextElement(); System.err.println(" " + n + " = " + v); } } } /** * Dump all servlet context attributes to {@link System#err}. * * @param context context to get attributes from */ public static void dumpServletContextAttributes(ServletContext context) { System.err.println("Servlet context attributes for"); for (Enumeration e = context.getAttributeNames(); e.hasMoreElements();) { String n = (String) e.nextElement(); System.err.println(" " + n + " = " + context.getAttribute(n)); } } /** * Dump all request parameters to {@link System#err} * * @param request request to get parameters from */ public static void dumpRequestParameters(HttpServletRequest request) { System.err.println("Request parameters for session #" + request.getSession().getId()); for (Enumeration e = request.getParameterNames(); e.hasMoreElements();) { String n = (String) e.nextElement(); String[] vals = request.getParameterValues(n); for (int i = 0; i < vals.length; i++) { System.err.println(" " + n + " = " + vals[i]); } } } /** * Dump all request parameters and some other useful stuff from * the request to {@link System#err} * * @param request request to get parameters from */ public static void dumpRequest(HttpServletRequest request) { System.err.println("Context Path " + request.getContextPath()); System.err.println("Path Translated " + request.getPathTranslated()); System.err.println("Path Info " + request.getPathInfo()); System.err.println("Query: " + request.getQueryString()); System.err.println("Request URI: " + request.getRequestURI()); System.err.println("Request URL: " + request.getRequestURL()); System.err.println("Is Secure: " + request.isSecure()); System.err.println("Scheme: " + request.getScheme()); dumpRequestParameters(request); dumpRequestAttributes(request); dumpRequestHeaders(request); } /** * Dump the contents of a {@link Map} to {@link System#err}. * * @param map map to dump */ public static void dumpMap(Map map) { System.err.println("Map dump"); for (Iterator i = map.entrySet().iterator(); i.hasNext();) { Map.Entry entry = (Map.Entry) i.next(); System.err.println(" Key = " + entry.getKey() + " Val = " + entry.getValue()); } } /** * Dump an exception to {@link System#err}. * * @param exception exception to dump */ public static void printStackTrace(Throwable exception) { Exception e; try { throw new Exception(); } catch (Exception ex) { e = ex; } StackTraceElement[] trace = e.getStackTrace(); System.err.println("[REMOVE-ME] - " + trace[1].getClassName() + ":" + trace[1].getLineNumber()); exception.printStackTrace(); } /** * Concatenate all of the non null messages from an exception chain, * appending full stops after each messages if they do not end with one. * * @param t trace * @return exception message chain text */ public static String getExceptionMessageChain(Throwable t) { StringBuffer buf = new StringBuffer(); while (t != null) { if (buf.length() > 0 && !buf.toString().endsWith(".")) { buf.append(". "); } if (t.getMessage() != null) { buf.append(t.getMessage().trim()); } t = t.getCause(); } return buf.toString(); } /** * Print a TODO message to {@link System#err}, including the current class * and line number call was made along with a specified message. * <p> * Use for temporary debug. Calling statement should be removed. * </p> * * @param message message to display */ public static void toDo(String message) { Exception e; try { throw new Exception(); } catch (Exception ex) { e = ex; } StackTraceElement[] trace = e.getStackTrace(); System.err.println( "[***TODO***] - " + trace[1].getClassName() + ":" + trace[1].getLineNumber() + " - " + message); } /** * Print some temporary debug to {@link System#err}, including the current * class and line number call was made along with a specified message. * <p> * Use for temporary debug. Calling statement should be removed. * </p> * * @param message message to display */ public static void removeMe(String message) { Exception e; try { throw new Exception(); } catch (Exception ex) { e = ex; } StackTraceElement[] trace = e.getStackTrace(); System.err.println( "[REMOVE-ME] - " + trace[1].getClassName() + ":" + trace[1].getLineNumber() + " - " + message); } /** * This method will replace '&' with "&", '"' with """, '<' with * "<" and '>' with ">". * * @param html html to encode * @return encoded html * @see #decodeHTML(String) */ public static String encodeHTML(String html) { // Does java have a method of doing this? StringBuffer buf = new StringBuffer(); char ch; for (int i = 0; i < html.length(); i++) { ch = html.charAt(i); switch (ch) { case '&': // May be already encoded if (((i + 5) < html.length()) && html.substring(i + 1, i + 5).equals("amp;")) { buf.append(ch); } else { buf.append("&"); } break; case '"': buf.append("""); break; case '<': buf.append("<"); break; case '>': buf.append(">"); break; default: buf.append(ch); } } return buf.toString(); } /** * Decode HTML entities * * @param html encoded html * @return decoded html * @see #encodeHTML(String) */ public static String decodeHTML(String html) { // Does java have a method of doing this? StringBuffer buf = new StringBuffer(); char ch; for (int i = 0; i < html.length(); i++) { ch = html.charAt(i); switch (ch) { case '&': String s = html.substring(i); if (s.startsWith("&")) { buf.append("&"); i += 4; } else if (s.startsWith(""e;")) { buf.append("\""); i += 6; } else if (s.startsWith("<")) { buf.append("<"); i += 3; } else if (s.startsWith(">")) { buf.append(">"); i += 3; } break; default: buf.append(ch); } } return buf.toString(); } /** * Escape a string so it is suitable for including as a Javascript string. * * @param string string to escape * @param doSingle replace single quotes * @param doDouble replace double quote quotes * @return escaped string */ public static String escapeForJavascriptString(String string, boolean doSingle, boolean doDouble) { if (string == null) { return ""; } string = trimBoth(string); string = string.replaceAll("\\\\", "\\\\\\\\"); if (doSingle) string = string.replaceAll("'", "\\\\'"); if (doDouble) string = string.replaceAll("\"", "\\\\'"); String[] lines = string.split("\n"); StringBuffer buf = new StringBuffer(); for (int i = 0; i < lines.length; i++) { if (buf.length() > 0) { buf.append("<br/>"); } buf.append(trimBoth(lines[i])); } return buf.toString(); } /** * Escape a string so it is suitable for including as a Javascript string. * * @param string * @return escaped string */ public static String escapeForJavascriptString(String string) { return escapeForJavascriptString(string, true, true); } /** * Delete a file or a directory and all of its children. * <p> * <b>Use with care ;-)</b> * * @param file file or directory to delete * @return file or directory deleted ok */ public static boolean delTree(File file) { if (log.isDebugEnabled()) log.debug("Deleting " + file.getAbsolutePath()); if (file.isDirectory()) { File[] f = file.listFiles(); if (f != null) { for (int i = 0; i < f.length; i++) { if (!delTree(f[i])) { return false; } } } } if (!file.delete()) { log.warn("Failed to remove " + file.getAbsolutePath()); return false; } return true; } /** * Trim a string to the specified size, optionally appending elipses (..) if * the string is too large. Eclipses are included in the final size. * Otherwise, the string is simply cut off at its maximum size. * * @param text text * @param size maximum size * @param addElipses add elipses if text to larget * @return trimmed string */ public static String trimToSize(String text, int size, boolean addElipses) { return text.length() <= size ? text : (text.substring(0, size - (addElipses ? (size > 3 ? 3 : size) : 0)) + (addElipses ? " .." : "")); } /** * Encode a url. First UTF-8 is tried, and if that fails US-ASCII. * * @param url url to encode * @return encoded url */ public static String urlEncode(String url) { return urlEncode(url, SystemProperties.get("adito.urlencoding", "UTF-8")); } /** * Encode a url. First UTF-8 is tried, and if that fails US-ASCII. * * @param url url to encode * @param charset the character set to encode with * @return encoded url */ public static String urlEncode(String url, String charset) { try { // W3C recommended return URLEncoder.encode(url, charset); } catch (UnsupportedEncodingException uee) { try { // return URLEncoder.encode(url, "us-ascii"); } catch (UnsupportedEncodingException uee2) { log.error("URL could not be encoded! This should NOT happen!!!"); return url; } } } /** * Decode a url. First UTF-8 is tried, and if that fails US-ASCII. * * @param url url to decode * @return decoded url */ public static String urlDecode(String url) { try { // W3C recommended return URLDecoder.decode(url, SystemProperties.get("adito.urlencoding", "UTF-8")); } catch (UnsupportedEncodingException uee) { try { // return URLDecoder.decode(url, "us-ascii"); } catch (UnsupportedEncodingException uee2) { log.error("URL could not be decoded! This should NOT happen!!!"); return url; } } } /** * Add headers to a response that will prevent compliant clients from * caching. * * @param response response to add appropriate headers to */ public static void noCache(HttpServletResponse response) { response.setHeader("Pragma", "no-cache"); // You cannot use setDateHeader with -1. This actually sets a date // rather than sending Expires: -1 //response.setDateHeader("Expires", new Date().getTime()); //response.setHeader("Expires", "-1"); response.setHeader("Cache-Control", "no-cache"); } /** * Decode a string based on the either the _charset_ request parameter that * may have been suplied with a request or the requests character encoding. * <p> * TODO Make sure this still works and it being used correctly, im not so * sure it is! * * @param request request to get encoding from * @param string string to decode * @return decoded string */ public static String decodeRequestString(HttpServletRequest request, String string) { String enc = request.getParameter("_charset_"); if (enc != null && !enc.equals("ISO-8859-1")) { try { return new String(string.getBytes("ISO-8859-1"), enc); } catch (Exception e) { } } enc = request.getCharacterEncoding(); if (enc != null && !enc.equals("ISO-8859-1")) { try { return new String(string.getBytes("ISO-8859-1"), enc); } catch (Exception e) { } } return string; } /** * Create a {@link Map} from a {@link java.util.List}. The key and value * objects of each entry will be identical. * * @param list list to turn into map * @return map */ public static Map listToHashMapKeys(List list) { HashMap map = new HashMap(); Object k; for (Iterator i = list.iterator(); i.hasNext();) { k = i.next(); map.put(k, k); } return map; } /** * Copy from an input stream to an output stream. It is up to the caller to * close the streams. * * @param in input stream * @param out output stream * @throws IOException on any error */ public static void copy(InputStream in, OutputStream out) throws IOException { copy(in, out, -1); } /** * Copy the specified number of bytes from an input stream to an output * stream. It is up to the caller to close the streams. * * @param in input stream * @param out output stream * @param count number of bytes to copy * @throws IOException on any error */ public static void copy(InputStream in, OutputStream out, long count) throws IOException { copy(in, out, count, BUFFER_SIZE); } /** * Copy the specified number of bytes from an input stream to an output * stream. It is up to the caller to close the streams. * * @param in input stream * @param out output stream * @param count number of bytes to copy * @param bufferSize buffer size * @throws IOException on any error */ public static void copy(InputStream in, OutputStream out, long count, int bufferSize) throws IOException { byte buffer[] = new byte[bufferSize]; int i = bufferSize; if (count >= 0) { while (count > 0) { if (count < bufferSize) i = in.read(buffer, 0, (int) count); else i = in.read(buffer, 0, bufferSize); if (i == -1) break; count -= i; out.write(buffer, 0, i); // LDP - Do not remove this flush! out.flush(); } } else { while (true) { i = in.read(buffer, 0, bufferSize); if (i < 0) break; if (log.isDebugEnabled()) log.debug("Transfered " + i + " bytes"); out.write(buffer, 0, i); // LDP - Do not remove this flush! out.flush(); } } } /** * Copy a file to another file. * * @param f file to copy * @param t target file * @throws IOException on any error */ public static void copy(File f, File t) throws IOException { copy(f, t, false); } /** * Copy a file to another file. * * @param f file to copy * @param t target file * @param onlyIfNewer only copy if the target file is new * @throws IOException on any error */ public static void copy(File f, File t, boolean onlyIfNewer) throws IOException { if (!onlyIfNewer || f.lastModified() > t.lastModified()) { if (log.isDebugEnabled()) log.debug("Copying " + f.getAbsolutePath() + " to " + t.getAbsolutePath()); InputStream in = new FileInputStream(f); try { OutputStream out = new FileOutputStream(t); try { copy(in, out); } finally { out.close(); } } finally { in.close(); } t.setLastModified(f.lastModified()); } else { if (log.isDebugEnabled()) log.debug("Skipping copying of file " + f.getAbsolutePath() + " as the target is newer than the source."); } } /** * Copy a file to a directory. * * @param from file to copy * @param toDir target directory * @param replace replace existing file * @param onlyIfNewer only copy if the target file is new * @throws IOException on any error */ public static void copyToDir(File from, File toDir, boolean replace, boolean onlyIfNewer) throws IOException { if (!toDir.exists()) { throw new IOException("Destination directory " + toDir.getAbsolutePath() + " doesn't exist."); } if (from.isDirectory()) { File toDirDir = new File(toDir, from.getName()); if (toDirDir.exists() && replace) { delTree(toDirDir); } if (!toDirDir.exists()) { if (log.isDebugEnabled()) log.debug("Creating directory " + toDirDir.getAbsolutePath()); if (!toDirDir.mkdirs()) { throw new IOException("Failed to create directory " + toDirDir.getAbsolutePath()); } } File[] f = from.listFiles(); if (f != null) { for (int i = 0; i < f.length; i++) { copyToDir(f[i], toDirDir, replace, onlyIfNewer); } } else { throw new IOException("Failed to list " + from.getAbsolutePath()); } } else if (from.isFile()) { copy(from, new File(toDir, from.getName()), onlyIfNewer); } else { throw new IOException(from.getAbsolutePath() + " is not a plain file or directory."); } } /** * Return an empty string when null passed, otherwise return the string. * * @param string string or null * @return string or empty string */ public static String emptyWhenNull(String string) { return string == null ? "" : string; } /** * Turn a constant name into an english like phrase. E.g. <i>HTTP_ERROR</i> * would be turned into <i>Http Error</i>. * * @param constant constant name * @return readable name */ public static String makeConstantReadable(String constant) { StringBuffer buf = new StringBuffer(); char ch; boolean firstChar = true; for (int i = 0; i < constant.length(); i++) { ch = constant.charAt(i); if (ch == '_') { ch = ' '; firstChar = true; } else { if (firstChar) { ch = Character.toUpperCase(ch); firstChar = false; } else { ch = Character.toLowerCase(ch); } } buf.append(ch); } return buf.toString(); } /** * Turn a key into an english like phrase. E.g. <i>webForwardURL</i> * would be turned into <i>Web Forward URL</i>. * * @param constant constant name * @return readable name */ public static String makeKeyReadable(String constant) { // vFSPath StringBuffer buf = new StringBuffer(); char ch; char lastChar = 0; for (int i = 0; i < constant.length(); i++) { ch = constant.charAt(i); if (i == 0) { ch = Character.toUpperCase(ch); } else { if (Character.isUpperCase(ch)) { if (!Character.isUpperCase(lastChar)) { buf.append(" "); } } } buf.append(ch); lastChar = ch; } return buf.toString(); } /** * Turn a constant like name into an key like structure. E.g. <i>HTTP_ERROR</i> * would be turned into <i>httpError</i>. * * @param constant constant * @return key */ public static String makeConstantKey(String constant) { StringBuffer buf = new StringBuffer(); char ch; boolean firstChar = false; for (int i = 0; i < constant.length(); i++) { ch = constant.charAt(i); if (ch == '_') { firstChar = true; } else { if (firstChar) { ch = Character.toUpperCase(ch); firstChar = false; } else { ch = Character.toLowerCase(ch); } buf.append(ch); } } return buf.toString(); } /** * Re-process the case of a space separated string of words. The first * character is capitalised, all others or lower cased. * * @param unCased uncased string * @return cased string */ public static String reCase(String unCased) { StringBuffer buf = new StringBuffer(); char ch; boolean wordNext = false; for (int i = 0; i < unCased.length(); i++) { ch = unCased.charAt(i); if (ch == ' ') { wordNext = true; } else { if (wordNext) { ch = Character.toUpperCase(ch); wordNext = false; } else { ch = Character.toLowerCase(ch); } buf.append(ch); } } return buf.toString(); } /** * Read from the provided input stream until the buffer is full, blocking if * there are no bytes available until there are. * * @param in input stream * @param buf buffer to read into * @return bytes read * @throws IOException on any error */ public static int readFullyIntoBuffer(InputStream in, byte[] buf) throws IOException { int read; while ((read = in.read(buf)) > -1) { ; } return read; } /** * Parse a simple pattern into a regular expression. Simple expressions * simply support '*' and '?' for 'any characters' and 'single character'. * By simplifying of the pattern may be defeated by starting the string with * a '#' or any exact matched may be specified by starting the string with a * '='. * * @param simplePattern simple pattern * @return regular expression pattern * */ public static String parseSimplePatternToRegExp(String simplePattern) { if (simplePattern.startsWith("#")) { simplePattern = simplePattern.substring(1); } else if (simplePattern.startsWith("=")) { simplePattern = "^" + Util.simplePatternToRegExp(simplePattern.substring(1)) + "$"; } else { simplePattern = "^" + Util.simplePatternToRegExp(simplePattern) + (simplePattern.indexOf('*') == -1 && simplePattern.indexOf('?') == -1 ? ".*" : "") + "$"; } return simplePattern; } /* * Convert a simple pattern into a regular expression. Simple expressions * simply support '*' and '?' for 'any characters' and 'single character'. * * @param simplePattern simple pattern @return regular expression pattern */ static String simplePatternToRegExp(String simplePattern) { int c = simplePattern.length(); char ch; StringBuffer buf = new StringBuffer(); for (int i = 0; i < c; i++) { ch = simplePattern.charAt(i); if (Character.isLetterOrDigit(ch)) { buf.append(ch); } else if (ch == '*') { buf.append(".*"); } else if (ch == '?') { buf.append(".?"); } else { buf.append("\\"); buf.append(ch); } } return buf.toString(); } /** * Get the class path from a class loader (must be an instance * of a {@link java.net.URLClassLoader}. * * @param classLoader * @return class path */ public static String getClassPath(ClassLoader classLoader) { StringBuffer buf = new StringBuffer(); if (classLoader instanceof URLClassLoader) { URLClassLoader urlc = (URLClassLoader) classLoader; URL[] urls = urlc.getURLs(); for (int i = 0; i < urls.length; i++) { if (urls[i].getProtocol().equals("file")) { File f = new File(Util.urlDecode(urls[i].getPath())); if (buf.length() > 0) { buf.append(File.pathSeparator); } buf.append(f.getPath()); } } } return buf.toString(); } /** * Append a string to another string inserting a comma if the original * string is not blank. If the original string is <code>null</code> it will be * treated as if it were blank. The value to append cannot be <code>null</code>. * * @param original original string * @param value string to append * @return new string */ public static String appendToCommaSeparatedList(String original, String value) { if (original == null || original.equals("")) { return value; } return original + "," + value; } /** * Append a string to the value of a system property insert a comma * if the original value is not blank. If the current value of the * original string is <code>null</code> it will be * treated as if it were blank. The value to append cannot be <code>null</code>. * * @param systemPropertyName system property name to append * @param value string to append */ public static void appendToCommaSeparatedSystemProperty(String systemPropertyName, String value) { System.setProperty(systemPropertyName, appendToCommaSeparatedList(SystemProperties.get(systemPropertyName), value)); } /** * Get the simple name of a class. * * @param cls class * @return simple name */ public static String getSimpleClassName(Class cls) { int idx = cls.getName().lastIndexOf("."); return idx == -1 ? cls.getName() : cls.getName().substring(idx + 1); } /** * Split a string into an array taking into account delimiters, quotes and * escapes * * @param str string to split * @param delim delimiter * @param quote quote character * @param escape escape character * @return array */ public static String[] splitString(String str, char delim, char quote, char escape) { Vector v = new Vector(); StringBuffer str1 = new StringBuffer(); char ch = ' '; boolean inQuote = false; boolean escaped = false; for (int i = 0; i < str.length(); i++) { ch = str.charAt(i); if ((escape != -1) && (ch == escape) && !escaped) { escaped = true; } else { if ((quote != -1) && (ch == quote) && !escaped) { inQuote = !inQuote; } else if (!inQuote && (ch == delim && !escaped)) { v.addElement(str1.toString()); str1.setLength(0); } else { str1.append(ch); } if (escaped) { escaped = false; } } } if (str.length() > 0) { v.addElement(str1.toString()); } String[] array; array = new String[v.size()]; v.copyInto(array); return array; } /** * Escape a string suitable for RFC2253. * * @param string * @return escaped string */ public static String escapeForDNString(String string) { char ch; StringBuffer b = new StringBuffer(string.length()); for (int i = 0; i < string.length(); i++) { ch = string.charAt(i); if (ch == ',' || ch == '+' || ch == '"' || ch == '<' || ch == '>' || ch == ';' || ch == '.') { b.append("\\"); b.append(Integer.toHexString(ch)); } else { b.append(ch); } } return b.toString(); } public static boolean checkVersion(String actual, String required) { int[] applicationVersion = getVersion(actual); int[] installedJREVersion = getVersion(required); for (int i = 0; i < applicationVersion.length && i < installedJREVersion.length; i++) { if (applicationVersion[i] < installedJREVersion[i]) return false; } return true; } public static int[] getVersion(String version) { int idx = 0; int pos = 0; int[] result = new int[0]; do { idx = version.indexOf('.', pos); int v; if (idx > -1) { v = Integer.parseInt(version.substring(pos, idx)); pos = idx + 1; } else { try { int sub = version.indexOf('_', pos); if (sub == -1) { sub = version.indexOf('-', pos); } if (sub > -1) { v = Integer.parseInt(version.substring(pos, sub)); } else { v = Integer.parseInt(version.substring(pos)); } } catch (NumberFormatException ex) { // Ignore the exception and return what version we have break; } } int[] tmp = new int[result.length + 1]; System.arraycopy(result, 0, tmp, 0, result.length); tmp[tmp.length - 1] = v; result = tmp; } while (idx > -1); return result; } public static String escapeForRegexpReplacement(String repl) { StringBuffer buf = new StringBuffer(repl.length()); char ch; int len = repl.length(); for (int i = 0; i < len; i++) { ch = repl.charAt(i); if (ch == '\\') { buf.append(ch); } else if (ch == '$') { buf.append('\\'); } buf.append(ch); } return buf.toString(); } /** * Get a day of week constant suitable for use with {@link Calendar} * given an english day day. This may be any case and only the first * 3 characters are tested for (i.e. sun, mon, tue, etc ..) * * @param text * @return day of week */ public static int getDayOfWeekForText(String text) { text = text.toLowerCase(); if (text.startsWith("sun")) { return Calendar.SUNDAY; } else if (text.startsWith("mon")) { return Calendar.MONDAY; } else if (text.startsWith("tue")) { return Calendar.TUESDAY; } else if (text.startsWith("wed")) { return Calendar.WEDNESDAY; } else if (text.startsWith("thu")) { return Calendar.THURSDAY; } else if (text.startsWith("fri")) { return Calendar.FRIDAY; } else if (text.startsWith("sat")) { return Calendar.SATURDAY; } return 0; } /** * Set a value in the system.properties file without destroying the * format. Note, be careful with this, its pretty simple at the moment * and doesn't encode property values. * * @param key key (required) * @param value value or <code>null</code> to comment * @param comment comment to set for new value or <code>null</code> to omit * @throws IOException on any error */ public static void setSystemProperty(String key, String value, String comment) throws IOException { InputStream in = null; OutputStream out = null; File f = new File(ContextHolder.getContext().getConfDirectory(), "system.properties"); File tf = new File(ContextHolder.getContext().getConfDirectory(), "system.properties.tmp"); File of = new File(ContextHolder.getContext().getConfDirectory(), "system.properties.old"); try { in = new FileInputStream(f); out = new FileOutputStream(tf); BufferedReader br = new BufferedReader(new InputStreamReader(in)); PrintWriter pw = new PrintWriter(out); String line = null; boolean found = false; while ((line = br.readLine()) != null) { if (found) { pw.println(line); } else { String trimLine = Util.trimBoth(line); boolean commented = false; int idx = 0; while (idx < trimLine.length() && trimLine.charAt(idx) == '#') { commented = true; idx++; } String tVal = trimLine.substring(idx); if (tVal.startsWith(key + "=")) { found = true; if (commented) { if (value == null) { // leave alone } else { // set value pw.println(key + "=" + value); } } else { if (value == null) { // comment pw.println("#" + line); } else { // set value pw.println(key + "=" + value); } } } else { pw.println(line); } trimLine.startsWith("#"); } } if (!found) { if (comment != null) { pw.println(); pw.println(comment); } pw.println(key + "=" + value); } pw.flush(); } finally { Util.closeStream(in); Util.closeStream(out); } // Move files if (of.exists() && !of.delete()) { log.warn("Failed to delete old backup system properties file"); } copy(f, of); copy(tf, f); if (!tf.delete()) { log.warn("Failed to delete temporary system properties file"); } } /** * Convert an array of objects to a comma separated string (using * each elements {@link Object#toString()} method. * * @param elements * @return as comma separated string */ public static String arrayToCommaSeparatedList(Object[] elements) { StringBuffer buf = new StringBuffer(); for (int i = 0; i < elements.length; i++) { if (i > 0) buf.append(","); buf.append(elements[i].toString()); } return buf.toString(); } /** * @param csv * @return */ public static Map<String, String> toMap(String csv) { return toMap(csv, ","); } /** * @param csv * @param delim * @return */ public static Map<String, String> toMap(String csv, String delim) { Map<String, String> values = new HashMap<String, String>(); for (StringTokenizer tokenizer = new StringTokenizer(csv, delim); tokenizer.hasMoreTokens();) { String token = tokenizer.nextToken(); int indexOfEquals = token.indexOf('='); int indexAfterEquals = indexOfEquals + 1; if (indexOfEquals != -1 && indexAfterEquals < token.length()) { String key = token.substring(0, indexOfEquals); String value = token.substring(indexAfterEquals, token.length()); values.put(key, value); } } return values; } /** * Test if a string is <code>null</code> if it is an * empty string when trimmed. * * @param string * @return null or trimmed blank string */ public static boolean isNullOrTrimmedBlank(String string) { return string == null || string.trim().length() == 0; } /** * Return a trimmed string regardless of whether the * source string is <code>null</code> (in which case an * empty string will be retuned). * * @param string * @return trimmed or blank string */ public static String trimmedOrBlank(String string) { return string == null ? "" : string.trim(); } /** * Return a trimmed string (both ends) regardless of whether the * source string is <code>null</code> (in which case an * empty string will be retuned). * * @param string * @return trimmed or blank string */ public static String trimmedBothOrBlank(String string) { return trimBoth(string == null ? "" : string.trim()); } /** * Attempt to make a file executable. Only current works on * systems that have the <b>chmod</b> command available. * * @param binLocation * @throws IOException on any error */ public static void makeExecutable(File binLocation) throws IOException { Process p = Runtime.getRuntime().exec(new String[] { "chmod", "ug+rx", binLocation.getAbsolutePath() }); try { copy(p.getErrorStream(), new ByteArrayOutputStream()); } finally { try { if (p.waitFor() != 0) { throw new IOException("Failed to set execute permission. Return code " + p.exitValue() + "."); } } catch (InterruptedException e) { } } } }