changeset 853:3242aff51053

remove RolloverFileOutputStream and cleanup NCSARequestLog
author Franklin Schmidt <fschmidt@gmail.com>
date Tue, 20 Sep 2016 00:23:56 -0600
parents b462b4ff22d8
children 359012f4e797
files src/org/eclipse/jetty/server/NCSARequestLog.java src/org/eclipse/jetty/util/RolloverFileOutputStream.java src/org/eclipse/jetty/util/StringUtil.java
diffstat 3 files changed, 457 insertions(+), 894 deletions(-) [+]
line wrap: on
line diff
--- a/src/org/eclipse/jetty/server/NCSARequestLog.java	Mon Sep 19 20:08:16 2016 -0600
+++ b/src/org/eclipse/jetty/server/NCSARequestLog.java	Tue Sep 20 00:23:56 2016 -0600
@@ -22,6 +22,8 @@
 import java.io.OutputStream;
 import java.io.OutputStreamWriter;
 import java.io.Writer;
+import java.io.File;
+import java.io.FileOutputStream;
 import java.util.Locale;
 import java.util.TimeZone;
 
@@ -29,8 +31,6 @@
 
 import org.eclipse.jetty.http.HttpHeaders;
 import org.eclipse.jetty.util.DateCache;
-import org.eclipse.jetty.util.RolloverFileOutputStream;
-import org.eclipse.jetty.util.StringUtil;
 import org.eclipse.jetty.util.component.AbstractLifeCycle;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -52,23 +52,15 @@
 public class NCSARequestLog extends AbstractLifeCycle implements RequestLog
 {
 	private static final Logger LOG = LoggerFactory.getLogger(NCSARequestLog.class);
-	private static ThreadLocal<StringBuilder> _buffers = new ThreadLocal<StringBuilder>()
-			{
-				@Override
-				protected StringBuilder initialValue()
-				{
-					return new StringBuilder(256);
-				}
-			};
+    private static final String __LINE_SEPARATOR=
+        System.getProperty("line.separator","\n");
 
 	private String _filename;
 	private boolean _extended;
-	private boolean _append;
-	private int _retainDays;
+	public long sizeLimit = 1048576L;
 	private boolean _closeOut;
 	private boolean _preferProxiedForAddress;
 	private String _logDateFormat = "dd/MMM/yyyy:HH:mm:ss Z";
-	private String _filenameDateFormat = null;
 	private Locale _logLocale = Locale.getDefault();
 	private String _logTimeZone = "GMT";
 	private boolean _logLatency = false;
@@ -77,7 +69,6 @@
 	private boolean _logDispatch = false;
 
 	private transient OutputStream _out;
-	private transient OutputStream _fileOut;
 	private transient DateCache _logDateCache;
 	private transient Writer _writer;
 
@@ -88,8 +79,6 @@
 	public NCSARequestLog()
 	{
 		_extended = true;
-		_append = true;
-		_retainDays = 31;
 	}
 
 	/* ------------------------------------------------------------ */
@@ -103,8 +92,6 @@
 	public NCSARequestLog(String filename)
 	{
 		_extended = true;
-		_append = true;
-		_retainDays = 31;
 		setFilename(filename);
 	}
 
@@ -141,21 +128,6 @@
 
 	/* ------------------------------------------------------------ */
 	/**
-	 * Retrieve the file name of the request log with the expanded
-	 * date wildcard if the output is written to the disk using
-	 * {@link RolloverFileOutputStream}.
-	 * 
-	 * @return file name of the request log, or null if not applicable
-	 */
-	public String getDatedFilename()
-	{
-		if (_fileOut instanceof RolloverFileOutputStream)
-			return ((RolloverFileOutputStream)_fileOut).getDatedFilename();
-		return null;
-	}
-
-	/* ------------------------------------------------------------ */
-	/**
 	 * Set the timestamp format for request log entries in the file.
 	 * If this is not set, the pre-formated request timestamp is used.
 	 * 
@@ -223,28 +195,6 @@
 
 	/* ------------------------------------------------------------ */
 	/**
-	 * Set the number of days before rotated log files are deleted.
-	 * 
-	 * @param retainDays number of days to keep a log file
-	 */
-	public void setRetainDays(int retainDays)
-	{
-		_retainDays = retainDays;
-	}
-
-	/* ------------------------------------------------------------ */
-	/**
-	 * Retrieve the number of days before rotated log files are deleted.
-	 * 
-	 * @return number of days to keep a log file
-	 */
-	public int getRetainDays()
-	{
-		return _retainDays;
-	}
-
-	/* ------------------------------------------------------------ */
-	/**
 	 * Set the extended request log format flag.
 	 * 
 	 * @param extended true - log the extended request information,
@@ -268,29 +218,6 @@
 
 	/* ------------------------------------------------------------ */
 	/**
-	 * Set append to log flag.
-	 * 
-	 * @param append true - request log file will be appended after restart,
-	 *               false - request log file will be overwritten after restart
-	 */
-	public void setAppend(boolean append)
-	{
-		_append = append;
-	}
-
-	/* ------------------------------------------------------------ */
-	/**
-	 * Retrieve append to log flag.
-	 * 
-	 * @return value of the flag
-	 */
-	public boolean isAppend()
-	{
-		return _append;
-	}
-
-	/* ------------------------------------------------------------ */
-	/**
 	 * Controls logging of the request cookies.
 	 * 
 	 * @param logCookies true - values of request cookies will be logged,
@@ -383,29 +310,6 @@
 	}
 
 	/* ------------------------------------------------------------ */
-	/**
-	 * Set the log file name date format.
-	 * @see RolloverFileOutputStream#RolloverFileOutputStream(String, boolean, int, TimeZone, String, String)
-	 * 
-	 * @param logFileDateFormat format string that is passed to {@link RolloverFileOutputStream}
-	 */
-	public void setFilenameDateFormat(String logFileDateFormat)
-	{
-		_filenameDateFormat = logFileDateFormat;
-	}
-
-	/* ------------------------------------------------------------ */
-	/**
-	 * Retrieve the file name date format string.
-	 * 
-	 * @return the log File Date Format
-	 */
-	public String getFilenameDateFormat()
-	{
-		return _filenameDateFormat;
-	}
-
-	/* ------------------------------------------------------------ */
 	/** 
 	 * Controls logging of the request dispatch time
 	 * 
@@ -438,11 +342,10 @@
 	{
 		try
 		{
-			if (_fileOut == null)
+			if (_out == null)
 				return;
 
-			StringBuilder buf= _buffers.get();
-			buf.setLength(0);
+			StringBuilder buf = new StringBuilder(256);
 
 			if (_logServer)
 			{
@@ -552,7 +455,7 @@
 				}
 			}
 
-			buf.append(StringUtil.__LINE_SEPARATOR);
+			buf.append(__LINE_SEPARATOR);
 			
 			String log = buf.toString();
 			write(log);
@@ -625,16 +528,19 @@
 			_logDateCache.setTimeZoneID(_logTimeZone);
 		}
 
-		if (_filename != null)
-		{
-			_fileOut = new RolloverFileOutputStream(_filename,_append,_retainDays,TimeZone.getTimeZone(_logTimeZone),_filenameDateFormat,null);
+		if (_filename != null) {
+			File file = new File(_filename);
+			if( file.exists() && file.length() > sizeLimit ) {
+				File old = new File(_filename+".old");
+				old.delete();
+				file.renameTo(old);
+			}
+			_out = new FileOutputStream(file,true);
 			_closeOut = true;
-			LOG.info("Opened " + getDatedFilename());
+			LOG.info("Opened " + _filename);
 		}
 		else
-			_fileOut = System.err;
-
-		_out = _fileOut;
+			_out = System.err;
 
 		synchronized(this)
 		{
@@ -664,7 +570,7 @@
 			{
 				LOG.trace("",e);
 			}
-			if (_out != null && _closeOut)
+			if (_closeOut)
 				try
 				{
 					_out.close();
@@ -675,7 +581,6 @@
 				}
 
 			_out = null;
-			_fileOut = null;
 			_closeOut = false;
 			_logDateCache = null;
 			_writer = null;
--- a/src/org/eclipse/jetty/util/RolloverFileOutputStream.java	Mon Sep 19 20:08:16 2016 -0600
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,340 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.util; 
-
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.FilterOutputStream;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.text.SimpleDateFormat;
-import java.util.Calendar;
-import java.util.Date;
-import java.util.GregorianCalendar;
-import java.util.Locale;
-import java.util.TimeZone;
-import java.util.Timer;
-import java.util.TimerTask;
-
-/** 
- * RolloverFileOutputStream
- * 
- * This output stream puts content in a file that is rolled over every 24 hours.
- * The filename must include the string "yyyy_mm_dd", which is replaced with the 
- * actual date when creating and rolling over the file.
- * 
- * Old files are retained for a number of days before being deleted.
- * 
- * 
- */
-public class RolloverFileOutputStream extends FilterOutputStream
-{
-    private static Timer __rollover;
-    
-    final static String YYYY_MM_DD="yyyy_mm_dd";
-    final static String ROLLOVER_FILE_DATE_FORMAT = "yyyy_MM_dd";
-    final static String ROLLOVER_FILE_BACKUP_FORMAT = "HHmmssSSS";
-    final static int ROLLOVER_FILE_RETAIN_DAYS = 31;
-
-    private RollTask _rollTask;
-    private SimpleDateFormat _fileBackupFormat;
-    private SimpleDateFormat _fileDateFormat;
-
-    private String _filename;
-    private File _file;
-    private boolean _append;
-    private int _retainDays;
-    
-    /* ------------------------------------------------------------ */
-    /**
-     * @param filename The filename must include the string "yyyy_mm_dd", 
-     * which is replaced with the actual date when creating and rolling over the file.
-     * @throws IOException
-     */
-    public RolloverFileOutputStream(String filename)
-        throws IOException
-    {
-        this(filename,true,ROLLOVER_FILE_RETAIN_DAYS);
-    }
-    
-    /* ------------------------------------------------------------ */
-    /**
-     * @param filename The filename must include the string "yyyy_mm_dd", 
-     * which is replaced with the actual date when creating and rolling over the file.
-     * @param append If true, existing files will be appended to.
-     * @throws IOException
-     */
-    public RolloverFileOutputStream(String filename, boolean append)
-        throws IOException
-    {
-        this(filename,append,ROLLOVER_FILE_RETAIN_DAYS);
-    }
-
-    /* ------------------------------------------------------------ */
-    /**
-     * @param filename The filename must include the string "yyyy_mm_dd", 
-     * which is replaced with the actual date when creating and rolling over the file.
-     * @param append If true, existing files will be appended to.
-     * @param retainDays The number of days to retain files before deleting them.  0 to retain forever.
-     * @throws IOException
-     */
-    public RolloverFileOutputStream(String filename,
-                                    boolean append,
-                                    int retainDays)
-        throws IOException
-    {
-        this(filename,append,retainDays,TimeZone.getDefault());
-    }
-
-    /* ------------------------------------------------------------ */
-    /**
-     * @param filename The filename must include the string "yyyy_mm_dd", 
-     * which is replaced with the actual date when creating and rolling over the file.
-     * @param append If true, existing files will be appended to.
-     * @param retainDays The number of days to retain files before deleting them. 0 to retain forever.
-     * @throws IOException
-     */
-    public RolloverFileOutputStream(String filename,
-                                    boolean append,
-                                    int retainDays,
-                                    TimeZone zone)
-        throws IOException
-    {
-
-         this(filename,append,retainDays,zone,null,null);
-    }
-     
-    /* ------------------------------------------------------------ */
-    /**
-     * @param filename The filename must include the string "yyyy_mm_dd", 
-     * which is replaced with the actual date when creating and rolling over the file.
-     * @param append If true, existing files will be appended to.
-     * @param retainDays The number of days to retain files before deleting them. 0 to retain forever.
-     * @param dateFormat The format for the date file substitution. The default is "yyyy_MM_dd". 
-     * @param backupFormat The format for the file extension of backup files. The default is "HHmmssSSS". 
-     * @throws IOException
-     */
-    public RolloverFileOutputStream(String filename,
-                                    boolean append,
-                                    int retainDays,
-                                    TimeZone zone,
-                                    String dateFormat,
-                                    String backupFormat)
-        throws IOException
-    {
-        super(null);
-
-        if (dateFormat==null)
-            dateFormat=ROLLOVER_FILE_DATE_FORMAT;
-        _fileDateFormat = new SimpleDateFormat(dateFormat);
-        
-        if (backupFormat==null)
-            backupFormat=ROLLOVER_FILE_BACKUP_FORMAT;
-        _fileBackupFormat = new SimpleDateFormat(backupFormat);
-        
-        _fileBackupFormat.setTimeZone(zone);
-        _fileDateFormat.setTimeZone(zone);
-        
-        if (filename!=null)
-        {
-            filename=filename.trim();
-            if (filename.length()==0)
-                filename=null;
-        }
-        if (filename==null)
-            throw new IllegalArgumentException("Invalid filename");
-
-        _filename=filename;
-        _append=append;
-        _retainDays=retainDays;
-        setFile();
-        
-        synchronized(RolloverFileOutputStream.class)
-        {
-            if (__rollover==null)
-                __rollover=new Timer(RolloverFileOutputStream.class.getName(),true);
-            
-            _rollTask=new RollTask();
-
-             Calendar now = Calendar.getInstance();
-             now.setTimeZone(zone);
-
-             GregorianCalendar midnight =
-                 new GregorianCalendar(now.get(Calendar.YEAR),
-                         now.get(Calendar.MONTH),
-                         now.get(Calendar.DAY_OF_MONTH),
-                         23,0);
-             midnight.setTimeZone(zone);
-             midnight.add(Calendar.HOUR,1);
-             __rollover.scheduleAtFixedRate(_rollTask,midnight.getTime(),1000L*60*60*24);
-        }
-    }
-
-    /* ------------------------------------------------------------ */
-    public String getFilename()
-    {
-        return _filename;
-    }
-    
-    /* ------------------------------------------------------------ */
-    public String getDatedFilename()
-    {
-        if (_file==null)
-            return null;
-        return _file.toString();
-    }
-    
-    /* ------------------------------------------------------------ */
-    public int getRetainDays()
-    {
-        return _retainDays;
-    }
-
-    /* ------------------------------------------------------------ */
-    private synchronized void setFile()
-        throws IOException
-    {
-        // Check directory
-        File file = new File(_filename);
-        _filename=file.getCanonicalPath();
-        file=new File(_filename);
-        File dir= new File(file.getParent());
-        if (!dir.isDirectory() || !dir.canWrite())
-            throw new IOException("Cannot write log directory "+dir);
-            
-        Date now=new Date();
-        
-        // Is this a rollover file?
-        String filename=file.getName();
-        int i=filename.toLowerCase(Locale.ENGLISH).indexOf(YYYY_MM_DD);
-        if (i>=0)
-        {
-            file=new File(dir,
-                          filename.substring(0,i)+
-                          _fileDateFormat.format(now)+
-                          filename.substring(i+YYYY_MM_DD.length()));
-        }
-            
-        if (file.exists()&&!file.canWrite())
-            throw new IOException("Cannot write log file "+file);
-
-        // Do we need to change the output stream?
-        if (out==null || !file.equals(_file))
-        {
-            // Yep
-            _file=file;
-            if (!_append && file.exists())
-                file.renameTo(new File(file.toString()+"."+_fileBackupFormat.format(now)));
-            OutputStream oldOut=out;
-            out=new FileOutputStream(file.toString(),_append);
-            if (oldOut!=null)
-                oldOut.close();
-            //if(log.isDebugEnabled())log.debug("Opened "+_file);
-        }
-    }
-
-    /* ------------------------------------------------------------ */
-    private void removeOldFiles()
-    {
-        if (_retainDays>0)
-        {
-            long now = System.currentTimeMillis();
-            
-            File file= new File(_filename);
-            File dir = new File(file.getParent());
-            String fn=file.getName();
-            int s=fn.toLowerCase(Locale.ENGLISH).indexOf(YYYY_MM_DD);
-            if (s<0)
-                return;
-            String prefix=fn.substring(0,s);
-            String suffix=fn.substring(s+YYYY_MM_DD.length());
-
-            String[] logList=dir.list();
-            for (int i=0;i<logList.length;i++)
-            {
-                fn = logList[i];
-                if(fn.startsWith(prefix)&&fn.indexOf(suffix,prefix.length())>=0)
-                {        
-                    File f = new File(dir,fn);
-                    long date = f.lastModified();
-                    if ( ((now-date)/(1000*60*60*24))>_retainDays)
-                        f.delete();   
-                }
-            }
-        }
-    }
-
-    /* ------------------------------------------------------------ */
-    @Override
-    public void write (byte[] buf)
-            throws IOException
-     {
-            out.write (buf);
-     }
-
-    /* ------------------------------------------------------------ */
-    @Override
-    public void write (byte[] buf, int off, int len)
-            throws IOException
-     {
-            out.write (buf, off, len);
-     }
-    
-    /* ------------------------------------------------------------ */
-    /** 
-     */
-    @Override
-    public void close()
-        throws IOException
-    {
-        synchronized(RolloverFileOutputStream.class)
-        {
-            try{super.close();}
-            finally
-            {
-                out=null;
-                _file=null;
-            }
-
-            _rollTask.cancel(); 
-        }
-    }
-    
-    /* ------------------------------------------------------------ */
-    /* ------------------------------------------------------------ */
-    /* ------------------------------------------------------------ */
-    private class RollTask extends TimerTask
-    {
-        @Override
-        public void run()
-        {
-            try
-            {
-                RolloverFileOutputStream.this.setFile();
-                RolloverFileOutputStream.this.removeOldFiles();
-
-            }
-            catch(IOException e)
-            {
-                // Cannot log this exception to a LOG, as RolloverFOS can be used by logging
-                e.printStackTrace();
-            }
-        }
-    }
-}
--- a/src/org/eclipse/jetty/util/StringUtil.java	Mon Sep 19 20:08:16 2016 -0600
+++ b/src/org/eclipse/jetty/util/StringUtil.java	Tue Sep 20 00:23:56 2016 -0600
@@ -35,470 +35,468 @@
  */
 public class StringUtil
 {
-    private static final Logger LOG = LoggerFactory.getLogger(StringUtil.class);
-    
-    public static final String ALL_INTERFACES="0.0.0.0";
-    public static final String CRLF="\015\012";
-    public static final String __LINE_SEPARATOR=
-        System.getProperty("line.separator","\n");
-       
-    public static final String __ISO_8859_1="ISO-8859-1";
-    public final static String __UTF8="UTF-8";
-    public final static String __UTF8Alt="UTF8";
-    public final static String __UTF16="UTF-16";
-    
-    public final static Charset __UTF8_CHARSET;
-    public final static Charset __ISO_8859_1_CHARSET;
-    
-    static
-    {
-        __UTF8_CHARSET=Charset.forName(__UTF8);
-        __ISO_8859_1_CHARSET=Charset.forName(__ISO_8859_1);
-    }
-    
-    private static char[] lowercases = {
-          '\000','\001','\002','\003','\004','\005','\006','\007',
-          '\010','\011','\012','\013','\014','\015','\016','\017',
-          '\020','\021','\022','\023','\024','\025','\026','\027',
-          '\030','\031','\032','\033','\034','\035','\036','\037',
-          '\040','\041','\042','\043','\044','\045','\046','\047',
-          '\050','\051','\052','\053','\054','\055','\056','\057',
-          '\060','\061','\062','\063','\064','\065','\066','\067',
-          '\070','\071','\072','\073','\074','\075','\076','\077',
-          '\100','\141','\142','\143','\144','\145','\146','\147',
-          '\150','\151','\152','\153','\154','\155','\156','\157',
-          '\160','\161','\162','\163','\164','\165','\166','\167',
-          '\170','\171','\172','\133','\134','\135','\136','\137',
-          '\140','\141','\142','\143','\144','\145','\146','\147',
-          '\150','\151','\152','\153','\154','\155','\156','\157',
-          '\160','\161','\162','\163','\164','\165','\166','\167',
-          '\170','\171','\172','\173','\174','\175','\176','\177' };
+	private static final Logger LOG = LoggerFactory.getLogger(StringUtil.class);
+	
+	public static final String ALL_INTERFACES="0.0.0.0";
+	public static final String CRLF="\015\012";
+	   
+	public static final String __ISO_8859_1="ISO-8859-1";
+	public final static String __UTF8="UTF-8";
+	public final static String __UTF8Alt="UTF8";
+	public final static String __UTF16="UTF-16";
+	
+	public final static Charset __UTF8_CHARSET;
+	public final static Charset __ISO_8859_1_CHARSET;
+	
+	static
+	{
+		__UTF8_CHARSET=Charset.forName(__UTF8);
+		__ISO_8859_1_CHARSET=Charset.forName(__ISO_8859_1);
+	}
+	
+	private static char[] lowercases = {
+		  '\000','\001','\002','\003','\004','\005','\006','\007',
+		  '\010','\011','\012','\013','\014','\015','\016','\017',
+		  '\020','\021','\022','\023','\024','\025','\026','\027',
+		  '\030','\031','\032','\033','\034','\035','\036','\037',
+		  '\040','\041','\042','\043','\044','\045','\046','\047',
+		  '\050','\051','\052','\053','\054','\055','\056','\057',
+		  '\060','\061','\062','\063','\064','\065','\066','\067',
+		  '\070','\071','\072','\073','\074','\075','\076','\077',
+		  '\100','\141','\142','\143','\144','\145','\146','\147',
+		  '\150','\151','\152','\153','\154','\155','\156','\157',
+		  '\160','\161','\162','\163','\164','\165','\166','\167',
+		  '\170','\171','\172','\133','\134','\135','\136','\137',
+		  '\140','\141','\142','\143','\144','\145','\146','\147',
+		  '\150','\151','\152','\153','\154','\155','\156','\157',
+		  '\160','\161','\162','\163','\164','\165','\166','\167',
+		  '\170','\171','\172','\173','\174','\175','\176','\177' };
 
-    /* ------------------------------------------------------------ */
-    /**
-     * fast lower case conversion. Only works on ascii (not unicode)
-     * @param s the string to convert
-     * @return a lower case version of s
-     */
-    public static String asciiToLowerCase(String s)
-    {
-        char[] c = null;
-        int i=s.length();
+	/* ------------------------------------------------------------ */
+	/**
+	 * fast lower case conversion. Only works on ascii (not unicode)
+	 * @param s the string to convert
+	 * @return a lower case version of s
+	 */
+	public static String asciiToLowerCase(String s)
+	{
+		char[] c = null;
+		int i=s.length();
 
-        // look for first conversion
-        while (i-->0)
-        {
-            char c1=s.charAt(i);
-            if (c1<=127)
-            {
-                char c2=lowercases[c1];
-                if (c1!=c2)
-                {
-                    c=s.toCharArray();
-                    c[i]=c2;
-                    break;
-                }
-            }
-        }
+		// look for first conversion
+		while (i-->0)
+		{
+			char c1=s.charAt(i);
+			if (c1<=127)
+			{
+				char c2=lowercases[c1];
+				if (c1!=c2)
+				{
+					c=s.toCharArray();
+					c[i]=c2;
+					break;
+				}
+			}
+		}
 
-        while (i-->0)
-        {
-            if(c[i]<=127)
-                c[i] = lowercases[c[i]];
-        }
-        
-        return c==null?s:new String(c);
-    }
+		while (i-->0)
+		{
+			if(c[i]<=127)
+				c[i] = lowercases[c[i]];
+		}
+		
+		return c==null?s:new String(c);
+	}
 
 
-    /* ------------------------------------------------------------ */
-    public static boolean startsWithIgnoreCase(String s,String w)
-    {
-        if (w==null)
-            return true;
-        
-        if (s==null || s.length()<w.length())
-            return false;
-        
-        for (int i=0;i<w.length();i++)
-        {
-            char c1=s.charAt(i);
-            char c2=w.charAt(i);
-            if (c1!=c2)
-            {
-                if (c1<=127)
-                    c1=lowercases[c1];
-                if (c2<=127)
-                    c2=lowercases[c2];
-                if (c1!=c2)
-                    return false;
-            }
-        }
-        return true;
-    }
-    
-    /* ------------------------------------------------------------ */
-    public static boolean endsWithIgnoreCase(String s,String w)
-    {
-        if (w==null)
-            return true;
+	/* ------------------------------------------------------------ */
+	public static boolean startsWithIgnoreCase(String s,String w)
+	{
+		if (w==null)
+			return true;
+		
+		if (s==null || s.length()<w.length())
+			return false;
+		
+		for (int i=0;i<w.length();i++)
+		{
+			char c1=s.charAt(i);
+			char c2=w.charAt(i);
+			if (c1!=c2)
+			{
+				if (c1<=127)
+					c1=lowercases[c1];
+				if (c2<=127)
+					c2=lowercases[c2];
+				if (c1!=c2)
+					return false;
+			}
+		}
+		return true;
+	}
+	
+	/* ------------------------------------------------------------ */
+	public static boolean endsWithIgnoreCase(String s,String w)
+	{
+		if (w==null)
+			return true;
 
-        if (s==null)
-            return false;
-            
-        int sl=s.length();
-        int wl=w.length();
-        
-        if (sl<wl)
-            return false;
-        
-        for (int i=wl;i-->0;)
-        {
-            char c1=s.charAt(--sl);
-            char c2=w.charAt(i);
-            if (c1!=c2)
-            {
-                if (c1<=127)
-                    c1=lowercases[c1];
-                if (c2<=127)
-                    c2=lowercases[c2];
-                if (c1!=c2)
-                    return false;
-            }
-        }
-        return true;
-    }
-    
-    /* ------------------------------------------------------------ */
-    /**
-     * returns the next index of a character from the chars string
-     */
-    public static int indexFrom(String s,String chars)
-    {
-        for (int i=0;i<s.length();i++)
-           if (chars.indexOf(s.charAt(i))>=0)
-              return i;
-        return -1;
-    }
-    
-    /* ------------------------------------------------------------ */
-    /**
-     * replace substrings within string.
-     */
-    public static String replace(String s, String sub, String with)
-    {
-        int c=0;
-        int i=s.indexOf(sub,c);
-        if (i == -1)
-            return s;
-    
-        StringBuilder buf = new StringBuilder(s.length()+with.length());
+		if (s==null)
+			return false;
+			
+		int sl=s.length();
+		int wl=w.length();
+		
+		if (sl<wl)
+			return false;
+		
+		for (int i=wl;i-->0;)
+		{
+			char c1=s.charAt(--sl);
+			char c2=w.charAt(i);
+			if (c1!=c2)
+			{
+				if (c1<=127)
+					c1=lowercases[c1];
+				if (c2<=127)
+					c2=lowercases[c2];
+				if (c1!=c2)
+					return false;
+			}
+		}
+		return true;
+	}
+	
+	/* ------------------------------------------------------------ */
+	/**
+	 * returns the next index of a character from the chars string
+	 */
+	public static int indexFrom(String s,String chars)
+	{
+		for (int i=0;i<s.length();i++)
+		   if (chars.indexOf(s.charAt(i))>=0)
+			  return i;
+		return -1;
+	}
+	
+	/* ------------------------------------------------------------ */
+	/**
+	 * replace substrings within string.
+	 */
+	public static String replace(String s, String sub, String with)
+	{
+		int c=0;
+		int i=s.indexOf(sub,c);
+		if (i == -1)
+			return s;
+	
+		StringBuilder buf = new StringBuilder(s.length()+with.length());
 
-        do
-        {
-            buf.append(s.substring(c,i));
-            buf.append(with);
-            c=i+sub.length();
-        } while ((i=s.indexOf(sub,c))!=-1);
+		do
+		{
+			buf.append(s.substring(c,i));
+			buf.append(with);
+			c=i+sub.length();
+		} while ((i=s.indexOf(sub,c))!=-1);
 
-        if (c<s.length())
-            buf.append(s.substring(c,s.length()));
+		if (c<s.length())
+			buf.append(s.substring(c,s.length()));
 
-        return buf.toString();
-        
-    }
+		return buf.toString();
+		
+	}
 
 
-    /* ------------------------------------------------------------ */
-    /** Remove single or double quotes.
-     */
-    public static String unquote(String s)
-    {
-        return QuotedStringTokenizer.unquote(s);
-    }
+	/* ------------------------------------------------------------ */
+	/** Remove single or double quotes.
+	 */
+	public static String unquote(String s)
+	{
+		return QuotedStringTokenizer.unquote(s);
+	}
 
 
-    /* ------------------------------------------------------------ */
-    /** Append substring to StringBuilder 
-     * @param buf StringBuilder to append to
-     * @param s String to append from
-     * @param offset The offset of the substring
-     * @param length The length of the substring
-     */
-    public static void append(StringBuilder buf,
-                              String s,
-                              int offset,
-                              int length)
-    {
-        synchronized(buf)
-        {
-            int end=offset+length;
-            for (int i=offset; i<end;i++)
-            {
-                if (i>=s.length())
-                    break;
-                buf.append(s.charAt(i));
-            }
-        }
-    }
+	/* ------------------------------------------------------------ */
+	/** Append substring to StringBuilder 
+	 * @param buf StringBuilder to append to
+	 * @param s String to append from
+	 * @param offset The offset of the substring
+	 * @param length The length of the substring
+	 */
+	public static void append(StringBuilder buf,
+							  String s,
+							  int offset,
+							  int length)
+	{
+		synchronized(buf)
+		{
+			int end=offset+length;
+			for (int i=offset; i<end;i++)
+			{
+				if (i>=s.length())
+					break;
+				buf.append(s.charAt(i));
+			}
+		}
+	}
 
-    
-    /* ------------------------------------------------------------ */
-    /**
-     * append hex digit
-     * 
-     */
-    public static void append(StringBuilder buf,byte b,int base)
-    {
-        int bi=0xff&b;
-        int c='0'+(bi/base)%base;
-        if (c>'9')
-            c= 'a'+(c-'0'-10);
-        buf.append((char)c);
-        c='0'+bi%base;
-        if (c>'9')
-            c= 'a'+(c-'0'-10);
-        buf.append((char)c);
-    }
+	
+	/* ------------------------------------------------------------ */
+	/**
+	 * append hex digit
+	 * 
+	 */
+	public static void append(StringBuilder buf,byte b,int base)
+	{
+		int bi=0xff&b;
+		int c='0'+(bi/base)%base;
+		if (c>'9')
+			c= 'a'+(c-'0'-10);
+		buf.append((char)c);
+		c='0'+bi%base;
+		if (c>'9')
+			c= 'a'+(c-'0'-10);
+		buf.append((char)c);
+	}
 
-    /* ------------------------------------------------------------ */
-    public static void append2digits(StringBuffer buf,int i)
-    {
-        if (i<100)
-        {
-            buf.append((char)(i/10+'0'));
-            buf.append((char)(i%10+'0'));
-        }
-    }
-    
-    /* ------------------------------------------------------------ */
-    public static void append2digits(StringBuilder buf,int i)
-    {
-        if (i<100)
-        {
-            buf.append((char)(i/10+'0'));
-            buf.append((char)(i%10+'0'));
-        }
-    }
-    
-    /* ------------------------------------------------------------ */
-    /** Return a non null string.
-     * @param s String
-     * @return The string passed in or empty string if it is null. 
-     */
-    public static String nonNull(String s)
-    {
-        if (s==null)
-            return "";
-        return s;
-    }
-    
-    /* ------------------------------------------------------------ */
-    public static boolean equals(String s,char[] buf, int offset, int length)
-    {
-        if (s.length()!=length)
-            return false;
-        for (int i=0;i<length;i++)
-            if (buf[offset+i]!=s.charAt(i))
-                return false;
-        return true;
-    }
+	/* ------------------------------------------------------------ */
+	public static void append2digits(StringBuffer buf,int i)
+	{
+		if (i<100)
+		{
+			buf.append((char)(i/10+'0'));
+			buf.append((char)(i%10+'0'));
+		}
+	}
+	
+	/* ------------------------------------------------------------ */
+	public static void append2digits(StringBuilder buf,int i)
+	{
+		if (i<100)
+		{
+			buf.append((char)(i/10+'0'));
+			buf.append((char)(i%10+'0'));
+		}
+	}
+	
+	/* ------------------------------------------------------------ */
+	/** Return a non null string.
+	 * @param s String
+	 * @return The string passed in or empty string if it is null. 
+	 */
+	public static String nonNull(String s)
+	{
+		if (s==null)
+			return "";
+		return s;
+	}
+	
+	/* ------------------------------------------------------------ */
+	public static boolean equals(String s,char[] buf, int offset, int length)
+	{
+		if (s.length()!=length)
+			return false;
+		for (int i=0;i<length;i++)
+			if (buf[offset+i]!=s.charAt(i))
+				return false;
+		return true;
+	}
 
-    /* ------------------------------------------------------------ */
-    public static String toUTF8String(byte[] b,int offset,int length)
-    {
-        try
-        {
-            return new String(b,offset,length,__UTF8);
-        }
-        catch (UnsupportedEncodingException e)
-        {
-            throw new IllegalArgumentException(e);
-        }
-    }
+	/* ------------------------------------------------------------ */
+	public static String toUTF8String(byte[] b,int offset,int length)
+	{
+		try
+		{
+			return new String(b,offset,length,__UTF8);
+		}
+		catch (UnsupportedEncodingException e)
+		{
+			throw new IllegalArgumentException(e);
+		}
+	}
 
-    /* ------------------------------------------------------------ */
-    public static String toString(byte[] b,int offset,int length,String charset)
-    {
-        try
-        {
-            return new String(b,offset,length,charset);
-        }
-        catch (UnsupportedEncodingException e)
-        {
-            throw new IllegalArgumentException(e);
-        }
-    }
+	/* ------------------------------------------------------------ */
+	public static String toString(byte[] b,int offset,int length,String charset)
+	{
+		try
+		{
+			return new String(b,offset,length,charset);
+		}
+		catch (UnsupportedEncodingException e)
+		{
+			throw new IllegalArgumentException(e);
+		}
+	}
 
 
-    /* ------------------------------------------------------------ */
-    public static boolean isUTF8(String charset)
-    {
-        return __UTF8.equalsIgnoreCase(charset)||__UTF8Alt.equalsIgnoreCase(charset);
-    }
+	/* ------------------------------------------------------------ */
+	public static boolean isUTF8(String charset)
+	{
+		return __UTF8.equalsIgnoreCase(charset)||__UTF8Alt.equalsIgnoreCase(charset);
+	}
 
 
-    /* ------------------------------------------------------------ */
-    public static String printable(String name)
-    {
-        if (name==null)
-            return null;
-        StringBuilder buf = new StringBuilder(name.length());
-        for (int i=0;i<name.length();i++)
-        {
-            char c=name.charAt(i);
-            if (!Character.isISOControl(c))
-                buf.append(c);
-        }
-        return buf.toString();
-    }
-    
-    /* ------------------------------------------------------------ */
-    public static String printable(byte[] b)
-    {
-        StringBuilder buf = new StringBuilder();
-        for (int i=0;i<b.length;i++)
-        {
-            char c=(char)b[i];
-            if (Character.isWhitespace(c)|| c>' ' && c<0x7f)
-                buf.append(c);
-            else 
-            {
-                buf.append("0x");
-                TypeUtil.toHex(b[i],buf);
-            }
-        }
-        return buf.toString();
-    }
-    
-    public static byte[] getBytes(String s)
-    {
-        try
-        {
-            return s.getBytes(__ISO_8859_1);
-        }
-        catch(Exception e)
-        {
-            LOG.warn("",e);
-            return s.getBytes();
-        }
-    }
-    
-    public static byte[] getBytes(String s,String charset)
-    {
-        try
-        {
-            return s.getBytes(charset);
-        }
-        catch(Exception e)
-        {
-            LOG.warn("",e);
-            return s.getBytes();
-        }
-    }
-    
-    
-    
-    /**
-     * Converts a binary SID to a string SID
-     * 
-     * http://en.wikipedia.org/wiki/Security_Identifier
-     * 
-     * S-1-IdentifierAuthority-SubAuthority1-SubAuthority2-...-SubAuthorityn
-     */
-    public static String sidBytesToString(byte[] sidBytes)
-    {
-        StringBuilder sidString = new StringBuilder();
-        
-        // Identify this as a SID
-        sidString.append("S-");
-        
-        // Add SID revision level (expect 1 but may change someday)
-        sidString.append(Byte.toString(sidBytes[0])).append('-');
-        
-        StringBuilder tmpBuilder = new StringBuilder();
-        
-        // crunch the six bytes of issuing authority value
-        for (int i = 2; i <= 7; ++i)
-        {
-            tmpBuilder.append(Integer.toHexString(sidBytes[i] & 0xFF));
-        }
-        
-        sidString.append(Long.parseLong(tmpBuilder.toString(), 16)); // '-' is in the subauth loop
+	/* ------------------------------------------------------------ */
+	public static String printable(String name)
+	{
+		if (name==null)
+			return null;
+		StringBuilder buf = new StringBuilder(name.length());
+		for (int i=0;i<name.length();i++)
+		{
+			char c=name.charAt(i);
+			if (!Character.isISOControl(c))
+				buf.append(c);
+		}
+		return buf.toString();
+	}
+	
+	/* ------------------------------------------------------------ */
+	public static String printable(byte[] b)
+	{
+		StringBuilder buf = new StringBuilder();
+		for (int i=0;i<b.length;i++)
+		{
+			char c=(char)b[i];
+			if (Character.isWhitespace(c)|| c>' ' && c<0x7f)
+				buf.append(c);
+			else 
+			{
+				buf.append("0x");
+				TypeUtil.toHex(b[i],buf);
+			}
+		}
+		return buf.toString();
+	}
+	
+	public static byte[] getBytes(String s)
+	{
+		try
+		{
+			return s.getBytes(__ISO_8859_1);
+		}
+		catch(Exception e)
+		{
+			LOG.warn("",e);
+			return s.getBytes();
+		}
+	}
+	
+	public static byte[] getBytes(String s,String charset)
+	{
+		try
+		{
+			return s.getBytes(charset);
+		}
+		catch(Exception e)
+		{
+			LOG.warn("",e);
+			return s.getBytes();
+		}
+	}
+	
+	
+	
+	/**
+	 * Converts a binary SID to a string SID
+	 * 
+	 * http://en.wikipedia.org/wiki/Security_Identifier
+	 * 
+	 * S-1-IdentifierAuthority-SubAuthority1-SubAuthority2-...-SubAuthorityn
+	 */
+	public static String sidBytesToString(byte[] sidBytes)
+	{
+		StringBuilder sidString = new StringBuilder();
+		
+		// Identify this as a SID
+		sidString.append("S-");
+		
+		// Add SID revision level (expect 1 but may change someday)
+		sidString.append(Byte.toString(sidBytes[0])).append('-');
+		
+		StringBuilder tmpBuilder = new StringBuilder();
+		
+		// crunch the six bytes of issuing authority value
+		for (int i = 2; i <= 7; ++i)
+		{
+			tmpBuilder.append(Integer.toHexString(sidBytes[i] & 0xFF));
+		}
+		
+		sidString.append(Long.parseLong(tmpBuilder.toString(), 16)); // '-' is in the subauth loop
    
-        // the number of subAuthorities we need to attach
-        int subAuthorityCount = sidBytes[1];
+		// the number of subAuthorities we need to attach
+		int subAuthorityCount = sidBytes[1];
 
-        // attach each of the subAuthorities
-        for (int i = 0; i < subAuthorityCount; ++i)
-        {
-            int offset = i * 4;
-            tmpBuilder.setLength(0);
-            // these need to be zero padded hex and little endian
-            tmpBuilder.append(String.format("%02X%02X%02X%02X", 
-                    (sidBytes[11 + offset] & 0xFF),
-                    (sidBytes[10 + offset] & 0xFF),
-                    (sidBytes[9 + offset] & 0xFF),
-                    (sidBytes[8 + offset] & 0xFF)));  
-            sidString.append('-').append(Long.parseLong(tmpBuilder.toString(), 16));
-        }
-        
-        return sidString.toString();
-    }
-    
-    /**
-     * Converts a string SID to a binary SID
-     * 
-     * http://en.wikipedia.org/wiki/Security_Identifier
-     * 
-     * S-1-IdentifierAuthority-SubAuthority1-SubAuthority2-...-SubAuthorityn
-     */
-    public static byte[] sidStringToBytes( String sidString )
-    {
-        String[] sidTokens = sidString.split("-");
-        
-        int subAuthorityCount = sidTokens.length - 3; // S-Rev-IdAuth-
-        
-        int byteCount = 0;
-        byte[] sidBytes = new byte[1 + 1 + 6 + (4 * subAuthorityCount)];
-        
-        // the revision byte
-        sidBytes[byteCount++] = (byte)Integer.parseInt(sidTokens[1]);
+		// attach each of the subAuthorities
+		for (int i = 0; i < subAuthorityCount; ++i)
+		{
+			int offset = i * 4;
+			tmpBuilder.setLength(0);
+			// these need to be zero padded hex and little endian
+			tmpBuilder.append(String.format("%02X%02X%02X%02X", 
+					(sidBytes[11 + offset] & 0xFF),
+					(sidBytes[10 + offset] & 0xFF),
+					(sidBytes[9 + offset] & 0xFF),
+					(sidBytes[8 + offset] & 0xFF)));  
+			sidString.append('-').append(Long.parseLong(tmpBuilder.toString(), 16));
+		}
+		
+		return sidString.toString();
+	}
+	
+	/**
+	 * Converts a string SID to a binary SID
+	 * 
+	 * http://en.wikipedia.org/wiki/Security_Identifier
+	 * 
+	 * S-1-IdentifierAuthority-SubAuthority1-SubAuthority2-...-SubAuthorityn
+	 */
+	public static byte[] sidStringToBytes( String sidString )
+	{
+		String[] sidTokens = sidString.split("-");
+		
+		int subAuthorityCount = sidTokens.length - 3; // S-Rev-IdAuth-
+		
+		int byteCount = 0;
+		byte[] sidBytes = new byte[1 + 1 + 6 + (4 * subAuthorityCount)];
+		
+		// the revision byte
+		sidBytes[byteCount++] = (byte)Integer.parseInt(sidTokens[1]);
 
-        // the # of sub authorities byte
-        sidBytes[byteCount++] = (byte)subAuthorityCount;
+		// the # of sub authorities byte
+		sidBytes[byteCount++] = (byte)subAuthorityCount;
 
-        // the certAuthority
-        String hexStr = Long.toHexString(Long.parseLong(sidTokens[2]));
-        
-        while( hexStr.length() < 12) // pad to 12 characters
-        {
-            hexStr = "0" + hexStr;
-        }
+		// the certAuthority
+		String hexStr = Long.toHexString(Long.parseLong(sidTokens[2]));
+		
+		while( hexStr.length() < 12) // pad to 12 characters
+		{
+			hexStr = "0" + hexStr;
+		}
 
-        // place the certAuthority 6 bytes
-        for ( int i = 0 ; i < hexStr.length(); i = i + 2)
-        {
-            sidBytes[byteCount++] = (byte)Integer.parseInt(hexStr.substring(i, i + 2),16);
-        }
-                
-        
-        for ( int i = 3; i < sidTokens.length ; ++i)
-        {
-            hexStr = Long.toHexString(Long.parseLong(sidTokens[i]));
-            
-            while( hexStr.length() < 8) // pad to 8 characters
-            {
-                hexStr = "0" + hexStr;
-            }     
-            
-            // place the inverted sub authorities, 4 bytes each
-            for ( int j = hexStr.length(); j > 0; j = j - 2)
-            {          
-                sidBytes[byteCount++] = (byte)Integer.parseInt(hexStr.substring(j-2, j),16);
-            }
-        }
-      
-        return sidBytes;
-    }
+		// place the certAuthority 6 bytes
+		for ( int i = 0 ; i < hexStr.length(); i = i + 2)
+		{
+			sidBytes[byteCount++] = (byte)Integer.parseInt(hexStr.substring(i, i + 2),16);
+		}
+				
+		
+		for ( int i = 3; i < sidTokens.length ; ++i)
+		{
+			hexStr = Long.toHexString(Long.parseLong(sidTokens[i]));
+			
+			while( hexStr.length() < 8) // pad to 8 characters
+			{
+				hexStr = "0" + hexStr;
+			}     
+			
+			// place the inverted sub authorities, 4 bytes each
+			for ( int j = hexStr.length(); j > 0; j = j - 2)
+			{          
+				sidBytes[byteCount++] = (byte)Integer.parseInt(hexStr.substring(j-2, j),16);
+			}
+		}
+	  
+		return sidBytes;
+	}
 }