KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > Acme > Utils


1 // Utils - assorted static utility routines
2
//
3
// Copyright (C)1996,1998 by Jef Poskanzer <jef@acme.com>. All rights reserved.
4
//
5
// Redistribution and use in source and binary forms, with or without
6
// modification, are permitted provided that the following conditions
7
// are met:
8
// 1. Redistributions of source code must retain the above copyright
9
// notice, this list of conditions and the following disclaimer.
10
// 2. Redistributions in binary form must reproduce the above copyright
11
// notice, this list of conditions and the following disclaimer in the
12
// documentation and/or other materials provided with the distribution.
13
//
14
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17
// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20
// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23
// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24
// SUCH DAMAGE.
25
//
26
// Visit the ACME Labs Java page for up-to-date versions of this and other
27
// fine Java utilities: http://www.acme.com/java/
28

29 package Acme;
30
31 import java.util.*;
32 import java.io.*;
33 import java.net.*;
34
35 /// Assorted static utility routines.
36
// <P>
37
// Whenever I come up with a static routine that might be of general use,
38
// I put it here. So far the class includes:
39
// <UL>
40
// <LI> some string routines that were left out of java.lang.String
41
// <LI> a general array-to-string routine
42
// <LI> a fixed version of java.io.InputStream's byte-array read routine
43
// <LI> a bunch of URL-hacking routines
44
// <LI> some easy-to-use wrappers for Runtime.exec
45
// <LI> a debugging routine to dump the current call stack
46
// <LI> a URLDecoder to match java.net.URLEncoder
47
// </UL>
48
// and lots more.
49
// <P>
50
// <A HREF="../../resources/classes/Acme/Utils.java">Fetch the software.</A><BR>
51
// <A HREF="../../resources/classes/Acme.tar.gz">Fetch the entire Acme package.</A>
52

