KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > google > gwt > dev > util > Util


1 /*
2  * Copyright 2006 Google Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5  * use this file except in compliance with the License. You may obtain a copy of
6  * the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13  * License for the specific language governing permissions and limitations under
14  * the License.
15  */

16 package com.google.gwt.dev.util;
17
18 import com.google.gwt.core.ext.TreeLogger;
19 import com.google.gwt.core.ext.UnableToCompleteException;
20 import com.google.gwt.core.ext.typeinfo.TypeOracle;
21 import com.google.gwt.util.tools.Utility;
22
23 import org.w3c.dom.Attr JavaDoc;
24 import org.w3c.dom.DOMException JavaDoc;
25 import org.w3c.dom.Document JavaDoc;
26 import org.w3c.dom.Element JavaDoc;
27 import org.w3c.dom.NamedNodeMap JavaDoc;
28 import org.w3c.dom.Node JavaDoc;
29 import org.w3c.dom.Text JavaDoc;
30
31 import java.io.BufferedReader JavaDoc;
32 import java.io.BufferedWriter JavaDoc;
33 import java.io.File JavaDoc;
34 import java.io.FileInputStream JavaDoc;
35 import java.io.FileNotFoundException JavaDoc;
36 import java.io.FileOutputStream JavaDoc;
37 import java.io.FilenameFilter JavaDoc;
38 import java.io.IOException JavaDoc;
39 import java.io.InputStream JavaDoc;
40 import java.io.InputStreamReader JavaDoc;
41 import java.io.OutputStream JavaDoc;
42 import java.io.OutputStreamWriter JavaDoc;
43 import java.io.PrintWriter JavaDoc;
44 import java.io.RandomAccessFile JavaDoc;
45 import java.io.Reader JavaDoc;
46 import java.io.StringWriter JavaDoc;
47 import java.io.UnsupportedEncodingException JavaDoc;
48 import java.lang.reflect.Array JavaDoc;
49 import java.lang.reflect.InvocationTargetException JavaDoc;
50 import java.lang.reflect.Method JavaDoc;
51 import java.net.MalformedURLException JavaDoc;
52 import java.net.URL JavaDoc;
53 import java.net.URLConnection JavaDoc;
54 import java.net.URLDecoder JavaDoc;
55 import java.security.MessageDigest JavaDoc;
56 import java.security.NoSuchAlgorithmException JavaDoc;
57 import java.util.Collection JavaDoc;
58 import java.util.Iterator JavaDoc;
59 import java.util.jar.JarEntry JavaDoc;
60
61 /**
62  * A smattering of useful methods. Methods in this class are candidates for
63  * being moved to {@link com.google.gwt.util.tools.Utility} if they would be
64  * generally useful to tool writers, and don't involve TreeLogger.
65  */

