KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sslexplorer > vfs > webdav > DAVUtilities


1 /* ========================================================================== *
2  * Copyright (C) 2004-2005 Pier Fumagalli <http://www.betaversion.org/~pier/> *
3  * All rights reserved. *
4  * ========================================================================== *
5  * *
6  * Licensed under the Apache License, Version 2.0 (the "License"). You may *
7  * not use this file except in compliance with the License. You may obtain a *
8  * copy of the License at <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 *
14  * under the License. *
15  * *
16  * ========================================================================== */

17 package com.sslexplorer.vfs.webdav;
18
19 import java.io.BufferedReader JavaDoc;
20 import java.io.InputStream JavaDoc;
21 import java.io.InputStreamReader JavaDoc;
22 import java.io.UnsupportedEncodingException JavaDoc;
23 import java.security.MessageDigest JavaDoc;
24 import java.text.SimpleDateFormat JavaDoc;
25 import java.util.Date JavaDoc;
26 import java.util.HashMap JavaDoc;
27 import java.util.Iterator JavaDoc;
28 import java.util.Locale JavaDoc;
29 import java.util.Map JavaDoc;
30 import java.util.Properties JavaDoc;
31 import java.util.StringTokenizer JavaDoc;
32 import java.util.TimeZone JavaDoc;
33
34 import com.maverick.util.URLUTF8Encoder;
35 import com.sslexplorer.boot.Util;
36 import com.sslexplorer.core.stringreplacement.SessionInfoReplacer;
37 import com.sslexplorer.security.SessionInfo;
38 import com.sslexplorer.vfs.utils.URI;
39 import com.sslexplorer.vfs.utils.URI.MalformedURIException;
40
41 /**
42  * <p>
43  * A collection of static utilities.
44  * </p>
45  *
46  * @author <a HREF="http://www.betaversion.org/~pier/">Pier Fumagalli</a>
47  */