53 public class Utils
54     {
55
56     /// Returns a date string formatted in Unix ls style - if it's within
57
// six months of now, Mmm dd hh:ss, else Mmm dd yyyy.
58
public static String JavaDoc lsDateStr( Date date )
59         {
60     Calendar cal = new GregorianCalendar();
61     cal.setTime( date );
62         long dateTime = date.getTime();
63     if ( dateTime == -1L )
64         return "------------";
65         long nowTime = (new Date()).getTime();
66         String JavaDoc[] months = {
67             "Jan", "Feb", "Mar", "Apr", "May", "Jun",
68             "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
69         String JavaDoc part1 =
70         months[cal.get(Calendar.MONTH)] +
71         Fmt.fmt( cal.get(Calendar.DATE), 3 );
72         if ( Math.abs( nowTime - dateTime ) < 183L * 24L * 60L * 60L * 1000L )
73             return part1 + Fmt.fmt( cal.get(Calendar.HOUR_OF_DAY), 3 ) + ":" +
74                 Fmt.fmt( cal.get(Calendar.MINUTE), 2, Fmt.ZF );
75         else
76             return part1 + Fmt.fmt( cal.get(Calendar.YEAR), 6 );
77         }
78
79
80     /// Returns "s" for numbers other than one, and "" for one.
81
public static String JavaDoc pluralStr( long n )
82     {
83     if ( n == 1 )
84         return "";
85     else
86         return "s";
87     }
88
89
90     // Various interval constants. Some are only approximate.
91
public static final long INT_SECOND = 1000L;
92     public static final long INT_MINUTE = INT_SECOND * 60L;
93     public static final long INT_HOUR = INT_MINUTE * 60L;
94     public static final long INT_DAY = INT_HOUR * 24L;
95     public static final long INT_WEEK = INT_DAY * 7L;
96     public static final long INT_MONTH = INT_DAY * 30L;
97     public static final long INT_YEAR = INT_DAY * 365L;
98     public static final long INT_DECADE = INT_DAY * 3652L;
99
100     /// Returns a string approximately describing a given time interval.
101
// @param interval the interval, in milliseconds
102
public static String JavaDoc intervalStr( long interval )
103     {
104     long decades, years, months, weeks, days, hours, minutes, seconds, millis;
105
106     decades = interval / INT_DECADE;
107     interval -= decades * INT_DECADE;
108     years = interval / INT_YEAR;
109     interval -= years * INT_YEAR;
110     months = interval / INT_MONTH;
111     interval -= months * INT_MONTH;
112     weeks = interval / INT_WEEK;
113     interval -= weeks * INT_WEEK;
114     days = interval / INT_DAY;
115     interval -= days * INT_DAY;
116     hours = interval / INT_HOUR;
117     interval -= hours * INT_HOUR;
118     minutes = interval / INT_MINUTE;
119     interval -= minutes * INT_MINUTE;
120     seconds = interval / INT_SECOND;
121     interval -= seconds * INT_SECOND;
122     millis = interval;
123
124     if ( decades > 0 )
125         if ( years == 0 )
126         return decades + " decade" + pluralStr( decades );
127         else
128         return
129             decades + " decade" + pluralStr( decades ) + ", " +
130             years + " years" + pluralStr( years );
131     else if ( years > 0 )
132         if ( months == 0 )
133         return years + " year" + pluralStr( years );
134         else
135         return
136             years + " year" + pluralStr( years ) + ", " +
137             months + " month" + pluralStr( months );
138     else if ( months > 0 )
139         if ( weeks == 0 )
140         return months + " month" + pluralStr( months );
141         else
142         return
143             months + " month" + pluralStr( months ) + ", " +
144             weeks + " week" + pluralStr( weeks );
145     else if ( weeks > 0 )
146         if ( days == 0 )
147         return weeks + " week" + pluralStr( weeks );
148         else
149         return
150             weeks + " week" + pluralStr( weeks ) + ", " +
151             days + " day" + pluralStr( days );
152     else if ( days > 0 )
153         if ( hours == 0 )
154         return days + " day" + pluralStr( days );
155         else
156         return
157             days + " day" + pluralStr( days ) + ", " +
158             hours + " hour" + pluralStr( hours );
159     else if ( hours > 0 )
160         if ( minutes == 0 )
161         return hours + " hour" + pluralStr( hours );
162         else
163         return
164             hours + " hour" + pluralStr( hours ) + ", " +
165             minutes + " minute" + pluralStr( minutes );
166     else if ( minutes > 0 )
167         if ( seconds == 0 )
168         return minutes + " minute" + pluralStr( minutes );
169         else
170         return
171             minutes + " minute" + pluralStr( minutes ) + ", " +
172             seconds + " second" + pluralStr( seconds );
173     else if ( seconds > 0 )
174         if ( millis == 0 )
175         return seconds + " second" + pluralStr( seconds );
176         else
177         return
178             seconds + " second" + pluralStr( seconds ) + ", " +
179             millis + " millisecond" + pluralStr( millis );
180     else
181         return millis + " millisecond" + pluralStr( millis );
182     }
183
184
185     /// Returns the length of the initial segment of str which consists
186
// entirely of characters from charSet.
187
public static int strSpan( String JavaDoc str, String JavaDoc charSet )
188     {
189     return strSpan( str, charSet, 0 );
190     }
191
192     /// Returns the length of the initial segment of str which consists
193
// entirely of characters from charSet, starting at the given index.
194
public static int strSpan( String JavaDoc str, String JavaDoc charSet, int fromIdx )
195     {
196     int i;
197     for ( i = fromIdx; i < str.length(); ++i )
198         if ( charSet.indexOf( str.charAt( i ) ) == -1 )
199         break;
200     return i - fromIdx;
201     }
202
203     /// Returns the length of the initial segment of str which consists
204
// entirely of characters NOT from charSet.
205
public static int strCSpan( String JavaDoc str, String JavaDoc charSet )
206     {
207     return strCSpan( str, charSet, 0 );
208     }
209
210     /// Returns the length of the initial segment of str which consists
211
// entirely of characters NOT from charSet, starting at the given index.
212
public static int strCSpan( String JavaDoc str, String JavaDoc charSet, int fromIdx )
213     {
214     int i;
215     for ( i = fromIdx; i < str.length(); ++i )
216         if ( charSet.indexOf( str.charAt( i ) ) != -1 )
217         break;
218     return i - fromIdx;
219     }
220
221     /// Checks whether a string matches a given wildcard pattern.
222
// Only does ? and *, and multiple patterns separated by |.
223
public static boolean match( String JavaDoc pattern, String JavaDoc string )
224     {
225     for ( int p = 0; ; ++p )
226         {
227         for ( int s = 0; ; ++p, ++s )
228         {
229         boolean sEnd = ( s >= string.length() );
230         boolean pEnd = ( p >= pattern.length() ||
231                  pattern.charAt( p ) == '|' );
232         if ( sEnd && pEnd )
233             return true;
234         if ( sEnd || pEnd )
235             break;
236         if ( pattern.charAt( p ) == '?' )
237             continue;
238         if ( pattern.charAt( p ) == '*' )
239             {
240             int i;
241             ++p;
242             for ( i = string.length(); i >= s; --i )
243             if ( match(
244                    pattern.substring( p ),
245                    string.substring( i ) ) ) /* not quite right */
246                 return true;
247             break;
248             }
249         if ( pattern.charAt( p ) != string.charAt( s ) )
250             break;
251         }
252         p = pattern.indexOf( '|', p );
253         if ( p == -1 )
254         return false;
255         }
256     }
257
258 // /// Finds the maximum length of a string that matches a given wildcard
259
// // pattern. Only does ? and *, and multiple patterns separated by |.
260
// public static int matchSpan( String pattern, String string )
261
// {
262
// // !!!
263
// return 0;
264
// }
265

266     /// Returns the length of the initial segment of str1 that equals str2.
267
public static int sameSpan( String JavaDoc str1, String JavaDoc str2 )
268     {
269     int i;
270     for ( i = 0;
271           i < str1.length() && i < str2.length() &&
272         str1.charAt( i ) == str2.charAt( i );
273           ++i )
274         ;
275     return i;
276     }
277
278     /// Returns the number of times the given character appears in the string.
279
public static int charCount( String JavaDoc str, char c )
280     {
281     int n = 0;
282     for ( int i = 0; i < str.length(); ++i )
283         if ( str.charAt( i ) == c )
284         ++n;
285     return n;
286     }
287
288
289     /// Turns a String into an array of Strings, by using StringTokenizer
290
// to split it up at whitespace.
291
public static String JavaDoc[] splitStr( String JavaDoc str )
292     {
293     StringTokenizer st = new StringTokenizer( str );
294     int n = st.countTokens();
295     String JavaDoc[] strs = new String JavaDoc[n];
296     for ( int i = 0; i < n; ++i )
297         strs[i] = st.nextToken();
298     return strs;
299     }
300
301     /// Turns a String into an array of Strings, by splitting it at
302
// the specified character. This does not use StringTokenizer,
303
// and therefore can handle empty fields.
304
public static String JavaDoc[] splitStr( String JavaDoc str, char delim )
305     {
306     int n = 1;
307     int index = -1;
308     while ( true )
309         {
310         index = str.indexOf( delim, index + 1 );
311         if ( index == -1 )
312         break;
313         ++n;
314         }
315     String JavaDoc[] strs = new String JavaDoc[n];
316     index = -1;
317     for ( int i = 0; i < n - 1; ++i )
318         {
319         int nextIndex = str.indexOf( delim, index + 1 );
320         strs[i] = str.substring( index + 1, nextIndex );
321         index = nextIndex;
322         }
323     strs[n - 1] = str.substring( index + 1 );
324     return strs;
325     }
326
327     /// Turns an array of Strings into a single String, with the components
328
// separated by spaces.
329
public static String JavaDoc flattenStrarr( String JavaDoc[] strs )
330     {
331     StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
332     for ( int i = 0; i < strs.length; ++i )
333         {
334         if ( i > 0 )
335         sb.append( ' ' );
336         sb.append( strs[i] );
337         }
338     return sb.toString();
339     }
340
341     /// Sorts an array of Strings.
342
// Java currently has no general sort function. Sorting Strings is
343
// common enough that it's worth making a special case.
344
public static void sortStrings( String JavaDoc[] strings )
345     {
346     // Just does a bubblesort.
347
for ( int i = 0; i < strings.length - 1; ++i )
348         {
349         for ( int j = i + 1; j < strings.length; ++j )
350         {
351         if ( strings[i].compareTo( strings[j] ) > 0 )
352             {
353             String JavaDoc t = strings[i];
354             strings[i] = strings[j];
355             strings[j] = t;
356             }
357         }
358         }
359     }
360     
361     /// Locates a String in an array of Strings.
362
// Returns -1 if the String is not found.
363
public static int indexOfString( String JavaDoc[] strings, String JavaDoc string )
364     {
365     for ( int i = 0; i < strings.length; ++i )
366         if ( string.equals( strings[i] ) )
367         return i;
368     return -1;
369     }
370
371     /// Locates a String in an array of Strings, ignoring case.
372
// Returns -1 if the String is not found.
373
public static int indexOfStringIgnoreCase( String JavaDoc[] strings, String JavaDoc string )
374     {
375     for ( int i = 0; i < strings.length; ++i )
376         if ( string.equalsIgnoreCase( strings[i] ) )
377         return i;
378     return -1;
379     }
380     
381     /// Compares two arrays of Strings for equality.
382
public static boolean equalsStrings( String JavaDoc[] strings1, String JavaDoc[] strings2 )
383     {
384     if ( strings1.length != strings2.length )
385         return false;
386     for ( int i = 0; i < strings1.length; ++i )
387         if ( ! strings1[i].equals( strings2[i] ) )
388         return false;
389     return true;
390     }
391
392
393     /// Returns the number a raised to the power of b. Long version
394
// of Math.pow(). Throws ArithmeticException if b is negative.
395
public static long pow( long a, long b ) throws ArithmeticException JavaDoc
396     {
397     if ( b < 0 )
398         throw new ArithmeticException JavaDoc();
399     long r = 1;
400     while ( b != 0 )
401         {
402         if ( odd( b ) )
403         r *= a;
404         b >>>= 1;
405         a *= a;
406         }
407     return r;
408     }
409
410
411     /// Parse an integer, returning a default value on errors.
412
public static int parseInt( String JavaDoc str, int def )
413     {
414     try
415         {
416         return Integer.parseInt( str );
417         }
418     catch ( Exception JavaDoc e )
419         {
420         return def;
421         }
422     }
423
424     /// Parse a long, returning a default value on errors.
425
public static long parseLong( String JavaDoc str, long def )
426     {
427     try
428         {
429         return Long.parseLong( str );
430         }
431     catch ( Exception JavaDoc e )
432         {
433         return def;
434         }
435     }
436
437
438     /// An array-to-String routine. Handles arrays of arbitrary
439
// type, including nested arrays. Sample output:
440
// <BLOCKQUOTE><CODE><PRE>
441
// byte[]: { (byte)0, (byte)1, (byte)2 }
442
// char[]: { '0', '1', '2' }
443
// short[]: { (short)0, (short)1, (short)2 }
444
// int[]: { 0, 1, 2 }
445
// long[]: { 0L, 1L, 2L }
446
// float[]: { 0F, 1F, 2F }
447
// double[]: { 0D, 1D, 2D }
448
// String[]: { "0", "1", "2" }
449
// int[][]: { { 0, 1, 2 }, { 3, 4, 5 } }
450
// </PRE></CODE></BLOCKQUOTE>
451
public static String JavaDoc arrayToString( Object JavaDoc o )
452     {
453     if ( o == null )
454         return "null";
455     String JavaDoc cl = o.getClass().getName();
456     if ( ! cl.startsWith( "[" ) )
457         // It's not an array; just call its toString method.
458
return o.toString();
459     StringBuffer JavaDoc sb = new StringBuffer JavaDoc( "{ " );
460     if ( o instanceof byte[] )
461         {
462         byte[] ba = (byte[]) o;
463         for ( int i = 0; i < ba.length; ++i )
464         {
465         if ( i > 0 ) sb.append( ", " );
466         sb.append( "(byte)" );
467         sb.append( ba[i] );
468         }
469         }
470     else if ( o instanceof char[] )
471         {
472         char[] ca = (char[]) o;
473         for ( int i = 0; i < ca.length; ++i )
474         {
475         if ( i > 0 ) sb.append( ", " );
476         sb.append( "'" );
477         sb.append( ca[i] );
478         sb.append( "'" );
479         }
480         }
481     else if ( o instanceof short[] )
482         {
483         short[] sa = (short[]) o;
484         for ( int i = 0; i < sa.length; ++i )
485         {
486         if ( i > 0 ) sb.append( ", " );
487         sb.append( "(short)" );
488         sb.append( sa[i] );
489         }
490         }
491     else if ( o instanceof int[] )
492         {
493         int[] ia = (int[]) o;
494         for ( int i = 0; i < ia.length; ++i )
495         {
496         if ( i > 0 ) sb.append( ", " );
497         sb.append( ia[i] );
498         }
499         }
500     else if ( o instanceof long[] )
501         {
502         long[] la = (long[]) o;
503         for ( int i = 0; i < la.length; ++i )
504         {
505         if ( i > 0 ) sb.append( ", " );
506         sb.append( la[i] );
507         sb.append( "L" );
508         }
509         }
510     else if ( o instanceof float[] )
511         {
512         float[] fa = (float[]) o;
513         for ( int i = 0; i < fa.length; ++i )
514         {
515         if ( i > 0 ) sb.append( ", " );
516         sb.append( fa[i] );
517         sb.append( "F" );
518         }
519         }
520     else if ( o instanceof double[] )
521         {
522         double[] da = (double[]) o;
523         for ( int i = 0; i < da.length; ++i )
524         {
525         if ( i > 0 ) sb.append( ", " );
526         sb.append( da[i] );
527         sb.append( "D" );
528         }
529         }
530     else if ( o instanceof String JavaDoc )
531         {
532         // Special-case Strings so we can surround them with quotes.
533
String JavaDoc[] sa = (String JavaDoc[]) o;
534         for ( int i = 0; i < sa.length; ++i )
535         {
536         if ( i > 0 ) sb.append( ", " );
537         sb.append( "\"" );
538         sb.append( sa[i] );
539         sb.append( "\"" );
540         }
541         }
542     else if ( cl.startsWith( "[L" ) )
543         {
544         // Some random class.
545
Object JavaDoc[] oa = (Object JavaDoc[]) o;
546         for ( int i = 0; i < oa.length; ++i )
547         {
548         if ( i > 0 ) sb.append( ", " );
549         sb.append( oa[i] );
550         }
551         }
552     else if ( cl.startsWith( "[[" ) )
553         {
554         // Nested arrays.
555
Object JavaDoc[] aa = (Object JavaDoc[]) o;
556         for ( int i = 0; i < aa.length; ++i )
557         {
558         if ( i > 0 ) sb.append( ", " );
559         sb.append( arrayToString( aa[i] ) );
560         }
561         }
562     else
563         sb.append( "(unknown array type)" );
564     sb.append( " }" );
565     return sb.toString();
566     }
567
568
569     /// Check if an object extends a given class or one of its superclasses.
570
// An instanceof that works on Class objects at runtime, instead
571
// of type descriptors at compile time.
572
public static boolean instanceOf( Object JavaDoc o, Class JavaDoc cl )
573     {
574     // Null check.
575
if ( o == null || cl == null )
576         return false;
577     Class JavaDoc ocl = o.getClass();
578     // Check if they are the same class.
579
if ( ocl.equals( cl ) )
580         return true;
581     // If the class is not itself an interface, then check its interfaces.
582
if ( ! cl.isInterface() )
583         {
584         Class JavaDoc ifs[] = cl.getInterfaces();
585         for ( int i = 0; i < ifs.length; ++i )
586         if ( instanceOf( o, ifs[i] ) )
587             return true;
588         }
589     // And check supeclasses.
590
Class JavaDoc scl = cl.getSuperclass();
591     if ( scl != null )
592         if ( instanceOf( o, scl ) )
593         return true;
594     // Guess not.
595
return false;
596     }
597
598
599     /// Test is a number is even.
600
public static boolean even( long n )
601     {
602     return ( n & 1 ) == 0;
603     }
604
605     /// Test is a number is odd.
606
public static boolean odd( long n )
607     {
608     return ( n & 1 ) != 0;
609     }
610
611
612     /// Count the number of 1-bits in a byte.
613
public static int countOnes( byte n )
614     {
615     return countOnes( n & 0xffL );
616     }
617
618     /// Count the number of 1-bits in an int.
619
public static int countOnes( int n )
620     {
621     return countOnes( n & 0xffffffffL );
622     }
623
624     /// Count the number of 1-bits in a long.
625
public static int countOnes( long n )
626     {
627     // There are faster ways to do this, all the way up to looking
628
// up bytes in a 256-element table. But this is not too bad.
629
int count = 0;
630     while ( n != 0 )
631         {
632         if ( odd( n ) )
633         ++count;
634         n >>>= 1;
635         }
636     return count;
637     }
638
639
640     /// A fixed version of java.io.InputStream.read(byte[], int, int). The
641
// standard version catches and ignores IOExceptions from below.
642
// This version sends them on to the caller.
643
public static int read( InputStream in, byte[] b, int off, int len ) throws IOException
644         {
645         if ( len <= 0 )
646             return 0;
647         int c = in.read();
648         if ( c == -1 )
649             return -1;
650         if ( b != null )
651             b[off] = (byte) c;
652         int i;
653         for ( i = 1; i < len ; ++i )
654             {
655             c = in.read();
656             if ( c == -1 )
657                 break;
658             if ( b != null )
659                 b[off + i] = (byte) c;
660             }
661         return i;
662         }
663
664     /// A version of read that reads the entire requested block, instead
665
// of sometimes terminating early.
666
// @return -1 on EOF, otherwise len
667
public static int readFully( InputStream in, byte[] b, int off, int len ) throws IOException
668         {
669     int l, r;
670     for ( l = 0; l < len; )
671         {
672         r = read( in, b, l, len - l );
673         if ( r == -1 )
674         return -1;
675         l += r;
676         }
677     return len;
678     }
679
680
681     /// Make a URL with no ref part and no query string. Also, if it's
682
// a directory then make sure there's a trailing slash.
683
public static URL plainUrl( URL context, String JavaDoc urlStr ) throws MalformedURLException
684     {
685     URL url = new URL( context, urlStr );
686     String JavaDoc fileStr = url.getFile();
687     int i = fileStr.indexOf( '?' );
688     if ( i != -1 )
689         fileStr = fileStr.substring( 0, i );
690     url = new URL(
691         url.getProtocol(), url.getHost(), url.getPort(), fileStr );
692     if ( ( ! fileStr.endsWith( "/" ) ) &&
693          urlStrIsDir( url.toExternalForm() ) )
694         {
695         fileStr = fileStr + "/";
696         url = new URL(
697         url.getProtocol(), url.getHost(), url.getPort(), fileStr );
698         }
699     return url;
700     }
701
702     /// Make a URL with no ref part and no query string. Also, if it's
703
// a directory then make sure there's a trailing slash.
704
public static URL plainUrl( String JavaDoc urlStr ) throws MalformedURLException
705     {
706         return plainUrl( null, urlStr );
707         }
708
709     /// Figure out the base URL for a given URL. What this means is
710
// if the URL points to a directory, you get that directory; if the
711
// URL points to a file, you get the directory the file is in.
712
public static String JavaDoc baseUrlStr( String JavaDoc urlStr )
713     {
714     if ( urlStr.endsWith( "/" ) )
715         return urlStr;
716     if ( urlStrIsDir( urlStr ) )
717         return urlStr + "/";
718     return urlStr.substring( 0, urlStr.lastIndexOf( '/' ) + 1 );
719     }
720
721     /// Makes sure if a URL is a directory, it ends with a slash.
722
public static String JavaDoc fixDirUrlStr( String JavaDoc urlStr )
723     {
724     if ( urlStr.endsWith( "/" ) )
725         return urlStr;
726     if ( urlStrIsDir( urlStr ) )
727         return urlStr + "/";
728     return urlStr;
729     }
730
731     /// Figures out whether a URL points to a directory or not.
732
// Web servers are lenient and accept directory-URLs without
733
// the trailing slash. What they actually do is return a
734
// redirect to the same URL with the trailing slash appended.
735
// Unfortunately, Java doesn't let us see that such a redirect
736
// happened. Instead we have to figure out it's a directory
737
// indirectly and heuristically.
738
public static boolean urlStrIsDir( String JavaDoc urlStr )
739     {
740     // If it ends with a slash, it's probably a directory.
741
if ( urlStr.endsWith( "/" ) )
742         return true;
743
744     // If the last component has a dot, it's probably not a directory.
745
int lastSlash = urlStr.lastIndexOf( '/' );
746     int lastPeriod = urlStr.lastIndexOf( '.' );
747     if ( lastPeriod != -1 && ( lastSlash == -1 || lastPeriod > lastSlash ) )
748         return false;
749
750     // Otherwise, append a slash and try to connect. This is
751
// fairly expensive.
752
String JavaDoc urlStrWithSlash = urlStr + "/";
753     try
754         {
755         URL url = new URL( urlStrWithSlash );
756         InputStream f = url.openStream();
757         f.close();
758         // Worked fine - it's probably a directory.
759
return true;
760         }
761     catch ( Exception JavaDoc e )
762         {
763         // Got an error - must not be a directory.
764
return false;
765         }
766     }
767
768
769     // Figures out whether a URL is absolute or not.
770
public static boolean urlStrIsAbsolute( String JavaDoc urlStr )
771     {
772     if ( urlStr.startsWith( "/" ) || urlStr.indexOf( ":/" ) != -1 )
773         return true;
774     // Should handle :8000/ and such too.
775
return false;
776     }
777
778     // Returns an equivalent URL string that is guaranteed to be absolute.
779
public static String JavaDoc absoluteUrlStr( String JavaDoc urlStr, URL contextUrl ) throws MalformedURLException
780     {
781     URL url = new URL( contextUrl, urlStr );
782     return url.toExternalForm();
783     }
784     
785
786     /// URLDecoder to go along with java.net.URLEncoder. Why there isn't
787
// already a decoder in the standard library is a mystery to me.
788
public static String JavaDoc urlDecoder( String JavaDoc encoded )
789     {
790     StringBuffer JavaDoc decoded = new StringBuffer JavaDoc();
791     int len = encoded.length();
792     for ( int i = 0; i < len; ++i )
793         {
794         if ( encoded.charAt( i ) == '%' && i + 2 < len )
795         {
796         int d1 = Character.digit( encoded.charAt( i + 1 ), 16 );
797         int d2 = Character.digit( encoded.charAt( i + 2 ), 16 );
798         if ( d1 != -1 && d2 != -1 )
799             decoded.append( (char) ( ( d1 << 4 ) + d2 ) );
800         i += 2;
801         }
802         else if ( encoded.charAt( i ) == '+' )
803         decoded.append( ' ' );
804         else
805         decoded.append( encoded.charAt( i ) );
806         }
807     return decoded.toString();
808     }
809     
810
811     /// A base-64 encoder, necessary for doing the client side of Basic
812
// Authentication. This encodes binary data as printable ASCII
813
// characters. Three 8-bit binary bytes are turned into four 6-bit
814
// values, like so:
815
//
816
// [11111111] [22222222] [33333333]
817
//
818
// [111111] [112222] [222233] [333333]
819
//
820
// Then the 6-bit values are represented using the characters "A-Za-z0-9+/".
821
public static String JavaDoc base64Encode( byte[] src )
822     {
823     StringBuffer JavaDoc encoded = new StringBuffer JavaDoc();
824     int i, phase = 0;
825     char c = 0;
826
827     for ( i = 0; i < src.length; ++i )
828         {
829         switch ( phase )
830         {
831         case 0:
832         c = b64EncodeTable[( src[i] >> 2 ) & 0x3f];
833         encoded.append( c );
834         c = b64EncodeTable[( src[i] & 0x3 ) << 4];
835         encoded.append( c );
836         ++phase;
837         break;
838         case 1:
839         c = b64EncodeTable[
840             ( b64DecodeTable[c] | ( src[i] >> 4 ) ) & 0x3f];
841         encoded.setCharAt( encoded.length() - 1, c );
842         c = b64EncodeTable[( src[i] & 0xf ) << 2];
843         encoded.append( c );
844         ++phase;
845         break;
846         case 2:
847         c = b64EncodeTable[
848             ( b64DecodeTable[c] | ( src[i] >> 6 ) ) & 0x3f];
849         encoded.setCharAt( encoded.length() - 1, c );
850         c = b64EncodeTable[src[i] & 0x3f];
851         encoded.append( c );
852         phase = 0;
853         break;
854         }
855         }
856     /* Pad with ='s. */
857     while ( phase++ < 3 )
858         encoded.append( '=' );
859     return encoded.toString();
860     }
861
862     private static char b64EncodeTable[] = {
863     'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', // 00-07
864
'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', // 08-15
865
'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', // 16-23
866
'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', // 24-31
867
'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', // 32-39
868
'o', 'p', 'q', 'r', 's', 't', 'u', 'v', // 40-47
869
'w', 'x', 'y', 'z', '0', '1', '2', '3', // 48-55
870
'4', '5', '6', '7', '8', '9', '+', '/' // 56-63
871
};
872
873     private static int b64DecodeTable[] = {
874     -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, // 00-0F
875
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, // 10-1F
876
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,62,-1,-1,-1,63, // 20-2F
877
52,53,54,55,56,57,58,59,60,61,-1,-1,-1,-1,-1,-1, // 30-3F
878
-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14, // 40-4F
879
15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,-1, // 50-5F
880
-1,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40, // 60-6F
881
41,42,43,44,45,46,47,48,49,50,51,-1,-1,-1,-1,-1, // 70-7F
882
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, // 80-8F
883
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, // 90-9F
884
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, // A0-AF
885
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, // B0-BF
886
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, // C0-CF
887
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, // D0-DF
888
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, // E0-EF
889
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 // F0-FF
890
};
891
892     /// A base-64 encoder that takes a String, for convenience.
893
public static String JavaDoc base64Encode( String JavaDoc srcString )
894     {
895     byte[] src = new byte[srcString.length()];
896     srcString.getBytes( 0, src.length, src, 0 );
897     return base64Encode( src );
898     }
899
900
901     /// Check if an array contains a given element.
902
public static boolean arraycontains( Object JavaDoc[] array, Object JavaDoc element )
903     {
904     for ( int i = 0; i < array.length; ++i )
905         if ( array[i].equals( element ) )
906         return true;
907     return false;
908     }
909
910
911     /// Run a program on the host system.
912
// <P>
913
// This routine runs the specified command, waits for it to
914
// finish, and returns the exit status.
915
// This is like the Unix system() routine. Unlike the Unix version,
916
// though, stdout and stderr get thrown away unless you redirect them.
917
public static int system( String JavaDoc cmd )
918     {
919     try
920         {
921         return runCommand( cmd ).waitFor();
922         }
923     catch ( IOException e )
924         {
925         return -1;
926         }
927     catch ( InterruptedException JavaDoc e )
928         {
929         return -1;
930         }
931     }
932
933     /// Run a program on the host system, and capture the output.
934
// <P>
935
// This routine runs the specified command, and returns an InputStream
936
// for reading the output of the program.
937
// <P>
938
// <B>WARNING:</B> In JDK1.0.2 there is a serious bug in the process
939
// IO routines, such that reading all the way to the end of a process's
940
// output will invariably get you an IOException( "read error" ).
941
// In some cases you will also <B>lose</B> the last bufferload of
942
// the output. The workaround is to add a " ; sleep 1" to the end of
943
// your command, and to ignore the "read error" IOException.
944
public static InputStream popenr( String JavaDoc cmd )
945     {
946     try
947         {
948         return runCommand( cmd ).getInputStream();
949         }
950     catch ( IOException e )
951         {
952         return null;
953         }
954     }
955
956     /// Run a program on the host system, and send it some input.
957
// <P>
958
// This routine runs the specified command, and returns an OutputStream
959
// for writing the program's input.
960
public static OutputStream popenw( String JavaDoc cmd )
961     {
962     try
963         {
964         return runCommand( cmd ).getOutputStream();
965         }
966     catch ( IOException e )
967         {
968         return null;
969         }
970     }
971
972     /// Run a program on the host system.
973
// <P>
974
// This routine runs the specified command, and returns a Process
975
// object so you can do what you like with it.
976
// <P>
977
// <B>WARNING:</B> In JDK1.0.2 there is a serious bug in the process
978
// IO routines, such that reading all the way to the end of a process's
979
// output will invariably get you an IOException( "read error" ).
980
// In some cases you will also <B>lose</B> the last bufferload of
981
// the output. The workaround is to add a " ; sleep 1" to the end of
982
// your command, and to ignore the "read error" IOException.
983
public static Process JavaDoc runCommand( String JavaDoc cmd ) throws IOException
984     {
985     Runtime JavaDoc runtime = Runtime.getRuntime();
986     String JavaDoc[] shCmd = new String JavaDoc[3];
987     shCmd[0] = "/bin/sh";
988     shCmd[1] = "-c";
989     shCmd[2] = cmd;
990     return runtime.exec( shCmd );
991     }
992
993
994     /// Copy the input to the output until EOF.
995
public static void copyStream( InputStream in, OutputStream out ) throws IOException
996     {
997     byte[] buf = new byte[4096];
998     int len;
999     while ( ( len = in.read( buf ) ) != -1 )
1000        out.write( buf, 0, len );
1001    }
1002
1003    /// Copy the input to the output until EOF.
1004
public static void copyStream( Reader in, Writer out ) throws IOException
1005    {
1006    char[] buf = new char[4096];
1007    int len;
1008    while ( ( len = in.read( buf ) ) != -1 )
1009        out.write( buf, 0, len );
1010    }
1011
1012    /// Copy the input to the output until EOF.
1013
public static void copyStream( InputStream in, Writer out ) throws IOException
1014    {
1015    byte[] buf1 = new byte[4096];
1016    char[] buf2 = new char[4096];
1017    int len, i;
1018    while ( ( len = in.read( buf1 ) ) != -1 )
1019        {
1020        for ( i = 0; i < len; ++i )
1021        buf2[i] = (char) buf1[i];
1022        out.write( buf2, 0, len );
1023        }
1024    }
1025
1026    /// Copy the input to the output until EOF.
1027
public static void copyStream( Reader in, OutputStream out ) throws IOException
1028    {
1029    char[] buf1 = new char[4096];
1030    byte[] buf2 = new byte[4096];
1031    int len, i;
1032    while ( ( len = in.read( buf1 ) ) != -1 )
1033        {
1034        for ( i = 0; i < len; ++i )
1035        buf2[i] = (byte) buf1[i];
1036        out.write( buf2, 0, len );
1037        }
1038    }
1039
1040
1041    /// Dump out the current call stack.
1042
public static void dumpStack( PrintStream p )
1043    {
1044    (new Throwable JavaDoc()).printStackTrace( p );
1045    }
1046
1047    /// Dump out the current call stack onto System.err.
1048
public static void dumpStack()
1049    {
1050    (new Throwable JavaDoc()).printStackTrace();
1051    }
1052
1053    }
1054
Popular Tags