66 public final class Util {
67
68   public static String JavaDoc DEFAULT_ENCODING = "UTF-8";
69
70   public static final File JavaDoc[] EMPTY_ARRAY_FILE = new File JavaDoc[0];
71
72   public static final String JavaDoc[] EMPTY_ARRAY_STRING = new String JavaDoc[0];
73
74   public static char[] HEX_CHARS = new char[] {
75       '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D',
76       'E', 'F'};
77
78   public static void addAll(Collection JavaDoc c, Object JavaDoc[] a) {
79     for (int i = 0; i < a.length; i++) {
80       c.add(a[i]);
81     }
82   }
83
84   public static byte[] append(byte[] xs, byte x) {
85     int n = xs.length;
86     byte[] t = new byte[n + 1];
87     System.arraycopy(xs, 0, t, 0, n);
88     t[n] = x;
89     return t;
90   }
91
92   public static Object JavaDoc[] append(Object JavaDoc[] xs, Object JavaDoc x) {
93     int n = xs.length;
94     Object JavaDoc[] t = (Object JavaDoc[]) Array.newInstance(xs.getClass().getComponentType(),
95         n + 1);
96     System.arraycopy(xs, 0, t, 0, n);
97     t[n] = x;
98     return t;
99   }
100
101   public static Object JavaDoc[] append(Object JavaDoc[] appendToThis, Object JavaDoc[] these) {
102     if (appendToThis == null) {
103       throw new NullPointerException JavaDoc("attempt to append to a null array");
104     }
105
106     if (these == null) {
107       throw new NullPointerException JavaDoc("attempt to append a null array");
108     }
109
110     Object JavaDoc[] result;
111     int newSize = appendToThis.length + these.length;
112     Class JavaDoc componentType = appendToThis.getClass().getComponentType();
113     result = (Object JavaDoc[]) Array.newInstance(componentType, newSize);
114     System.arraycopy(appendToThis, 0, result, 0, appendToThis.length);
115     System.arraycopy(these, 0, result, appendToThis.length, these.length);
116     return result;
117   }
118
119   /**
120    * Computes the MD5 hash for the specified byte array.
121    *
122    * @return a big fat string encoding of the MD5 for the content, suitably
123    * formatted for use as a file name
124    */

125   public static String JavaDoc computeStrongName(byte[] content) {
126     MessageDigest JavaDoc md5;
127     try {
128       md5 = MessageDigest.getInstance("MD5");
129     } catch (NoSuchAlgorithmException JavaDoc e) {
130       throw new RuntimeException JavaDoc("Error initializing MD5", e);
131     }
132
133     for (int i = 0; i < content.length; i++) {
134       md5.update(content[i]);
135     }
136
137     byte[] hash = md5.digest();
138
139     // Hex version of the hash.
140
//
141
char[] name = new char[2 * hash.length];
142     int j = 0;
143     for (int i = 0; i < hash.length; i++) {
144       name[j++] = HEX_CHARS[(hash[i] & 0xF0) >> 4];
145       name[j++] = HEX_CHARS[hash[i] & 0x0F];
146     }
147
148     return new String JavaDoc(name);
149   }
150
151   public static boolean copy(TreeLogger logger, File JavaDoc in, File JavaDoc out)
152       throws UnableToCompleteException {
153     FileInputStream JavaDoc fis = null;
154     try {
155       if (in.lastModified() > out.lastModified()) {
156         fis = new FileInputStream JavaDoc(in);
157         copy(logger, fis, out);
158         return true;
159       } else {
160         return false;
161       }
162     } catch (FileNotFoundException JavaDoc e) {
163       logger.log(TreeLogger.ERROR, "Unable to open file '"
164           + in.getAbsolutePath() + "'", e);
165       throw new UnableToCompleteException();
166     } finally {
167       Utility.close(fis);
168     }
169   }
170
171   public static void copy(TreeLogger logger, InputStream JavaDoc is, File JavaDoc out)
172       throws UnableToCompleteException {
173     FileOutputStream JavaDoc fos = null;
174     try {
175       out.getParentFile().mkdirs();
176       fos = new FileOutputStream JavaDoc(out);
177       copy(logger, is, fos);
178     } catch (FileNotFoundException JavaDoc e) {
179       logger.log(TreeLogger.ERROR, "Unable to create file '"
180           + out.getAbsolutePath() + "'", e);
181       throw new UnableToCompleteException();
182     } finally {
183       Utility.close(fos);
184     }
185   }
186
187   public static void copy(TreeLogger logger, InputStream JavaDoc is, OutputStream JavaDoc os)
188       throws UnableToCompleteException {
189     try {
190       byte[] buf = new byte[8 * 1024];
191       int i = 0;
192       while ((i = is.read(buf)) != -1) {
193         os.write(buf, 0, i);
194       }
195     } catch (IOException JavaDoc e) {
196       logger.log(TreeLogger.ERROR, "Error during copy", e);
197       throw new UnableToCompleteException();
198     }
199   }
200
201   public static boolean copy(TreeLogger logger, URL JavaDoc in, File JavaDoc out)
202       throws UnableToCompleteException {
203     InputStream JavaDoc is = null;
204     try {
205       URLConnection JavaDoc conn = in.openConnection();
206       if (conn.getLastModified() > out.lastModified()) {
207         is = in.openStream();
208         copy(logger, is, out);
209         return true;
210       } else {
211         return false;
212       }
213     } catch (IOException JavaDoc e) {
214       logger.log(TreeLogger.ERROR, "Unable to open '" + in.toExternalForm()
215           + "'", e);
216       throw new UnableToCompleteException();
217     } finally {
218       Utility.close(is);
219     }
220   }
221
222   public static Reader JavaDoc createReader(TreeLogger logger, URL JavaDoc url)
223       throws UnableToCompleteException {
224     try {
225       return new InputStreamReader JavaDoc(url.openStream());
226     } catch (IOException JavaDoc e) {
227       logger.log(TreeLogger.ERROR, "Unable to open resource: " + url, e);
228       throw new UnableToCompleteException();
229     }
230   }
231
232   public static void deleteFilesInDirectory(File JavaDoc dir) {
233     File JavaDoc[] files = dir.listFiles();
234     if (files != null) {
235       for (int i = 0; i < files.length; i++) {
236         File JavaDoc file = files[i];
237         if (file.isFile()) {
238           file.delete();
239         }
240       }
241     }
242   }
243
244   /**
245    * Deletes all files have the same base name as the specified file.
246    */

247   public static void deleteFilesStartingWith(File JavaDoc dir, final String JavaDoc prefix) {
248     File JavaDoc[] toDelete = dir.listFiles(new FilenameFilter JavaDoc() {
249       public boolean accept(File JavaDoc dir, String JavaDoc name) {
250         return name.startsWith(prefix);
251       }
252     });
253
254     if (toDelete != null) {
255       for (int i = 0; i < toDelete.length; i++) {
256         toDelete[i].delete();
257       }
258     }
259   }
260
261   /**
262    * Converts a URL "jar:file:aaa.jar!bbb" to the filename "aaa.jar". This also
263    * does URLDecoding if needed.
264    *
265    * @param location the URL pointing at a jar location
266    * @return the path to the jar file
267    */

268   public static String JavaDoc findFileName(String JavaDoc location) {
269     String JavaDoc newLocation = location;
270     if ((location.startsWith("zip:file:"))
271         || (location.startsWith("jar:file:"))) {
272       int lastIndexOfExclam = newLocation.lastIndexOf('!');
273       // This file lives in a jar or zipfile
274
// we pretend the location is the jar or zip file
275
if (lastIndexOfExclam != -1) {
276         newLocation = newLocation.substring(0, lastIndexOfExclam);
277       }
278       newLocation = newLocation.substring(9);
279       // If the file does not exist that may be because the path is
280
// URLEncoded. Therefore, decode it.
281
if (!new File JavaDoc(newLocation).exists()) {
282         try {
283           newLocation = URLDecoder.decode(newLocation, DEFAULT_ENCODING);
284         } catch (UnsupportedEncodingException JavaDoc e) {
285           // An unsupported encoding indicates confusion; do nothing.
286
return location;
287         }
288       }
289     }
290     return newLocation;
291   }
292
293   public static URL JavaDoc findSourceInClassPath(ClassLoader JavaDoc cl, String JavaDoc sourceTypeName) {
294     String JavaDoc toTry = sourceTypeName.replace('.', '/') + ".java";
295     URL JavaDoc foundURL = cl.getResource(toTry);
296     if (foundURL != null) {
297       return foundURL;
298     }
299     int i = sourceTypeName.lastIndexOf('.');
300     if (i != -1) {
301       return findSourceInClassPath(cl, sourceTypeName.substring(0, i));
302     } else {
303       return null;
304     }
305   }
306
307   /**
308    * @param cls A class whose name you want.
309    * @return The base name for the specified class.
310    */

311   public static String JavaDoc getClassName(Class JavaDoc cls) {
312     return getClassName(cls.getName());
313   }
314
315   /**
316    * @param className A fully-qualified class name whose name you want.
317    * @return The base name for the specified class.
318    */

319   public static String JavaDoc getClassName(String JavaDoc className) {
320     return className.substring(className.lastIndexOf('.') + 1);
321   }
322
323   /**
324    * Gets the contents of a file.
325    *
326    * @param relativePath relative path within the install directory
327    * @return the contents of the file, or null if an error occurred
328    */

329   public static String JavaDoc getFileFromInstallPath(String JavaDoc relativePath) {
330     String JavaDoc installPath = Utility.getInstallPath();
331     File JavaDoc file = new File JavaDoc(installPath + '/' + relativePath);
332     return readFileAsString(file);
333   }
334
335   /**
336    * A 4-digit hex result.
337    */

338   public static void hex4(char c, StringBuffer JavaDoc sb) {
339     sb.append(HEX_CHARS[(c & 0xF000) >> 12]);
340     sb.append(HEX_CHARS[(c & 0x0F00) >> 8]);
341     sb.append(HEX_CHARS[(c & 0x00F0) >> 4]);
342     sb.append(HEX_CHARS[c & 0x000F]);
343   }
344
345   /**
346    * This method invokes an inaccessable method in another class.
347    *
348    * @param targetClass the class owning the method
349    * @param methodName the name of the method
350    * @param argumentTypes the types of the parameters to the method call
351    * @param target the receiver of the method call
352    * @param arguments the parameters to the method call
353    */

354   public static void invokeInaccessableMethod(Class JavaDoc targetClass,
355       String JavaDoc methodName, Class JavaDoc[] argumentTypes, TypeOracle target,
356       Object JavaDoc[] arguments) {
357     String JavaDoc failedReflectErrMsg = "The definition of " + targetClass.getName()
358         + "." + methodName + " has changed in an " + "incompatible way.";
359     try {
360       Method JavaDoc m = targetClass.getDeclaredMethod(methodName, argumentTypes);
361       m.setAccessible(true);
362       m.invoke(target, arguments);
363     } catch (NoSuchMethodException JavaDoc e) {
364       throw new RuntimeException JavaDoc(failedReflectErrMsg, e);
365     } catch (IllegalArgumentException JavaDoc e) {
366       throw new RuntimeException JavaDoc(failedReflectErrMsg, e);
367     } catch (IllegalAccessException JavaDoc e) {
368       throw new RuntimeException JavaDoc(failedReflectErrMsg, e);
369     } catch (InvocationTargetException JavaDoc e) {
370       throw new RuntimeException JavaDoc(failedReflectErrMsg, e);
371     }
372   }
373
374   public static boolean isCompilationUnitOnDisk(String JavaDoc loc) {
375     try {
376       if (new File JavaDoc(loc).exists()) {
377         return true;
378       }
379
380       URL JavaDoc url = new URL JavaDoc(loc);
381       String JavaDoc s = url.toExternalForm();
382       if (s.startsWith("file:") || s.startsWith("jar:")) {
383         return true;
384       }
385     } catch (MalformedURLException JavaDoc e) {
386       // Probably not really on disk.
387
}
388     return false;
389   }
390
391   public static boolean isValidJavaIdent(String JavaDoc token) {
392     if (token.length() == 0) {
393       return false;
394     }
395
396     if (!Character.isJavaIdentifierStart(token.charAt(0))) {
397       return false;
398     }
399
400     for (int i = 1, n = token.length(); i < n; i++) {
401       if (!Character.isJavaIdentifierPart(token.charAt(i))) {
402         return false;
403       }
404     }
405
406     return true;
407   }
408
409   public static void logMissingTypeErrorWithHints(TreeLogger logger,
410       String JavaDoc missingType) {
411     logger = logger.branch(TreeLogger.ERROR, "Unable to find type '"
412         + missingType + "'", null);
413
414     ClassLoader JavaDoc cl = Thread.currentThread().getContextClassLoader();
415
416     URL JavaDoc sourceURL = findSourceInClassPath(cl, missingType);
417     if (sourceURL != null) {
418       if (missingType.indexOf(".client.") != -1) {
419         Messages.HINT_PRIOR_COMPILER_ERRORS.log(logger, null);
420         Messages.HINT_CHECK_MODULE_INHERITANCE.log(logger, null);
421       } else {
422         // Give the best possible hint here.
423
//
424
if (findSourceInClassPath(cl, missingType) == null) {
425           Messages.HINT_CHECK_MODULE_NONCLIENT_SOURCE_DECL.log(logger, null);
426         } else {
427           Messages.HINT_PRIOR_COMPILER_ERRORS.log(logger, null);
428         }
429       }
430     } else if (!missingType.equals("java.lang.Object")) {
431       Messages.HINT_CHECK_TYPENAME.log(logger, missingType, null);
432       Messages.HINT_CHECK_CLASSPATH_SOURCE_ENTRIES.log(logger, null);
433     }
434
435     // For Object in particular, there's a special warning.
436
//
437
if (missingType.indexOf("java.lang.") == 0) {
438       Messages.HINT_CHECK_INHERIT_CORE.log(logger, null);
439     } else if (missingType.indexOf("com.google.gwt.core.") == 0) {
440       Messages.HINT_CHECK_INHERIT_CORE.log(logger, null);
441     } else if (missingType.indexOf("com.google.gwt.user.") == 0) {
442       Messages.HINT_CHECK_INHERIT_USER.log(logger, null);
443     }
444   }
445
446   // /**
447
// * Reads the file as an array of strings.
448
// */
449
// public static String[] readURLAsStrings(URL url) {
450
// ArrayList lines = new ArrayList();
451
// String contents = readURLAsString(url);
452
// if (contents != null) {
453
// StringReader sr = new StringReader(contents);
454
// BufferedReader br = new BufferedReader(sr);
455
// String line;
456
// while (null != (line = readNextLine(br)))
457
// lines.add(line);
458
// }
459
// return (String[]) lines.toArray(new String[lines.size()]);
460
// }
461

462   /**
463    * Attempts to make a path relative to a particular directory.
464    *
465    * @param from the directory from which 'to' should be relative
466    * @param to an absolute path which will be returned so that it is relative to
467    * 'from'
468    * @return the relative path, if possible; null otherwise
469    */

470   public static File JavaDoc makeRelativeFile(File JavaDoc from, File JavaDoc to) {
471
472     // Keep ripping off directories from the 'from' path until the 'from' path
473
// is a prefix of the 'to' path.
474
//
475
String JavaDoc toPath = tryMakeCanonical(to).getAbsolutePath();
476     File JavaDoc currentFrom = tryMakeCanonical(from.isDirectory() ? from
477         : from.getParentFile());
478
479     int numberOfBackups = 0;
480     while (currentFrom != null) {
481       String JavaDoc currentFromPath = currentFrom.getPath();
482       if (toPath.startsWith(currentFromPath)) {
483         // Found a prefix!
484
//
485
break;
486       } else {
487         ++numberOfBackups;
488         currentFrom = currentFrom.getParentFile();
489       }
490     }
491
492     if (currentFrom == null) {
493       // Cannot make it relative.
494
//
495
return null;
496     }
497
498     // Find everything to the right of the common prefix.
499
//
500
String JavaDoc trailingToPath = toPath.substring(currentFrom.getAbsolutePath().length());
501     if (currentFrom.getParentFile() != null && trailingToPath.length() > 0) {
502       trailingToPath = trailingToPath.substring(1);
503     }
504
505     File JavaDoc relativeFile = new File JavaDoc(trailingToPath);
506     for (int i = 0; i < numberOfBackups; ++i) {
507       relativeFile = new File JavaDoc("..", relativeFile.getPath());
508     }
509
510     return relativeFile;
511   }
512
513   public static String JavaDoc makeRelativePath(File JavaDoc from, File JavaDoc to) {
514     File JavaDoc f = makeRelativeFile(from, to);
515     return (f != null ? f.getPath() : null);
516   }
517
518   public static String JavaDoc makeRelativePath(File JavaDoc from, String JavaDoc to) {
519     File JavaDoc f = makeRelativeFile(from, new File JavaDoc(to));
520     return (f != null ? f.getPath() : null);
521   }
522
523   /**
524    * Give the developer a chance to see the in-memory source that failed.
525    */

526   public static String JavaDoc maybeDumpSource(TreeLogger logger, String JavaDoc location,
527       char[] source, String JavaDoc optionalTypeName) {
528
529     if (isCompilationUnitOnDisk(location)) {
530       // Don't write another copy.
531
//
532
return null;
533     }
534
535     File JavaDoc tmpSrc;
536     Throwable JavaDoc caught = null;
537     try {
538       String JavaDoc prefix = "gen";
539       if (optionalTypeName != null) {
540         prefix = optionalTypeName;
541       }
542       tmpSrc = File.createTempFile(prefix, ".java");
543       writeCharsAsFile(logger, tmpSrc, source);
544       String JavaDoc dumpPath = tmpSrc.getAbsolutePath();
545       logger.log(TreeLogger.ERROR, "Compilation problem due to '" + location
546           + "'; see snapshot " + dumpPath, null);
547       return dumpPath;
548     } catch (IOException JavaDoc e) {
549       caught = e;
550     } catch (UnableToCompleteException e) {
551       caught = e;
552     }
553     logger.log(TreeLogger.ERROR,
554         "Compilation problem due to in-memory source '" + location
555             + "', but unable to dump to disk", caught);
556     return null;
557   }
558
559   public static byte[] readFileAsBytes(File JavaDoc file) {
560     FileInputStream JavaDoc fileInputStream = null;
561     try {
562       fileInputStream = new FileInputStream JavaDoc(file);
563       int length = (int) file.length();
564       byte[] data = new byte[length];
565       fileInputStream.read(data);
566       return data;
567     } catch (IOException JavaDoc e) {
568       return null;
569     } finally {
570       Utility.close(fileInputStream);
571     }
572   }
573
574   public static char[] readFileAsChars(File JavaDoc file) {
575     if (!file.exists()) {
576       return null;
577     }
578     Reader JavaDoc fileReader = null;
579     try {
580       fileReader = new InputStreamReader JavaDoc(new FileInputStream JavaDoc(file),
581           DEFAULT_ENCODING);
582       int length = (int) file.length();
583       char[] data = new char[length];
584       if (length < 0) {
585         return null;
586       }
587       char[] fileContents = new char[length];
588       int charsRead = fileReader.read(fileContents);
589       if (charsRead < fileContents.length) {
590         /*
591          * Calling functions expect returned char[] to be fully populated. This
592          * happens because some UTF-8 chars take more than one byte to
593          * represent.
594          */

595         char[] trimmed = new char[charsRead];
596         System.arraycopy(fileContents, 0, trimmed, 0, charsRead);
597         fileContents = trimmed;
598       }
599       return fileContents;
600     } catch (IOException JavaDoc e) {
601       return null;
602     } finally {
603       Utility.close(fileReader);
604     }
605   }
606
607   public static String JavaDoc readFileAsString(File JavaDoc file) {
608     try {
609       URL JavaDoc toURL = file.toURL();
610       char[] buf = readURLAsChars(toURL);
611       if (buf == null) {
612         return null;
613       }
614       return String.valueOf(buf);
615     } catch (MalformedURLException JavaDoc e) {
616       return null;
617     }
618   }
619
620   /**
621    * Reads the next non-empty line.
622    *
623    * @return a non-empty string that has been trimmed or null if the reader is
624    * exhausted
625    */

626   public static String JavaDoc readNextLine(BufferedReader JavaDoc br) {
627     try {
628       String JavaDoc line = br.readLine();
629       while (line != null) {
630         line = line.trim();
631         if (line.length() > 0) {
632           break;
633         }
634         line = br.readLine();
635       }
636       return line;
637     } catch (IOException JavaDoc e) {
638       return null;
639     }
640   }
641
642   /**
643    * @return null if the file could not be read
644    */

645   public static char[] readURLAsChars(URL JavaDoc url) {
646     // ENH: add a weak cache that has an additional check against the file date
647
InputStreamReader JavaDoc reader = null;
648     try {
649       URLConnection JavaDoc connection = url.openConnection();
650       connection.setUseCaches(false);
651       reader = new InputStreamReader JavaDoc(connection.getInputStream(),
652           DEFAULT_ENCODING);
653       int contentLength = connection.getContentLength();
654       if (contentLength < 0) {
655         return null;
656       }
657       char[] fileContents = new char[contentLength];
658       int charsRead = reader.read(fileContents);
659       if (charsRead < fileContents.length) {
660         /*
661          * Calling functions expect returned char[] to be fully populated. This
662          * happens because some UTF-8 chars take more than one byte to
663          * represent.
664          */

665         char[] trimmed = new char[charsRead];
666         System.arraycopy(fileContents, 0, trimmed, 0, charsRead);
667         fileContents = trimmed;
668       }
669       return fileContents;
670     } catch (IOException JavaDoc e) {
671       return null;
672     } finally {
673       Utility.close(reader);
674     }
675   }
676
677   /**
678    * Deletes a file or recursively deletes a directory.
679    *
680    * @param file the file to delete, or if this is a directory, the directory
681    * that serves as the root of a recursive deletion
682    * @param childrenOnly if <code>true</code>, only the children of a
683    * directory are recursively deleted but the specified directory
684    * itself is spared; if <code>false</code>, the specified
685    * directory is also deleted; ignored if <code>file</code> is not a
686    * directory
687    */

688   public static void recursiveDelete(File JavaDoc file, boolean childrenOnly) {
689     if (file.isDirectory()) {
690       File JavaDoc[] children = file.listFiles();
691       if (children != null) {
692         for (int i = 0; i < children.length; i++) {
693           recursiveDelete(children[i], false);
694         }
695       }
696       if (childrenOnly) {
697         // Do not delete the specified directory itself.
698
//
699
return;
700       }
701     }
702     file.delete();
703   }
704
705   public static File JavaDoc removeExtension(File JavaDoc file) {
706     String JavaDoc name = file.getName();
707     int lastDot = name.lastIndexOf('.');
708     if (lastDot != -1) {
709       name = name.substring(0, lastDot);
710     }
711     return new File JavaDoc(file.getParentFile(), name);
712   }
713
714   public static Object JavaDoc[] removeNulls(Object JavaDoc[] a) {
715     int n = a.length;
716     for (int i = 0; i < a.length; i++) {
717       if (a[i] == null) {
718         --n;
719       }
720     }
721
722     Class JavaDoc componentType = a.getClass().getComponentType();
723     Object JavaDoc[] t = (Object JavaDoc[]) Array.newInstance(componentType, n);
724     int out = 0;
725     for (int in = 0; in < t.length; in++) {
726       if (a[in] != null) {
727         t[out++] = a[in];
728       }
729     }
730     return t;
731   }
732
733   /**
734    * @param path The path to slashify.
735    * @return The path with any directory separators replaced with '/'.
736    */

737   public static String JavaDoc slashify(String JavaDoc path) {
738     path = path.replace(File.separatorChar, '/');
739     if (path.endsWith("/")) {
740       path = path.substring(0, path.length() - 1);
741     }
742     return path;
743   }
744
745   /**
746    * Creates an array from a collection of the speciifed component type and
747    * size. You can definitely downcast the result to T[] if T is the specified
748    * component type.
749    */

750   public static Object JavaDoc[] toArray(Class JavaDoc componentType, Collection JavaDoc coll) {
751     int n = coll.size();
752     Object JavaDoc[] a = (Object JavaDoc[]) Array.newInstance(componentType, n);
753     return coll.toArray(a);
754   }
755
756   /**
757    * Like {@link #toArray(Class, Collection)}, but the option of having the
758    * array reversed.
759    */

760   public static Object JavaDoc[] toArrayReversed(Class JavaDoc componentType, Collection JavaDoc coll) {
761     int n = coll.size();
762     Object JavaDoc[] a = (Object JavaDoc[]) Array.newInstance(componentType, n);
763     int i = n - 1;
764     for (Iterator JavaDoc iter = coll.iterator(); iter.hasNext(); --i) {
765       a[i] = iter.next();
766     }
767     return a;
768   }
769
770   /**
771    * Creates a string array from the contents of a collection.
772    */

773   public static String JavaDoc[] toStringArray(Collection JavaDoc coll) {
774     return (String JavaDoc[]) toArray(String JavaDoc.class, coll);
775   }
776
777   public static URL JavaDoc toURL(File JavaDoc f) {
778     try {
779       return f.toURI().toURL();
780     } catch (MalformedURLException JavaDoc e) {
781       throw new RuntimeException JavaDoc("Failed to convert a File to a URL", e);
782     }
783   }
784
785   public static URL JavaDoc toURL(URL JavaDoc jarUrl, JarEntry JavaDoc jarEntry) {
786     return toURL(jarUrl, jarEntry.toString());
787   }
788
789   public static URL JavaDoc toURL(URL JavaDoc jarUrl, String JavaDoc path) {
790     try {
791       return new URL JavaDoc("jar" + ":" + jarUrl.toString() + "!/" + path);
792     } catch (MalformedURLException JavaDoc e) {
793       throw new RuntimeException JavaDoc("Failed to convert a jar path to a URL", e);
794     }
795   }
796
797   public static String JavaDoc toXml(Document JavaDoc doc) {
798     Throwable JavaDoc caught = null;
799     try {
800       byte[] bytes = toXmlUtf8(doc);
801       return new String JavaDoc(bytes, DEFAULT_ENCODING);
802     } catch (UnsupportedEncodingException JavaDoc e) {
803       caught = e;
804     }
805     throw new RuntimeException JavaDoc("Unable to encode xml string as utf-8", caught);
806   }
807
808   public static byte[] toXmlUtf8(Document JavaDoc doc) {
809     Throwable JavaDoc caught = null;
810     try {
811       StringWriter JavaDoc sw = new StringWriter JavaDoc();
812       PrintWriter JavaDoc pw = new PrintWriter JavaDoc(sw);
813       writeDocument(pw, doc);
814       return sw.toString().getBytes(DEFAULT_ENCODING);
815     } catch (UnsupportedEncodingException JavaDoc e) {
816       caught = e;
817     } catch (IOException JavaDoc e) {
818       caught = e;
819     }
820     throw new RuntimeException JavaDoc(
821         "Unable to encode xml document object as a string", caught);
822
823     // THE COMMENTED-OUT CODE BELOW IS THE WAY I'D LIKE TO GENERATE XML,
824
// BUT IT SEEMS TO BLOW UP WHEN YOU CHANGE JRE VERSIONS AND/OR RUN
825
// IN TOMCAT. INSTEAD, I JUST SLAPPED TOGETHER THE MINIMAL STUFF WE
826
// NEEDED TO WRITE CACHE ENTRIES.
827

828     // Throwable caught = null;
829
// try {
830
// TransformerFactory transformerFactory = TransformerFactory.newInstance();
831
// Transformer transformer = transformerFactory.newTransformer();
832
// transformer.setOutputProperty(javax.xml.transform.OutputKeys.INDENT,
833
// "yes");
834
// transformer.setOutputProperty(
835
// "{http://xml.apache.org/xslt}indent-amount", "4");
836
// ByteArrayOutputStream baos = new ByteArrayOutputStream();
837
// OutputStreamWriter osw = new OutputStreamWriter(baos, "UTF-8");
838
// StreamResult result = new StreamResult(osw);
839
// DOMSource domSource = new DOMSource(doc);
840
// transformer.transform(domSource, result);
841
// byte[] bytes = baos.toByteArray();
842
// return bytes;
843
// } catch (TransformerConfigurationException e) {
844
// caught = e;
845
// } catch (UnsupportedEncodingException e) {
846
// caught = e;
847
// } catch (TransformerException e) {
848
// caught = e;
849
// }
850
// throw new RuntimeException(
851
// "Unable to encode xml document object as a string", caught);
852
}
853
854   public static File JavaDoc tryCombine(File JavaDoc parentMaybeIgnored, File JavaDoc childMaybeAbsolute) {
855     if (childMaybeAbsolute == null) {
856       return parentMaybeIgnored;
857     } else if (childMaybeAbsolute.isAbsolute()) {
858       return childMaybeAbsolute;
859     } else {
860       return new File JavaDoc(parentMaybeIgnored, childMaybeAbsolute.getPath());
861     }
862   }
863
864   public static File JavaDoc tryCombine(File JavaDoc parentMaybeIgnored,
865       String JavaDoc childMaybeAbsolute) {
866     return tryCombine(parentMaybeIgnored, new File JavaDoc(childMaybeAbsolute));
867   }
868
869   /**
870    * Attempts to find the canonical form of a file path.
871    *
872    * @return the canonical version of the file path, if it could be computed;
873    * otherwise, the original file is returned unmodified
874    */

875   public static File JavaDoc tryMakeCanonical(File JavaDoc file) {
876     try {
877       return file.getCanonicalFile();
878     } catch (IOException JavaDoc e) {
879       return file;
880     }
881   }
882
883   public static void writeBytesToFile(TreeLogger logger, File JavaDoc where, byte[] what)
884       throws UnableToCompleteException {
885     writeBytesToFile(logger, where, new byte[][] {what});
886   }
887
888   /**
889    * Gathering write.
890    */

891   public static void writeBytesToFile(TreeLogger logger, File JavaDoc where,
892       byte[][] what) throws UnableToCompleteException {
893     RandomAccessFile JavaDoc f = null;
894     Throwable JavaDoc caught;
895     try {
896       where.getParentFile().mkdirs();
897       f = new RandomAccessFile JavaDoc(where, "rwd");
898       long newLen = 0;
899       for (int i = 0; i < what.length; i++) {
900         newLen += what[i].length;
901         f.write(what[i]);
902       }
903       f.setLength(newLen);
904       return;
905     } catch (FileNotFoundException JavaDoc e) {
906       caught = e;
907     } catch (IOException JavaDoc e) {
908       caught = e;
909     } finally {
910       Utility.close(f);
911     }
912     String JavaDoc msg = "Unable to write file '" + where + "'";
913     logger.log(TreeLogger.ERROR, msg, caught);
914     throw new UnableToCompleteException();
915   }
916
917   public static void writeCharsAsFile(TreeLogger logger, File JavaDoc file, char[] chars)
918       throws UnableToCompleteException {
919     FileOutputStream JavaDoc stream = null;
920     OutputStreamWriter JavaDoc writer = null;
921     BufferedWriter JavaDoc buffered = null;
922     try {
923       file.getParentFile().mkdirs();
924       stream = new FileOutputStream JavaDoc(file);
925       writer = new OutputStreamWriter JavaDoc(stream, DEFAULT_ENCODING);
926       buffered = new BufferedWriter JavaDoc(writer);
927       buffered.write(chars);
928     } catch (IOException JavaDoc e) {
929       logger.log(TreeLogger.ERROR, "Unable to write file: "
930           + file.getAbsolutePath(), e);
931       throw new UnableToCompleteException();
932     } finally {
933       Utility.close(buffered);
934       Utility.close(writer);
935       Utility.close(stream);
936     }
937   }
938
939   public static boolean writeStringAsFile(File JavaDoc file, String JavaDoc string) {
940     FileOutputStream JavaDoc stream = null;
941     OutputStreamWriter JavaDoc writer = null;
942     BufferedWriter JavaDoc buffered = null;
943     try {
944       stream = new FileOutputStream JavaDoc(file);
945       writer = new OutputStreamWriter JavaDoc(stream, DEFAULT_ENCODING);
946       buffered = new BufferedWriter JavaDoc(writer);
947       file.getParentFile().mkdirs();
948       buffered.write(string);
949     } catch (IOException JavaDoc e) {
950       return false;
951     } finally {
952       Utility.close(buffered);
953       Utility.close(writer);
954       Utility.close(stream);
955     }
956     return true;
957   }
958
959   /**
960    * Escapes '&', '<', '>', '"', and '\'' to their XML entity equivalents.
961    */

962   private static String JavaDoc escapeXml(String JavaDoc unescaped) {
963     String JavaDoc escaped = unescaped.replaceAll("\\&", "&amp;");
964     escaped = escaped.replaceAll("\\<", "&lt;");
965     escaped = escaped.replaceAll("\\>", "&gt;");
966     escaped = escaped.replaceAll("\\\"", "&quot;");
967     escaped = escaped.replaceAll("\\'", "&apos;");
968     return escaped;
969   }
970
971   private static void writeAttribute(PrintWriter JavaDoc w, Attr JavaDoc attr, int depth)
972       throws IOException JavaDoc {
973     w.write(attr.getName());
974     w.write('=');
975     Node JavaDoc c = attr.getFirstChild();
976     while (c != null) {
977       w.write('"');
978       writeNode(w, c, depth);
979       w.write('"');
980       c = c.getNextSibling();
981     }
982   }
983
984   private static void writeDocument(PrintWriter JavaDoc w, Document JavaDoc d)
985       throws IOException JavaDoc {
986     w.println("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
987     Node JavaDoc c = d.getFirstChild();
988     while (c != null) {
989       writeNode(w, c, 0);
990       c = c.getNextSibling();
991     }
992   }
993
994   private static void writeElement(PrintWriter JavaDoc w, Element JavaDoc el, int depth)
995       throws IOException JavaDoc {
996     String JavaDoc tagName = el.getTagName();
997
998     writeIndent(w, depth);
999     w.write('<');
1000    w.write(tagName);
1001    NamedNodeMap JavaDoc attrs = el.getAttributes();
1002    for (int i = 0, n = attrs.getLength(); i < n; ++i) {
1003      w.write(' ');
1004      writeNode(w, attrs.item(i), depth);
1005    }
1006
1007    Node JavaDoc c = el.getFirstChild();
1008    if (c != null) {
1009      // There is at least one child.
1010
//
1011
w.println('>');
1012
1013      // Write the children.
1014
//
1015
while (c != null) {
1016        writeNode(w, c, depth + 1);
1017        w.println();
1018        c = c.getNextSibling();
1019      }
1020
1021      // Write the closing tag.
1022
//
1023
writeIndent(w, depth);
1024      w.write("</");
1025      w.write(tagName);
1026      w.print('>');
1027    } else {
1028      // There are no children, so just write the short form close.
1029
//
1030
w.print("/>");
1031    }
1032  }
1033
1034  private static void writeIndent(PrintWriter JavaDoc w, int depth) {
1035    for (int i = 0; i < depth; ++i) {
1036      w.write('\t');
1037    }
1038  }
1039
1040  private static void writeNode(PrintWriter JavaDoc w, Node JavaDoc node, int depth)
1041      throws IOException JavaDoc {
1042    short nodeType = node.getNodeType();
1043    switch (nodeType) {
1044      case Node.ELEMENT_NODE:
1045        writeElement(w, (Element JavaDoc) node, depth);
1046        break;
1047      case Node.ATTRIBUTE_NODE:
1048        writeAttribute(w, (Attr JavaDoc) node, depth);
1049        break;
1050      case Node.DOCUMENT_NODE:
1051        writeDocument(w, (Document JavaDoc) node);
1052        break;
1053      case Node.TEXT_NODE:
1054        writeText(w, (Text JavaDoc) node);
1055        break;
1056
1057      case Node.COMMENT_NODE:
1058      case Node.CDATA_SECTION_NODE:
1059      case Node.ENTITY_REFERENCE_NODE:
1060      case Node.ENTITY_NODE:
1061      case Node.PROCESSING_INSTRUCTION_NODE:
1062      default:
1063        throw new RuntimeException JavaDoc("Unsupported DOM node type: " + nodeType);
1064    }
1065  }
1066
1067  private static void writeText(PrintWriter JavaDoc w, Text JavaDoc text) throws DOMException JavaDoc {
1068    String JavaDoc nodeValue = text.getNodeValue();
1069    String JavaDoc escaped = escapeXml(nodeValue);
1070    w.write(escaped);
1071  }
1072
1073  /**
1074   * Not instantiable.
1075   */

1076  private Util() {
1077  }
1078
1079}
1080
Popular Tags