Main Page | Packages | Class Hierarchy | Class List | Directories | File List | Class Members | Related Pages

Utils.java

00001 // Utils - assorted static utility routines
00002 //
00003 // Copyright (C)1996,1998 by Jef Poskanzer <jef@acme.com>.  All rights reserved.
00004 //
00005 // Redistribution and use in source and binary forms, with or without
00006 // modification, are permitted provided that the following conditions
00007 // are met:
00008 // 1. Redistributions of source code must retain the above copyright
00009 //    notice, this list of conditions and the following disclaimer.
00010 // 2. Redistributions in binary form must reproduce the above copyright
00011 //    notice, this list of conditions and the following disclaimer in the
00012 //    documentation and/or other materials provided with the distribution.
00013 //
00014 // THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
00015 // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00016 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00017 // ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
00018 // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00019 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00020 // OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00021 // HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00022 // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00023 // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00024 // SUCH DAMAGE.
00025 //
00026 // Visit the ACME Labs Java page for up-to-date versions of this and other
00027 // fine Java utilities: http://www.acme.com/java/
00028 
00029 package Acme;
00030 
00031 import java.util.*;
00032 import java.io.*;
00033 import java.net.*;
00034 import java.text.SimpleDateFormat;
00035 
00037 // <P>
00038 // Whenever I come up with a static routine that might be of general use,
00039 // I put it here.  So far the class includes:
00040 // <UL>
00041 // <LI> some string routines that were left out of java.lang.String
00042 // <LI> a general array-to-string routine
00043 // <LI> a fixed version of java.io.InputStream's byte-array read routine
00044 // <LI> a bunch of URL-hacking routines
00045 // <LI> some easy-to-use wrappers for Runtime.exec
00046 // <LI> a debugging routine to dump the current call stack
00047 // <LI> a URLDecoder to match java.net.URLEncoder
00048 // </UL>
00049 // and lots more.
00050 // <P>
00051 // <A HREF="/resources/classes/Acme/Utils.java">Fetch the software.</A><BR>
00052 // <A HREF="/resources/classes/Acme.tar.Z">Fetch the entire Acme package.</A>
00053 
00054 public class Utils
00055     {
00056 
00058     // six months of now, Mmm dd hh:ss, else Mmm dd  yyyy.
00059     static final SimpleDateFormat shortfmt = new SimpleDateFormat("MMM dd HH:mm");
00060     static final SimpleDateFormat longfmt = new SimpleDateFormat("MMM dd yyyy");
00061     public static String lsDateStr( Date date )
00062         {
00063         if ( Math.abs( System.currentTimeMillis() - date.getTime() ) < 183L * 24L * 60L * 60L * 1000L )
00064             return shortfmt.format(date);
00065         else
00066             return longfmt.format(date);
00067         }
00068 
00069 
00071     public static String pluralStr( long n )
00072         {
00073         if ( n == 1 )
00074             return "";
00075         else
00076             return "s";
00077         }
00078 
00079 
00080     // Various interval constants.  Some are only approximate.
00081     public static final long INT_SECOND = 1000L;
00082     public static final long INT_MINUTE = INT_SECOND * 60L;
00083     public static final long INT_HOUR = INT_MINUTE * 60L;
00084     public static final long INT_DAY = INT_HOUR * 24L;
00085     public static final long INT_WEEK = INT_DAY * 7L;
00086     public static final long INT_MONTH = INT_DAY * 30L;
00087     public static final long INT_YEAR = INT_DAY * 365L;
00088     public static final long INT_DECADE = INT_DAY * 3652L;
00089 
00091     // @param interval the interval, in milliseconds
00092     public static String intervalStr( long interval )
00093         {
00094         long decades, years, months, weeks, days, hours, minutes, seconds, millis;
00095 
00096         decades = interval / INT_DECADE;
00097         interval -= decades * INT_DECADE;
00098         years = interval / INT_YEAR;
00099         interval -= years * INT_YEAR;
00100         months = interval / INT_MONTH;
00101         interval -= months * INT_MONTH;
00102         weeks = interval / INT_WEEK;
00103         interval -= weeks * INT_WEEK;
00104         days = interval / INT_DAY;
00105         interval -= days * INT_DAY;
00106         hours = interval / INT_HOUR;
00107         interval -= hours * INT_HOUR;
00108         minutes = interval / INT_MINUTE;
00109         interval -= minutes * INT_MINUTE;
00110         seconds = interval / INT_SECOND;
00111         interval -= seconds * INT_SECOND;
00112         millis = interval;
00113 
00114         if ( decades > 0 )
00115             if ( years == 0 )
00116                 return decades + " decade" + pluralStr( decades );
00117             else
00118                 return
00119                     decades + " decade" + pluralStr( decades ) + ", " +
00120                     years + " years" + pluralStr( years );
00121         else if ( years > 0 )
00122             if ( months == 0 )
00123                 return years + " year" + pluralStr( years );
00124             else
00125                 return
00126                     years + " year" + pluralStr( years ) + ", " +
00127                     months + " month" + pluralStr( months );
00128         else if ( months > 0 )
00129             if ( weeks == 0 )
00130                 return months + " month" + pluralStr( months );
00131             else
00132                 return
00133                     months + " month" + pluralStr( months ) + ", " +
00134                     weeks + " week" + pluralStr( weeks );
00135         else if ( weeks > 0 )
00136             if ( days == 0 )
00137                 return weeks + " week" + pluralStr( weeks );
00138             else
00139                 return
00140                     weeks + " week" + pluralStr( weeks ) + ", " +
00141                     days + " day" + pluralStr( days );
00142         else if ( days > 0 )
00143             if ( hours == 0 )
00144                 return days + " day" + pluralStr( days );
00145             else
00146                 return
00147                     days + " day" + pluralStr( days ) + ", " +
00148                     hours + " hour" + pluralStr( hours );
00149         else if ( hours > 0 )
00150             if ( minutes == 0 )
00151                 return hours + " hour" + pluralStr( hours );
00152             else
00153                 return
00154                     hours + " hour" + pluralStr( hours ) + ", " +
00155                     minutes + " minute" + pluralStr( minutes );
00156         else if ( minutes > 0 )
00157             if ( seconds == 0 )
00158                 return minutes + " minute" + pluralStr( minutes );
00159             else
00160                 return
00161                     minutes + " minute" + pluralStr( minutes ) + ", " +
00162                     seconds + " second" + pluralStr( seconds );
00163         else if ( seconds > 0 )
00164             if ( millis == 0 )
00165                 return seconds + " second" + pluralStr( seconds );
00166             else
00167                 return
00168                     seconds + " second" + pluralStr( seconds ) + ", " +
00169                     millis + " millisecond" + pluralStr( millis );
00170         else
00171             return millis + " millisecond" + pluralStr( millis );
00172         }
00173 
00174 
00176     // entirely of characters from charSet.
00177     public static int strSpan( String str, String charSet )
00178         {
00179         return strSpan( str, charSet, 0 );
00180         }
00181 
00183     // entirely of characters from charSet, starting at the given index.
00184     public static int strSpan( String str, String charSet, int fromIdx )
00185         {
00186         int i;
00187         for ( i = fromIdx; i < str.length(); ++i )
00188             if ( charSet.indexOf( str.charAt( i ) ) == -1 )
00189                 break;
00190         return i - fromIdx;
00191         }
00192 
00194     // entirely of characters NOT from charSet.
00195     public static int strCSpan( String str, String charSet )
00196         {
00197         return strCSpan( str, charSet, 0 );
00198         }
00199 
00201     // entirely of characters NOT from charSet, starting at the given index.
00202     public static int strCSpan( String str, String charSet, int fromIdx )
00203         {
00204         int i;
00205         for ( i = fromIdx; i < str.length(); ++i )
00206             if ( charSet.indexOf( str.charAt( i ) ) != -1 )
00207                 break;
00208         return i - fromIdx;
00209         }
00210 
00212     // Only does ? and *, and multiple patterns separated by |.
00213     public static boolean match( String pattern, String string )
00214         {
00215         for ( int p = 0; ; ++p )
00216             {
00217             for ( int s = 0; ; ++p, ++s )
00218                 {
00219                 boolean sEnd = ( s >= string.length() );
00220                 boolean pEnd = ( p >= pattern.length() ||
00221                                  pattern.charAt( p ) == '|' );
00222                 if ( sEnd && pEnd )
00223                     return true;
00224                 if ( sEnd || pEnd )
00225                     break;
00226                 if ( pattern.charAt( p ) == '?' )
00227                     continue;
00228                 if ( pattern.charAt( p ) == '*' )
00229                     {
00230                     int i;
00231                     ++p;
00232                     for ( i = string.length(); i >= s; --i )
00233                         if ( match(
00234                                pattern.substring( p ),
00235                                string.substring( i ) ) )  /* not quite right */
00236                             return true;
00237                     break;
00238                     }
00239                 if ( pattern.charAt( p ) != string.charAt( s ) )
00240                     break;
00241                 }
00242             p = pattern.indexOf( '|', p );
00243             if ( p == -1 )
00244                 return false;
00245             }
00246         }
00247 
00249     // pattern.  Only does ? and *, and multiple patterns separated by |.
00250     public static int matchSpan( String pattern, String string )
00251     {
00252         int result = 0;
00253         StringTokenizer st = new StringTokenizer(pattern, "|");
00254         
00255         while (st.hasMoreTokens())
00256         {
00257             int len = matchSpan1(st.nextToken(), string);
00258             if (len > result)
00259                 result = len;
00260         }
00261         return result;
00262     }
00263 
00264     static int matchSpan1( String pattern, String string )
00265     {
00266         int p=0;
00267         for (; p < string.length() && p < pattern.length(); p++)
00268         {
00269             if (pattern.charAt(p) == string.charAt(p))
00270                 continue;
00271             if (pattern.charAt(p) == '*')
00272                 return p-1;
00273             return 0;
00274         }
00275         return p<(pattern.length()-1)?-1:p;
00276     }
00277 
00279     public static int sameSpan( String str1, String str2 )
00280         {
00281         int i;
00282         for ( i = 0;
00283               i < str1.length() && i < str2.length() &&
00284                 str1.charAt( i ) == str2.charAt( i );
00285               ++i )
00286             ;
00287         return i;
00288         }
00289 
00291     public static int charCount( String str, char c )
00292         {
00293         int n = 0;
00294         for ( int i = 0; i < str.length(); ++i )
00295             if ( str.charAt( i ) == c )
00296                 ++n;
00297         return n;
00298         }
00299 
00300 
00302     // to split it up at whitespace.
00303     public static String[] splitStr( String str )
00304         {
00305         StringTokenizer st = new StringTokenizer( str );
00306         int n = st.countTokens();
00307         String[] strs = new String[n];
00308         for ( int i = 0; i < n; ++i )
00309             strs[i] = st.nextToken();
00310         return strs;
00311         }
00312 
00314     // the specified character.  This does not use StringTokenizer,
00315     // and therefore can handle empty fields.
00316     public static String[] splitStr( String str, char delim )
00317         {
00318         int n = 1;
00319         int index = -1;
00320         while ( true )
00321             {
00322             index = str.indexOf( delim, index + 1 );
00323             if ( index == -1 )
00324                 break;
00325             ++n;
00326             }
00327         String[] strs = new String[n];
00328         index = -1;
00329         for ( int i = 0; i < n - 1; ++i )
00330             {
00331             int nextIndex = str.indexOf( delim, index + 1 );
00332             strs[i] = str.substring( index + 1, nextIndex );
00333             index = nextIndex;
00334             }
00335         strs[n - 1] = str.substring( index + 1 );
00336         return strs;
00337         }
00338 
00340     // separated by spaces.
00341     public static String flattenStrarr( String[] strs )
00342         {
00343         StringBuffer sb = new StringBuffer();
00344         for ( int i = 0; i < strs.length; ++i )
00345             {
00346             if ( i > 0 )
00347                 sb.append( ' ' );
00348             sb.append( strs[i] );
00349             }
00350         return sb.toString();
00351         }
00352 
00354     // Java currently has no general sort function.  Sorting Strings is
00355     // common enough that it's worth making a special case.
00356     public static void sortStrings( String[] strings )
00357         {
00358         // Just does a bubblesort.
00359         for ( int i = 0; i < strings.length - 1; ++i )
00360             {
00361             for ( int j = i + 1; j < strings.length; ++j )
00362                 {
00363                 if ( strings[i].compareTo( strings[j] ) > 0 )
00364                     {
00365                     String t = strings[i];
00366                     strings[i] = strings[j];
00367                     strings[j] = t;
00368                     }
00369                 }
00370             }
00371         }
00372     
00374     // Returns -1 if the String is not found.
00375     public static int indexOfString( String[] strings, String string )
00376         {
00377         for ( int i = 0; i < strings.length; ++i )
00378             if ( string.equals( strings[i] ) )
00379                 return i;
00380         return -1;
00381         }
00382 
00384     // Returns -1 if the String is not found.
00385     public static int indexOfStringIgnoreCase( String[] strings, String string )
00386         {
00387         for ( int i = 0; i < strings.length; ++i )
00388             if ( string.equalsIgnoreCase( strings[i] ) )
00389                 return i;
00390         return -1;
00391         }
00392     
00394     public static boolean equalsStrings( String[] strings1, String[] strings2 )
00395         {
00396         if ( strings1.length != strings2.length )
00397             return false;
00398         for ( int i = 0; i < strings1.length; ++i )
00399             if ( ! strings1[i].equals( strings2[i] ) )
00400                 return false;
00401         return true;
00402         }
00403 
00404 
00406     // of Math.pow().  Throws ArithmeticException if b is negative.
00407     public static long pow( long a, long b ) throws ArithmeticException
00408         {
00409         if ( b < 0 )
00410             throw new ArithmeticException();
00411         long r = 1;
00412         while ( b != 0 )
00413             {
00414             if ( odd( b ) )
00415                 r *= a;
00416             b >>>= 1;
00417             a *= a;
00418             }
00419         return r;
00420         }
00421 
00422 
00424     public static int parseInt( String str, int def )
00425         {
00426         try
00427             {
00428             return Integer.parseInt( str );
00429             }
00430         catch ( Exception e )
00431             {
00432             return def;
00433             }
00434         }
00435 
00437     public static long parseLong( String str, long def )
00438         {
00439         try
00440             {
00441             return Long.parseLong( str );
00442             }
00443         catch ( Exception e )
00444             {
00445             return def;
00446             }
00447         }
00448 
00449 
00451     // type, including nested arrays.  Sample output:
00452     // <BLOCKQUOTE><CODE><PRE>
00453     // byte[]:    { (byte)0, (byte)1, (byte)2 }
00454     // char[]:    { '0', '1', '2' }
00455     // short[]:   { (short)0, (short)1, (short)2 }
00456     // int[]:     { 0, 1, 2 }
00457     // long[]:    { 0L, 1L, 2L }
00458     // float[]:   { 0F, 1F, 2F }
00459     // double[]:  { 0D, 1D, 2D }
00460     // String[]:  { "0", "1", "2" }
00461     // int[][]:   { { 0, 1, 2 }, { 3, 4, 5 } }
00462     // </PRE></CODE></BLOCKQUOTE>
00463     public static String arrayToString( Object o )
00464         {
00465         if ( o == null )
00466             return "null";
00467         String cl = o.getClass().getName();
00468         if ( ! cl.startsWith( "[" ) )
00469             // It's not an array; just call its toString method.
00470             return o.toString();
00471         StringBuffer sb = new StringBuffer( "{ " );
00472         if ( o instanceof byte[] )
00473             {
00474             byte[] ba = (byte[]) o;
00475             for ( int i = 0; i < ba.length; ++i )
00476                 {
00477                 if ( i > 0 ) sb.append( ", " );
00478                 sb.append( "(byte)" );
00479                 sb.append( ba[i] );
00480                 }
00481             }
00482         else if ( o instanceof char[] )
00483             {
00484             char[] ca = (char[]) o;
00485             for ( int i = 0; i < ca.length; ++i )
00486                 {
00487                 if ( i > 0 ) sb.append( ", " );
00488                 sb.append( "'" );
00489                 sb.append( ca[i] );
00490                 sb.append( "'" );
00491                 }
00492             }
00493         else if ( o instanceof short[] )
00494             {
00495             short[] sa = (short[]) o;
00496             for ( int i = 0; i < sa.length; ++i )
00497                 {
00498                 if ( i > 0 ) sb.append( ", " );
00499                 sb.append( "(short)" );
00500                 sb.append( sa[i] );
00501                 }
00502             }
00503         else if ( o instanceof int[] )
00504             {
00505             int[] ia = (int[]) o;
00506             for ( int i = 0; i < ia.length; ++i )
00507                 {
00508                 if ( i > 0 ) sb.append( ", " );
00509                 sb.append( ia[i] );
00510                 }
00511             }
00512         else if ( o instanceof long[] )
00513             {
00514             long[] la = (long[]) o;
00515             for ( int i = 0; i < la.length; ++i )
00516                 {
00517                 if ( i > 0 ) sb.append( ", " );
00518                 sb.append( la[i] );
00519                 sb.append( "L" );
00520                 }
00521             }
00522         else if ( o instanceof float[] )
00523             {
00524             float[] fa = (float[]) o;
00525             for ( int i = 0; i < fa.length; ++i )
00526                 {
00527                 if ( i > 0 ) sb.append( ", " );
00528                 sb.append( fa[i] );
00529                 sb.append( "F" );
00530                 }
00531             }
00532         else if ( o instanceof double[] )
00533             {
00534             double[] da = (double[]) o;
00535             for ( int i = 0; i < da.length; ++i )
00536                 {
00537                 if ( i > 0 ) sb.append( ", " );
00538                 sb.append( da[i] );
00539                 sb.append( "D" );
00540                 }
00541             }
00542         else if ( o instanceof String )
00543             {
00544             // Special-case Strings so we can surround them with quotes.
00545             String[] sa = (String[]) o;
00546             for ( int i = 0; i < sa.length; ++i )
00547                 {
00548                 if ( i > 0 ) sb.append( ", " );
00549                 sb.append( "\"" );
00550                 sb.append( sa[i] );
00551                 sb.append( "\"" );
00552                 }
00553             }
00554         else if ( cl.startsWith( "[L" ) )
00555             {
00556             // Some random class.
00557             Object[] oa = (Object[]) o;
00558             for ( int i = 0; i < oa.length; ++i )
00559                 {
00560                 if ( i > 0 ) sb.append( ", " );
00561                 sb.append( oa[i] );
00562                 }
00563             }
00564         else if ( cl.startsWith( "[[" ) )
00565             {
00566             // Nested arrays.
00567             Object[] aa = (Object[]) o;
00568             for ( int i = 0; i < aa.length; ++i )
00569                 {
00570                 if ( i > 0 ) sb.append( ", " );
00571                 sb.append( arrayToString( aa[i] ) );
00572                 }
00573             }
00574         else
00575             sb.append( "(unknown array type)" );
00576         sb.append( " }" );
00577         return sb.toString();
00578         }
00579 
00580 
00582     // An instanceof that works on Class objects at runtime, instead
00583     // of type descriptors at compile time.
00584     public static boolean instanceOf( Object o, Class cl )
00585         {
00586         // Null check.
00587         if ( o == null || cl == null )
00588             return false;
00589         Class ocl = o.getClass();
00590         // Check if they are the same class.
00591         if ( ocl.equals( cl ) )
00592             return true;
00593         // If the class is not itself an interface, then check its interfaces.
00594         if ( ! cl.isInterface() )
00595             {
00596             Class ifs[] = cl.getInterfaces();
00597             for ( int i = 0; i < ifs.length; ++i )
00598                 if ( instanceOf( o, ifs[i] ) )
00599                     return true;
00600             }
00601         // And check supeclasses.
00602         Class scl = cl.getSuperclass();
00603         if ( scl != null )
00604             if ( instanceOf( o, scl ) )
00605                 return true;
00606         // Guess not.
00607         return false;
00608         }
00609 
00610 
00612     public static boolean even( long n )
00613         {
00614         return ( n & 1 ) == 0;
00615         }
00616 
00618     public static boolean odd( long n )
00619         {
00620         return ( n & 1 ) != 0;
00621         }
00622 
00623 
00625     public static int countOnes( byte n )
00626         {
00627         return countOnes( n & 0xffL );
00628         }
00629 
00631     public static int countOnes( int n )
00632         {
00633         return countOnes( n & 0xffffffffL );
00634         }
00635 
00637     public static int countOnes( long n )
00638         {
00639         // There are faster ways to do this, all the way up to looking
00640         // up bytes in a 256-element table.  But this is not too bad.
00641         int count = 0;
00642         while ( n != 0 )
00643             {
00644             if ( odd( n ) )
00645                 ++count;
00646             n >>>= 1;
00647             }
00648         return count;
00649         }
00650 
00651 
00653     // standard version catches and ignores IOExceptions from below.
00654     // This version sends them on to the caller.
00655     public static int read( InputStream in, byte[] b, int off, int len ) throws IOException
00656         {
00657         if ( len <= 0 )
00658             return 0;
00659         int c = in.read();
00660         if ( c == -1 )
00661             return -1;
00662         if ( b != null )
00663             b[off] = (byte) c;
00664         int i;
00665         for ( i = 1; i < len ; ++i )
00666             {
00667             c = in.read();
00668             if ( c == -1 )
00669                 break;
00670             if ( b != null )
00671                 b[off + i] = (byte) c;
00672             }
00673         return i;
00674         }
00675 
00677     // of sometimes terminating early.
00678     // @return -1 on EOF, otherwise len
00679     public static int readFully( InputStream in, byte[] b, int off, int len ) throws IOException
00680         {
00681         int l, r;
00682         for ( l = 0; l < len; )
00683             {
00684             r = read( in, b, l, len - l );
00685             if ( r == -1 )
00686                 return -1;
00687             l += r;
00688             }
00689         return len;
00690         }
00691 
00692 
00694     // a directory then make sure there's a trailing slash.
00695     public static URL plainUrl( URL context, String urlStr ) throws MalformedURLException
00696         {
00697         URL url = new URL( context, urlStr );
00698         String fileStr = url.getFile();
00699         int i = fileStr.indexOf( '?' );
00700         if ( i != -1 )
00701             fileStr = fileStr.substring( 0, i );
00702         url = new URL(
00703             url.getProtocol(), url.getHost(), url.getPort(), fileStr );
00704         if ( ( ! fileStr.endsWith( "/" ) ) &&
00705              urlStrIsDir( url.toExternalForm() ) )
00706             {
00707             fileStr = fileStr + "/";
00708             url = new URL(
00709                 url.getProtocol(), url.getHost(), url.getPort(), fileStr );
00710             }
00711         return url;
00712         }
00713 
00715     // a directory then make sure there's a trailing slash.
00716     public static URL plainUrl( String urlStr ) throws MalformedURLException
00717         {
00718         return plainUrl( null, urlStr );
00719         }
00720 
00722     // if the URL points to a directory, you get that directory; if the
00723     // URL points to a file, you get the directory the file is in.
00724     public static String baseUrlStr( String urlStr )
00725         {
00726         if ( urlStr.endsWith( "/" ) )
00727             return urlStr;
00728         if ( urlStrIsDir( urlStr ) )
00729             return urlStr + "/";
00730         return urlStr.substring( 0, urlStr.lastIndexOf( '/' ) + 1 );
00731         }
00732 
00734     public static String fixDirUrlStr( String urlStr )
00735         {
00736         if ( urlStr.endsWith( "/" ) )
00737             return urlStr;
00738         if ( urlStrIsDir( urlStr ) )
00739             return urlStr + "/";
00740         return urlStr;
00741         }
00742 
00744     // Web servers are lenient and accept directory-URLs without
00745     // the trailing slash.  What they actually do is return a
00746     // redirect to the same URL with the trailing slash appended.
00747     // Unfortunately, Java doesn't let us see that such a redirect
00748     // happened.  Instead we have to figure out it's a directory
00749     // indirectly and heuristically.
00750     public static boolean urlStrIsDir( String urlStr )
00751         {
00752         // If it ends with a slash, it's probably a directory.
00753         if ( urlStr.endsWith( "/" ) )
00754             return true;
00755 
00756         // If the last component has a dot, it's probably not a directory.
00757         int lastSlash = urlStr.lastIndexOf( '/' );
00758         int lastPeriod = urlStr.lastIndexOf( '.' );
00759         if ( lastPeriod != -1 && ( lastSlash == -1 || lastPeriod > lastSlash ) )
00760             return false;
00761 
00762         // Otherwise, append a slash and try to connect.  This is
00763         // fairly expensive.
00764         String urlStrWithSlash = urlStr + "/";
00765         try
00766             {
00767             URL url = new URL( urlStrWithSlash );
00768             InputStream f = url.openStream();
00769             f.close();
00770             // Worked fine - it's probably a directory.
00771             return true;
00772             }
00773         catch ( Exception e )
00774             {
00775             // Got an error - must not be a directory.
00776             return false;
00777             }
00778         }
00779 
00780 
00781     // Figures out whether a URL is absolute or not.
00782     public static boolean urlStrIsAbsolute( String urlStr )
00783         {
00784         if ( urlStr.startsWith( "/" ) || urlStr.indexOf( ":/" ) != -1 )
00785             return true;
00786         // Should handle :8000/ and such too.
00787         return false;
00788         }
00789 
00790     // Returns an equivalent URL string that is guaranteed to be absolute.
00791     public static String absoluteUrlStr( String urlStr, URL contextUrl ) throws MalformedURLException
00792         {
00793         URL url = new URL( contextUrl, urlStr );
00794         return url.toExternalForm();
00795         }
00796     
00797 
00799     // already a decoder in the standard library is a mystery to me.
00800     public static String urlDecoder( String encoded )
00801         {
00802         StringBuffer decoded = new StringBuffer();
00803         int len = encoded.length();
00804         for ( int i = 0; i < len; ++i )
00805             {
00806             if ( encoded.charAt( i ) == '%' && i + 2 < len )
00807                 {
00808                 int d1 = Character.digit( encoded.charAt( i + 1 ), 16 );
00809                 int d2 = Character.digit( encoded.charAt( i + 2 ), 16 );
00810                 if ( d1 != -1 && d2 != -1 )
00811                     decoded.append( (char) ( ( d1 << 4 ) + d2 ) );
00812                 i += 2;
00813                 }
00814             else if ( encoded.charAt( i ) == '+' )
00815                 decoded.append( ' ' );
00816             else
00817                 decoded.append( encoded.charAt( i ) );
00818             }
00819         return decoded.toString();
00820         }
00821 
00822 
00824     public static boolean arraycontains( Object[] array, Object element )
00825         {
00826         for ( int i = 0; i < array.length; ++i )
00827             if ( array[i].equals( element ) )
00828                 return true;
00829         return false;
00830         }
00831 
00832 
00834     // <P>
00835     // This routine runs the specified command, waits for it to
00836     // finish, and returns the exit status.
00837     // This is like the Unix system() routine.  Unlike the Unix version,
00838     // though, stdout and stderr get thrown away unless you redirect them.
00839     public static int system( String cmd )
00840         {
00841         try
00842             {
00843             return runCommand( cmd ).waitFor();
00844             }
00845         catch ( IOException e )
00846             {
00847             return -1;
00848             }
00849         catch ( InterruptedException e )
00850             {
00851             return -1;
00852             }
00853         }
00854 
00856     // <P>
00857     // This routine runs the specified command, and returns an InputStream
00858     // for reading the output of the program.
00859     // <P>
00860     // <B>WARNING:</B> In JDK1.0.2 there is a serious bug in the process
00861     // IO routines, such that reading all the way to the end of a process's
00862     // output will invariably get you an IOException( "read error" ).
00863     // In some cases you will also <B>lose</B> the last bufferload of
00864     // the output.  The workaround is to add a " ; sleep 1" to the end of
00865     // your command, and to ignore the "read error" IOException.
00866     public static InputStream popenr( String cmd )
00867         {
00868         try
00869             {
00870             return runCommand( cmd ).getInputStream();
00871             }
00872         catch ( IOException e )
00873             {
00874             return null;
00875             }
00876         }
00877 
00879     // <P>
00880     // This routine runs the specified command, and returns an OutputStream
00881     // for writing the program's input.
00882     public static OutputStream popenw( String cmd )
00883         {
00884         try
00885             {
00886             return runCommand( cmd ).getOutputStream();
00887             }
00888         catch ( IOException e )
00889             {
00890             return null;
00891             }
00892         }
00893 
00895     // <P>
00896     // This routine runs the specified command, and returns a Process
00897     // object so you can do what you like with it.
00898     // <P>
00899     // <B>WARNING:</B> In JDK1.0.2 there is a serious bug in the process
00900     // IO routines, such that reading all the way to the end of a process's
00901     // output will invariably get you an IOException( "read error" ).
00902     // In some cases you will also <B>lose</B> the last bufferload of
00903     // the output.  The workaround is to add a " ; sleep 1" to the end of
00904     // your command, and to ignore the "read error" IOException.
00905     public static Process runCommand( String cmd ) throws IOException
00906         {
00907         Runtime runtime = Runtime.getRuntime();
00908         String[] shCmd = new String[3];
00909         shCmd[0] = "/bin/sh";
00910         shCmd[1] = "-c";
00911         shCmd[2] = cmd;
00912         return runtime.exec( shCmd );
00913         }
00914 
00915 
00917     public static void copyStream( InputStream in, OutputStream out ) throws IOException
00918         {
00919         byte[] buf = new byte[4096];
00920         int len;
00921         while ( ( len = in.read( buf ) ) != -1 )
00922             out.write( buf, 0, len );
00923         }
00924 
00926     public static void copyStream( Reader in, Writer out ) throws IOException
00927         {
00928         char[] buf = new char[4096];
00929         int len;
00930         while ( ( len = in.read( buf ) ) != -1 )
00931             out.write( buf, 0, len );
00932         }
00933 
00935     public static void copyStream( InputStream in, Writer out ) throws IOException
00936         {
00937         byte[] buf1 = new byte[4096];
00938         char[] buf2 = new char[4096];
00939         int len, i;
00940         while ( ( len = in.read( buf1 ) ) != -1 )
00941             {
00942             for ( i = 0; i < len; ++i )
00943                 buf2[i] = (char) buf1[i];
00944             out.write( buf2, 0, len );
00945             }
00946         }
00947 
00949     public static void copyStream( Reader in, OutputStream out ) throws IOException
00950         {
00951         char[] buf1 = new char[4096];
00952         byte[] buf2 = new byte[4096];
00953         int len, i;
00954         while ( ( len = in.read( buf1 ) ) != -1 )
00955             {
00956             for ( i = 0; i < len; ++i )
00957                 buf2[i] = (byte) buf1[i];
00958             out.write( buf2, 0, len );
00959             }
00960         }
00961 
00963     public static void dumpStack( PrintStream p )
00964         {
00965         (new Throwable()).printStackTrace( p );
00966         }
00967 
00969     public static void dumpStack()
00970         {
00971         (new Throwable()).printStackTrace();
00972         }
00973 
00975     public static void putAll(Hashtable _dest, Hashtable _src) {
00976     }
00977 
00978     }
00979 

Generated on Wed Dec 14 21:05:35 2005 for OpenMobileIS by  doxygen 1.4.4