/* * Utils.java * * Created on May 19, 2007, 10:19:18 PM * * this class provides a number of static helper methods * */ package com.pugh.sockso; import com.pugh.sockso.db.Database; import com.pugh.sockso.web.BadRequestException; import org.apache.log4j.Logger; import java.io.BufferedReader; import java.io.File; import java.io.InputStream; import java.io.OutputStream; import java.io.UnsupportedEncodingException; import java.io.Writer; import java.net.InetAddress; import java.net.URLDecoder; import java.net.URLEncoder; import java.net.UnknownHostException; import java.security.MessageDigest; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Random; import java.util.regex.Matcher; import java.util.regex.Pattern; public class Utils { private static final Logger log = Logger.getLogger( Utils.class ); private static String APPLICATION_DIRECTORY; static { setApplicationDirectory( new File(System.getProperty("user.home") + File.separator + ".sockso") ); } /** * sets the application directory to use (this should probably ONLY be * done on startup, doing so after this could be bad...) * * @param directory * */ public static void setApplicationDirectory( final File directory ) { APPLICATION_DIRECTORY = directory.getAbsolutePath(); } /** * returns the absolute path to the application directory * * @return * */ public static String getApplicationDirectory() { return APPLICATION_DIRECTORY; } /** * returns the absolute path to the covers directory * * @return * */ public static String getCoversDirectory() { return APPLICATION_DIRECTORY + File.separator + Constants.COVERS_DIR; } /** * returns the extension for a file in lowercase * * @param file the file to get the extension for * @return the file's extension * */ public static String getExt( final File file ) { return getExt( file.getName() ); } /** * returns the extension for a filename in lowercase * * @param name the name/path of the file to get the extension for * @return the file's extension * */ public static String getExt( final String name ) { return name.substring( name.lastIndexOf(".") + 1 ).toLowerCase(); } /** * returns a random string of characters (A-Z) of the specified length * * @param length the length of the string * @return random string * */ public static String getRandomString( final int length ) { final StringBuffer sb = new StringBuffer(); final Random rand = new Random(); for ( int i=0; i<length; i++ ) sb.append( (char) ((Math.abs(rand.nextInt()) % 26) + 65) ); return sb.toString(); } /** * Close a Writer impl catching any errors * * @param out * */ public static void close( final OutputStream out ) { if ( out != null ) { try { out.close(); } catch ( final Exception e ) { log.error( "Error closing output stream: " +e.getMessage() ); } } } /** * closes an sql statement and handles any errors that may occur * * @param s the statement to close * */ public static void close( final Statement s ) { if ( s == null ) return; try { s.close(); } catch ( final Exception e ) { log.error( "Error closing statement: " + e.getMessage() ); } } /** * closes an sql result set and handles any errors that may occur * * @param rs the result set to close * */ public static void close( final ResultSet rs ) { if ( rs == null ) return; try { rs.close(); } catch ( final Exception e ) { e.printStackTrace(); log.error( "Error closing result set: " + e.getMessage() ); } } /** * closes an input stream and handles any errors that may occur * * @param s the input stream to close * */ public static void close( final InputStream s ) { if ( s == null ) return; try { s.close(); } catch ( final Exception e ) { log.error( "Error closing input stream: " + e.getMessage() ); } } /** * closes an output stream and handles any errors that may occur * * @param s the input stream to close * */ public static void close( final Writer s ) { if ( s == null ) return; try { s.close(); } catch ( final Exception e ) { log.error( "Error closing output stream: " + e.getMessage() ); } } /** * closes a buffered reader and handles any errors that may occur * * @param s the buffered reader to close * */ public static void close( final BufferedReader s ) { if ( s == null ) return; try { s.close(); } catch ( final Exception e ) { log.error( "Error closing buffered reader: " + e.getMessage() ); } } /** * url encodes a string, if an error is encountered then * you'll get the empty string back * * @TODO - refactor into WebObject class? * * @param string the string to encode * @return the encoded string * */ public static String URLEncode( final String string ) { try { return URLEncoder.encode( string, Constants.URL_CHAR_ENCODING ); } catch ( final UnsupportedEncodingException e ) { log.error( e.getMessage() ); } return ""; } /** * decodes an url encoded string, if an error is encountered then * you'll get the empty string back * * @TODO - refactor into WebObject class? * * @param string the string to decode * @return the decoded string * */ public static String URLDecode( final String string ) { try { return URLDecoder.decode( string, Constants.URL_CHAR_ENCODING ); } catch ( final UnsupportedEncodingException e ) { log.error( e.getMessage() ); } return ""; } /** * tries to get the local ip address * * @TODO - static callout smells of badness... * * @return local ip * * @throws UnknownHostException * */ public static String getLocalIp() throws UnknownHostException { return InetAddress.getLocalHost().getHostAddress(); } /** * creates an md5 hash of a string * * @param text the string to hash * @return hash * */ public static String md5( final String text ) { try { final MessageDigest md = MessageDigest.getInstance("MD5"); md.update(text.getBytes("iso-8859-1"), 0, text.length()); byte[] md5hash = md.digest(); return convertToHex(md5hash); } catch ( final Exception e ) {} return null; } private static String convertToHex(byte[] data) { final StringBuffer buf = new StringBuffer(); for (int i = 0; i < data.length; i++) { int halfbyte = (data[i] >>> 4) & 0x0F; int two_halfs = 0; do { if ((0 <= halfbyte) && (halfbyte <= 9)) buf.append((char) ('0' + halfbyte)); else buf.append((char) ('a' + (halfbyte - 10))); halfbyte = data[i] & 0x0F; } while(two_halfs++ < 1); } return buf.toString(); } /** * formats a date object to a nice format * * @param date the date to format * @return a nicely formatted date * */ public static String formatDate( final Date date ) { final SimpleDateFormat formatter = new SimpleDateFormat( "EEE MMM dd, yyyy" ); return formatter.format( date ); } /** * returns the path to the uploads directory if it is set, "" otherwise * * @return path to directory, "" if not set * */ public static String getUploadsPath( final Database db, final Properties p ) { PreparedStatement st = null; ResultSet rs = null; try { final String strCollId = p.get( Constants.WWW_UPLOADS_COLLECTION_ID ).trim(); if ( strCollId.matches("^\\d+$") ) { final int uploadsCollId = Integer.parseInt( strCollId ); final String sql = " select path " + " from collection " + " where id = ? " + " limit 1 "; st = db.prepare( sql ); st.setInt( 1, uploadsCollId ); rs = st.executeQuery(); if ( rs.next() ) return rs.getString( "path" ); } } catch ( final SQLException e ) { log.error( e ); } catch ( final NumberFormatException e ) { log.debug( "No valid uploads collection ID defined: " +e ); } finally { Utils.close( rs ); Utils.close( st ); } return ""; } /** * encodes a value for safe use in XML * * @param value * @return * */ public static String XMLEncode( final String value ) { String newValue = value.toString(); final String[] reps = new String[] { "&", "&", "<", "<", ">", ">", "\"", """, "'", "'" }; for ( int i=0; i<reps.length; i+=2 ) newValue = newValue.replace( reps[i], reps[i+1] ); return newValue; } /** * returns a path with the current systems trailing slash at the end * * @param file * * @return path with trailing slash * */ public static String getPathWithSlash( final File file ) { return getPathWithSlash( file.getAbsolutePath() ); } /** * returns a path with the current systems trailing slash at the end * * @param path * * @return path with trailing slash * */ public static String getPathWithSlash( final String path ) { final String separator = System.getProperty( "file.separator" ); return getPathWithSlash( path, separator ); } /** * returns a path with the current systems trailing slash at the end, * using the separator as the one for this system. * * NB! This is here to aid unit testing, you should let the other functions * work out the system path separator and stuff... * * @param path * @param separator * * @return path with trailing slash * */ protected static String getPathWithSlash( final String path, final String separator ) { return ( !path.matches(".*\\" +separator+ "$") ) ? path + separator : path; } /** * escapes a javascript string for use in a literal (ie. escapes single * quotes and backslashes in the string) * * @param str * @return * */ public static String escapeJs( final String str ) { return str .replaceAll( "\\\\", "\\\\\\\\" ) // 1. backslashes .replaceAll("'","\\\\'"); // 2. single quotes } /** * checks that a property is set, marking a feature as being enabled * * @param p Properties object * @param property feature enabling property * * @throws BadRequestException * */ public static void checkFeatureEnabled( final Properties p, final String property ) throws BadRequestException { if ( !isFeatureEnabled(p,property) ) throw new BadRequestException( "feature not enabled", 403 ); } /** * checks if a feature is enabled, returns true if it is, false otherwise * * @param p * @param property * * @return boolean * */ public static boolean isFeatureEnabled( final Properties p, final String property ) { return p.get( property ).equals( Properties.YES ); } /** * a method to do a CASE INSENSITIVE regex search-replace * * @param regex * @param replaceWith * @param subject * */ public static String replaceAll( final String regex, final String replaceWith, final String subject ) { final Pattern p = Pattern.compile( regex, Pattern.CASE_INSENSITIVE ); final Matcher m = p.matcher( subject ); return m.replaceAll( replaceWith ); } /** * u2e = unicode to entities * * converts any unicode characters in a string to their numeric entity * */ public static String u2e( final String orig ) { final int length = orig.length(); final StringBuffer buffer = new StringBuffer( length * 2 ); for ( int i = 0; i < length; i++ ) { char c = orig.charAt(i); int code = c; buffer.append( code < 0x80 ? c : "&#" +( (int) c )+';' ); } return buffer.toString(); } /** * Takes an array of strings and joins them using the specified glue. * * @param array * @param glue * @param start * @param end * * @return * */ public static String joinArray( final String[] array, final String glue, final int start, final int end ) { final StringBuffer sb = new StringBuffer(); for ( int i=start; i<=end; i++ ) { if ( i > start ) { sb.append( glue ); } sb.append( array[i] ); } return sb.toString(); } }