48 public class DAVUtilities {
49
50     /**
51      * <p>
52      * A {@link String} of all acceptable characters in a URI.
53      * </p>
54      */

55     // private static final String ACCEPTABLE = "ABCDEFGHIJLKMNOPQRSTUVWXYZ" +
56
// // ALPHA
57
// // (UPPER)
58
// "abcdefghijklmnopqrstuvwxyz" + // ALPHA (LOWER)
59
// "0123456789" + // DIGIT
60
// "_-!.~'()*" + // UNRESERVED
61
// ",;:$&+=" + // PUNCT
62
// "?/[]@"; // RESERVED
63
private static final String JavaDoc ACCEPTABLE = "ABCDEFGHIJLKMNOPQRSTUVWXYZ" + // ALPHA
64
// (UPPER)
65
"abcdefghijklmnopqrstuvwxyz" + // ALPHA (LOWER)
66
"0123456789" + // DIGIT
67
"_-!.~'()*" + // UNRESERVED
68
",;:$+=" + // PUNCT
69
"?/@"; // RESERVED
70

71     /**
72      * <p>
73      * A {@link HashMap} of configured mime types.
74      * </p>
75      */

76     private static Map JavaDoc MIME_TYPES = new HashMap JavaDoc();
77     /**
78      * <p>
79      * A {@link HashMap} of configured mime types.
80      * </p>
81      */

82     private static Properties JavaDoc PROPERTIES = new Properties JavaDoc();
83     /**
84      * <p>
85      * The {@link SimpleDateFormat} RFC-822 date format.
86      * </p>
87      */

88     private static final String JavaDoc FORMAT_822 = "EEE, dd MMM yyyy HH:mm:ss 'GMT'";
89     /**
90      * <p>
91      * The {@link TimeZone} to use for formatting RFC-822 dates.
92      * </p>
93      */

94     private static final TimeZone JavaDoc TIMEZONE_822 = TimeZone.getTimeZone("GMT");
95
96     /**
97      * <p>
98      * Load the mime types map from a resource.
99      * </p>
100      */

101     static {
102         InputStream JavaDoc prop = DAVUtilities.class.getResourceAsStream("webdav.props");
103         try {
104             DAVUtilities.PROPERTIES.load(prop);
105             prop.close();
106         } catch (Exception JavaDoc exception) {
107             exception.printStackTrace();
108         }
109
110         /* Load up the mime types table */
111         InputStream JavaDoc mime = DAVUtilities.class.getResourceAsStream("mime.types");
112         try {
113             InputStreamReader JavaDoc read = new InputStreamReader JavaDoc(mime);
114             BufferedReader JavaDoc buff = new BufferedReader JavaDoc(read);
115             String JavaDoc line = null;
116             while ((line = buff.readLine()) != null) {
117                 line = line.trim();
118                 if (line.length() == 0)
119                     continue;
120                 if (line.charAt(0) == '#')
121                     continue;
122                 StringTokenizer JavaDoc tokenizer = new StringTokenizer JavaDoc(line);
123                 if (tokenizer.countTokens() > 1) {
124                     String JavaDoc type = tokenizer.nextToken();
125                     while (tokenizer.hasMoreTokens()) {
126                         String JavaDoc extension = '.' + tokenizer.nextToken();
127                         DAVUtilities.MIME_TYPES.put(extension, type);
128                     }
129                 }
130             }
131             buff.close();
132             read.close();
133             mime.close();
134         } catch (Exception JavaDoc exception) {
135             exception.printStackTrace();
136         }
137     }
138
139     /**
140      * <p>
141      * Deny public construction of {@link DAVUtilities} instances.
142      * </p>
143      */

144     private DAVUtilities() {
145         super();
146     }
147
148     /**
149      * <p>
150      * Return the value of a property configured for this package.
151      * </p>
152      *
153      * @param name the property name
154      * @return a {@link String} instance or <b>null</b> if unknown.
155      */

156     public static String JavaDoc getProperty(String JavaDoc name) {
157         if (name == null)
158             return null;
159         return DAVUtilities.PROPERTIES.getProperty(name);
160     }
161
162     /**
163      * <p>
164      * Return the MIME Type configured for a given resource.
165      * </p>
166      *
167      * @param name the resource name whose MIME Type needs to be looked up.
168      * @return a {@link String} instance or <b>null</b> if the type is unknown.
169      */

170     public static String JavaDoc getMimeType(String JavaDoc name) {
171         if (name == null)
172             return null;
173
174         Iterator JavaDoc iterator = DAVUtilities.MIME_TYPES.keySet().iterator();
175         while (iterator.hasNext()) {
176             String JavaDoc extension = (String JavaDoc) iterator.next();
177             if (name.endsWith(extension)) {
178                 return (String JavaDoc) DAVUtilities.MIME_TYPES.get(extension);
179             }
180         }
181
182         return null;
183     }
184
185     /**
186      * <p>
187      * Return a {@link String} message given an HTTP status code.
188      * </p>
189      *
190      * @param status status code
191      * @return status strings
192      */

193     public static String JavaDoc getStatusMessage(int status) {
194         switch (status) {
195             /* HTTP/1.1 RFC-2616 */
196             case 100:
197                 return "100 Continue";
198             case 101:
199                 return "101 Switching Protocols";
200             case 200:
201                 return "200 OK";
202             case 201:
203                 return "201 Created";
204             case 202:
205                 return "202 Accepted";
206             case 203:
207                 return "203 Non-Authoritative Information";
208             case 204:
209                 return "204 No Content";
210             case 205:
211                 return "205 Reset Content";
212             case 206:
213                 return "206 Partial Content";
214             case 300:
215                 return "300 Multiple Choices";
216             case 301:
217                 return "301 Moved Permanently";
218             case 302:
219                 return "302 Found";
220             case 303:
221                 return "303 See Other";
222             case 304:
223                 return "304 Not Modified";
224             case 305:
225                 return "305 Use Proxy";
226             case 306:
227                 return "306 (Unused)";
228             case 307:
229                 return "307 Temporary Redirect";
230             case 400:
231                 return "400 Bad Request";
232             case 401:
233                 return "401 Unauthorized";
234             case 402:
235                 return "402 Payment Required";
236             case 403:
237                 return "403 Forbidden";
238             case 404:
239                 return "404 Not Found";
240             case 405:
241                 return "405 Method Not Allowed";
242             case 406:
243                 return "406 Not Acceptable";
244             case 407:
245                 return "407 Proxy Authentication Required";
246             case 408:
247                 return "408 Request Timeout";
248             case 409:
249                 return "409 Conflict";
250             case 410:
251                 return "410 Gone";
252             case 411:
253                 return "411 Length Required";
254             case 412:
255                 return "412 Precondition Failed";
256             case 413:
257                 return "413 Request Entity Too Large";
258             case 414:
259                 return "414 Request-URI Too Long";
260             case 415:
261                 return "415 Unsupported Media Type";
262             case 416:
263                 return "416 Requested Range Not Satisfiable";
264             case 417:
265                 return "417 Expectation Failed";
266             case 500:
267                 return "500 Internal Server Error";
268             case 501:
269                 return "501 Not Implemented";
270             case 502:
271                 return "502 Bad Gateway";
272             case 503:
273                 return "503 Service Unavailable";
274             case 504:
275                 return "504 Gateway Timeout";
276             case 505:
277                 return "505 HTTP Version Not Supported";
278
279                 /* DAV/1.0 RFC-2518 */
280             case 102:
281                 return "102 Processing";
282             case 207:
283                 return "207 Multi-Status";
284             case 422:
285                 return "422 Unprocessable Entity";
286             case 423:
287                 return "423 Locked";
288             case 424:
289                 return "424 Failed Dependency";
290             case 507:
291                 return "507 Insufficient Storage";
292
293                 /* Unknown */
294             default:
295                 return null;
296         }
297     }
298
299     /**
300      * <p>
301      * Format an {@link Object} according to the HTTP/1.1 RFC.
302      * </p>
303      *
304      * @param object the {@link Object} to format.
305      * @return a {@link String} instance or <b>null</b> if the object was null.
306      */

307     public static String JavaDoc format(Object JavaDoc object) {
308         if (object == null)
309             return null;
310         if (object instanceof String JavaDoc)
311             return ((String JavaDoc) object);
312         if (object instanceof Date JavaDoc) {
313             SimpleDateFormat JavaDoc formatter = new SimpleDateFormat JavaDoc(FORMAT_822, Locale.ENGLISH);
314             formatter.setTimeZone(TIMEZONE_822);
315             return formatter.format((Date JavaDoc) object);
316         }
317         return (object.toString());
318     }
319
320     /**
321      * <p>
322      * Return the HEX representation of an array of bytes.
323      * </p>
324      *
325      * @param buffer the array of bytes to convert in a HEX {@link String}.
326      * @return a <b>non-null</b> {@link String} instance.
327      */

328     public static String JavaDoc toHexString(byte buffer[]) {
329         char output[] = new char[buffer.length * 2];
330         int position = 0;
331         for (int x = 0; x < buffer.length; x++) {
332             output[position++] = DAVUtilities.toHexDigit(buffer[x] >> 4);
333             output[position++] = DAVUtilities.toHexDigit(buffer[x]);
334         }
335         return new String JavaDoc(output);
336     }
337
338     /**
339      * <p>
340      * Return the HEX representation of a long integer.
341      * </p>
342      *
343      * @param number the long to convert in a HEX {@link String}.
344      * @return a <b>non-null</b> 16-characters {@link String} instance.
345      */

346     public static String JavaDoc toHexString(long number) {
347         char output[] = new char[16];
348         output[0] = DAVUtilities.toHexDigit((int) (number >> 60));
349         output[1] = DAVUtilities.toHexDigit((int) (number >> 56));
350         output[2] = DAVUtilities.toHexDigit((int) (number >> 52));
351         output[3] = DAVUtilities.toHexDigit((int) (number >> 48));
352         output[4] = DAVUtilities.toHexDigit((int) (number >> 44));
353         output[5] = DAVUtilities.toHexDigit((int) (number >> 40));
354         output[6] = DAVUtilities.toHexDigit((int) (number >> 36));
355         output[7] = DAVUtilities.toHexDigit((int) (number >> 32));
356         output[8] = DAVUtilities.toHexDigit((int) (number >> 28));
357         output[9] = DAVUtilities.toHexDigit((int) (number >> 24));
358         output[10] = DAVUtilities.toHexDigit((int) (number >> 20));
359         output[11] = DAVUtilities.toHexDigit((int) (number >> 16));
360         output[12] = DAVUtilities.toHexDigit((int) (number >> 12));
361         output[13] = DAVUtilities.toHexDigit((int) (number >> 8));
362         output[14] = DAVUtilities.toHexDigit((int) (number >> 4));
363         output[15] = DAVUtilities.toHexDigit((int) (number));
364         return new String JavaDoc(output);
365     }
366
367     /**
368      * <p>
369      * Return the HEX representation of an integer.
370      * </p>
371      *
372      * @param number the int to convert in a HEX {@link String}.
373      * @return a <b>non-null</b> 8-characters {@link String} instance.
374      */

375     public static String JavaDoc toHexString(int number) {
376         char output[] = new char[8];
377         output[0] = DAVUtilities.toHexDigit((int) (number >> 28));
378         output[1] = DAVUtilities.toHexDigit((int) (number >> 24));
379         output[2] = DAVUtilities.toHexDigit((int) (number >> 20));
380         output[3] = DAVUtilities.toHexDigit((int) (number >> 16));
381         output[4] = DAVUtilities.toHexDigit((int) (number >> 12));
382         output[5] = DAVUtilities.toHexDigit((int) (number >> 8));
383         output[6] = DAVUtilities.toHexDigit((int) (number >> 4));
384         output[7] = DAVUtilities.toHexDigit((int) (number));
385         return new String JavaDoc(output);
386     }
387
388     /**
389      * <p>
390      * Return the HEX representation of a char.
391      * </p>
392      *
393      * @param number the char to convert in a HEX {@link String}.
394      * @return a <b>non-null</b> 4-characters {@link String} instance.
395      */

396     public static String JavaDoc toHexString(char number) {
397         char output[] = new char[4];
398         output[0] = DAVUtilities.toHexDigit((int) (number >> 12));
399         output[1] = DAVUtilities.toHexDigit((int) (number >> 8));
400         output[2] = DAVUtilities.toHexDigit((int) (number >> 4));
401         output[3] = DAVUtilities.toHexDigit((int) (number));
402         return new String JavaDoc(output);
403     }
404
405     /**
406      * <p>
407      * Return the HEX representation of a byte.
408      * </p>
409      *
410      * @param number the byte to convert in a HEX {@link String}.
411      * @return a <b>non-null</b> 2-characters {@link String} instance.
412      */

413     public static String JavaDoc toHexString(byte number) {
414         char output[] = new char[2];
415         output[0] = DAVUtilities.toHexDigit((int) (number >> 4));
416         output[1] = DAVUtilities.toHexDigit((int) (number));
417         return new String JavaDoc(output);
418     }
419
420     /**
421      * <p>
422      * Return the single digit character representing the HEX encoding of the
423      * lower four bits of a given integer.
424      * </p>
425      *
426      * @param number number to conver
427      * @return hex character
428      */

429     private static char toHexDigit(int number) {
430         switch (number & 0x0F) {
431             case 0x00:
432                 return '0';
433             case 0x01:
434                 return '1';
435             case 0x02:
436                 return '2';
437             case 0x03:
438                 return '3';
439             case 0x04:
440                 return '4';
441             case 0x05:
442                 return '5';
443             case 0x06:
444                 return '6';
445             case 0x07:
446                 return '7';
447             case 0x08:
448                 return '8';
449             case 0x09:
450                 return '9';
451             case 0x0A:
452                 return 'A';
453             case 0x0B:
454                 return 'B';
455             case 0x0C:
456                 return 'C';
457             case 0x0D:
458                 return 'D';
459             case 0x0E:
460                 return 'E';
461             case 0x0F:
462                 return 'F';
463         }
464         String JavaDoc message = "Invalid HEX digit " + Integer.toHexString(number);
465         throw new IllegalArgumentException JavaDoc(message);
466     }
467
468     /**
469      * Encode a path suitable for use in a URI. Forward slashes will not be encoded.
470      *
471      * @param path
472      * @return encoding path
473      */

474     public static String JavaDoc encodePath(String JavaDoc path) {
475         return encodePath(path, false, "UTF-8");
476     }
477     
478     public static String JavaDoc encodePath(String JavaDoc path, boolean encodeSlash) {
479         return encodePath(path, encodeSlash, "UTF-8");
480     }
481
482     public static String JavaDoc encodePath(String JavaDoc path, String JavaDoc charset) {
483         return encodePath(path, false, charset);
484     }
485     /**
486      * Process a URI for replacements and encode the result correctly
487      *
488      * @param uri
489      * @param session session info to use for replacements
490      * @return processed uri
491      * @throws MalformedURIException
492      */

493     public static URI processAndEncodeURI(String JavaDoc uri, SessionInfo session, String JavaDoc charset) throws MalformedURIException {
494         // TODO We have problems with passwords containing @ characters here
495
String JavaDoc path = session == null ? uri : SessionInfoReplacer.replace(session, uri);
496         URI nuri = new URI(path);
497         if(nuri.getUserinfo() != null) {
498             nuri.setUserinfo(encodeURIUserInfo(nuri.getUserinfo()));
499         }
500         if(nuri.getPath() != null && !nuri.getPath().equals("")) {
501             nuri.setPath(encodePath(nuri.getPath(), charset));
502         }
503         return nuri;
504     }
505     
506     // NOTE this method is for the password hack in prcess
507

508     public static URI processAndEncodeURI(String JavaDoc uri, SessionInfo session) throws MalformedURIException {
509         return processAndEncodeURI(uri, session, "UTF-8");
510     }
511
512     /**
513      * Encode a path suitable for use in a URI.
514      *
515      * @param path path
516      * @param encodeSlash encode forward slashes (/)
517      * @return encoded path
518      */

519     public static String JavaDoc encodePath(String JavaDoc path, boolean encodeSlash, String JavaDoc charset) {
520         /* Encode the string */
521         StringBuffer JavaDoc buffer = new StringBuffer JavaDoc();
522         byte encoded[];
523         try {
524             if(charset==null)
525                 encoded = path.getBytes();
526             else
527                 encoded = path.getBytes(charset);
528             for (int x = 0; x < encoded.length; x++) {
529                 if (((int) encoded[x] == '%' && encodeSlash) || ACCEPTABLE.indexOf((int) encoded[x]) < 0) {
530                     buffer.append('%');
531                     buffer.append(DAVUtilities.toHexString(encoded[x]));
532                     continue;
533                 }
534                 buffer.append((char) encoded[x]);
535             }
536         } catch (UnsupportedEncodingException JavaDoc e) {
537             e.printStackTrace();
538             return path;
539         }
540
541         return buffer.toString();
542     }
543     
544     /**
545      * Encode the user info part of a URI
546      *
547      * @param uriUserInfo URI user info
548      * @return encoded URI user info
549      */

550     public static String JavaDoc encodeURIUserInfo(String JavaDoc uriUserInfo) {
551         int idx = uriUserInfo.indexOf(':');
552         if(idx != -1) {
553             return URLUTF8Encoder.encode(uriUserInfo.substring(0, idx), true) + ":" +
554             URLUTF8Encoder.encode(uriUserInfo.substring(idx + 1), true);
555         }
556         return Util.urlEncode(uriUserInfo);
557     }
558
559     /**
560      * Get ETAG
561      *
562      * @param path
563      * @param lastModified
564      * @return ETAG
565      */

566     public static String JavaDoc getETAG(String JavaDoc path, Date JavaDoc lastModified) {
567         StringBuffer JavaDoc etag = new StringBuffer JavaDoc();
568         etag.append('"');
569
570         /* Append the MD5 hash of this resource name */
571         try {
572             MessageDigest JavaDoc digester = MessageDigest.getInstance("MD5");
573             digester.reset();
574             digester.update(path.getBytes("UTF8"));
575             etag.append(DAVUtilities.toHexString(digester.digest()));
576             etag.append('-');
577         } catch (Exception JavaDoc e) {
578             // If we can't get the MD5 HASH, let's ignore and hope...
579
}
580
581         /* Append the hashCode of this resource name */
582         etag.append(DAVUtilities.toHexString(path.hashCode()));
583
584         /* Append the last modification date if possible */
585         if (lastModified != null) {
586             etag.append('-');
587             etag.append(DAVUtilities.toHexString(lastModified.getTime()));
588         }
589
590         /* Close the ETag */
591         etag.append('"');
592         return (etag.toString());
593     }
594
595     /**
596      * Strip the first element in a path
597      *
598      * @param path
599      * @return new path
600      */

601     public static String JavaDoc stripFirstPath(String JavaDoc path) {
602         if (path.length() < 1) {
603             return path;
604         }
605         int idx = path.indexOf('/', 1);
606         return idx == -1 ? path : path.substring(idx);
607     }
608
609     /**
610      * Strip all leading slashes
611      *
612      * @param path
613      * @return new path
614      */

615     public static String JavaDoc stripLeadingSlash(String JavaDoc path) {
616         while (path != null && path.startsWith("/")) {
617             path = path.substring(1);
618         }
619         return path;
620     }
621
622     /**
623      * Strip all trailing slashes
624      *
625      * @param path
626      * @return new path
627      */

628     public static String JavaDoc stripTrailingSlash(String JavaDoc path) {
629         while (path.endsWith("/")) {
630             path = path.substring(0, path.length() - 1);
631         }
632         return path;
633     }
634     
635     /**
636      * String the user info section from a URI
637      * @param uri
638      * @return
639      */

640     public static String JavaDoc stripUserInfo(String JavaDoc uri) {
641         
642         int idx1 = uri.indexOf("//");
643         int idx2 = uri.indexOf('@');
644         
645         if(idx1 > -1 && idx2 > -1 && idx1 < idx2) {
646             return uri.substring(0, idx1+2) + uri.substring(idx2);
647         } else
648             return uri;
649         
650     }
651
652     /**
653      * Strips the directory from a file path (if any) using the specified
654      * character as a separator. If an empty path is supplied then an empty is
655      * returned.
656      *
657      * @param path path
658      * @param separator separator
659      * @return path
660      */

661     public static String JavaDoc basename(String JavaDoc path, char separator) {
662         if (path.equals("")) {
663             return path;
664         }
665         while (path.endsWith(String.valueOf(separator))) {
666             path = path.substring(0, path.length() - 1);
667         }
668         int idx = path.lastIndexOf(separator);
669         return idx == -1 ? path : path.substring(idx + 1);
670     }
671
672     /**
673      * Concatent two paths
674      *
675      * @param original original path
676      * @param append path to append
677      * @return new path
678      */

679     public static String JavaDoc concatenatePaths(String JavaDoc original, String JavaDoc append) {
680         if (append != null) {
681             if (original.endsWith("/")) {
682                 original = original.concat(stripLeadingSlash(append));
683             } else {
684                 if (append.startsWith("/")) {
685                     original = original.concat(append);
686                 } else {
687                     original = original.concat("/".concat(append));
688                 }
689             }
690         }
691         return original;
692     }
693
694     /**
695      * Get the parent path or <code>null</code> if at the root
696      *
697      * @param path
698      * @return parent path
699      */

700     public static String JavaDoc getParentPath(String JavaDoc path) {
701         path = stripTrailingSlash(path);
702         String JavaDoc parent = null;
703         if (!path.equals("")) {
704             int idx = path.lastIndexOf("/");
705             if (idx == -1) {
706                 parent = "/";
707             } else {
708                 parent = path.substring(0, idx + 1);
709             }
710         }
711         return parent;
712     }
713
714     /**
715      * Strips any trailing slashes then returns anything up to last slash (i.e.
716      * the filename part is stripped leave the directory name). If the path is
717      * already /, <code>null</code> will be returned.
718      *
719      * @param path path
720      * @return dirname
721      */

722     public static String JavaDoc dirname(String JavaDoc path) {
723         String JavaDoc s = stripTrailingSlash(path);
724         if (s.equals("")) {
725             return null;
726         }
727         return s.substring(0, s.lastIndexOf("/"));
728     }
729 }
730
Popular Tags