KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > cocoon > util > NetUtils


1 /*
2  * Copyright 1999-2004 The Apache Software Foundation.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of 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,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16 package org.apache.cocoon.util;
17
18 import org.apache.cocoon.environment.Request;
19 import org.apache.commons.lang.StringUtils;
20 import org.apache.commons.lang.SystemUtils;
21 import org.apache.excalibur.source.SourceParameters;
22
23 import java.io.ByteArrayOutputStream JavaDoc;
24 import java.io.IOException JavaDoc;
25 import java.io.OutputStreamWriter JavaDoc;
26 import java.io.UnsupportedEncodingException JavaDoc;
27 import java.lang.reflect.InvocationTargetException JavaDoc;
28 import java.lang.reflect.Method JavaDoc;
29 import java.net.URLDecoder JavaDoc;
30 import java.net.URLEncoder JavaDoc;
31 import java.util.BitSet JavaDoc;
32 import java.util.Enumeration JavaDoc;
33 import java.util.Iterator JavaDoc;
34 import java.util.LinkedList JavaDoc;
35 import java.util.Map JavaDoc;
36 import java.util.StringTokenizer JavaDoc;
37
38 /**
39  * A collection of <code>File</code>, <code>URL</code> and filename
40  * utility methods
41  *
42  * @author <a HREF="mailto:stefano@apache.org">Stefano Mazzocchi</a>
43  * @version CVS $Id: NetUtils.java 168042 2005-05-04 01:47:09Z antonio $
44  */

45 public class NetUtils {
46
47     /**
48      * Array containing the safe characters set as defined by RFC 1738
49      */

50     private static BitSet JavaDoc safeCharacters;
51
52     private static final char[] hexadecimal =
53     {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
54      'A', 'B', 'C', 'D', 'E', 'F'};
55
56     static {
57         safeCharacters = new BitSet JavaDoc(256);
58         int i;
59         // 'lowalpha' rule
60
for (i = 'a'; i <= 'z'; i++) {
61             safeCharacters.set(i);
62         }
63         // 'hialpha' rule
64
for (i = 'A'; i <= 'Z'; i++) {
65             safeCharacters.set(i);
66         }
67         // 'digit' rule
68
for (i = '0'; i <= '9'; i++) {
69             safeCharacters.set(i);
70         }
71
72         // 'safe' rule
73
safeCharacters.set('$');
74         safeCharacters.set('-');
75         safeCharacters.set('_');
76         safeCharacters.set('.');
77         safeCharacters.set('+');
78
79         // 'extra' rule
80
safeCharacters.set('!');
81         safeCharacters.set('*');
82         safeCharacters.set('\'');
83         safeCharacters.set('(');
84         safeCharacters.set(')');
85         safeCharacters.set(',');
86
87         // special characters common to http: file: and ftp: URLs ('fsegment' and 'hsegment' rules)
88
safeCharacters.set('/');
89         safeCharacters.set(':');
90         safeCharacters.set('@');
91         safeCharacters.set('&');
92         safeCharacters.set('=');
93     }
94
95     /**
96      * Decode a path.
97      *
98      * <p>Interprets %XX (where XX is hexadecimal number) as UTF-8 encoded bytes.
99      * <p>The validity of the input path is not checked (i.e. characters that were not encoded will
100      * not be reported as errors).
101      * <p>This method differs from URLDecoder.decode in that it always uses UTF-8 (while URLDecoder
102      * uses the platform default encoding, often ISO-8859-1), and doesn't translate + characters to spaces.
103      *
104      * @param path the path to decode
105      * @return the decoded path
106      */

107     public static String JavaDoc decodePath(String JavaDoc path) {
108         StringBuffer JavaDoc translatedPath = new StringBuffer JavaDoc(path.length());
109         byte[] encodedchars = new byte[path.length() / 3];
110         int i = 0;
111         int length = path.length();
112         int encodedcharsLength = 0;
113         while (i < length) {
114             if (path.charAt(i) == '%') {
115                 // we must process all consecutive %-encoded characters in one go, because they represent
116
// an UTF-8 encoded string, and in UTF-8 one character can be encoded as multiple bytes
117
while (i < length && path.charAt(i) == '%') {
118                     if (i + 2 < length) {
119                         try {
120                             byte x = (byte)Integer.parseInt(path.substring(i + 1, i + 3), 16);
121                             encodedchars[encodedcharsLength] = x;
122                         } catch (NumberFormatException JavaDoc e) {
123                             throw new IllegalArgumentException JavaDoc("NetUtils.decodePath: " +
124                                                                "Illegal hex characters in pattern %" + path.substring(i + 1, i + 3));
125                         }
126                         encodedcharsLength++;
127                         i += 3;
128                     } else {
129                         throw new IllegalArgumentException JavaDoc("NetUtils.decodePath: " +
130                                                            "% character should be followed by 2 hexadecimal characters.");
131                     }
132                 }
133                 try {
134                     String JavaDoc translatedPart = new String JavaDoc(encodedchars, 0, encodedcharsLength, "UTF-8");
135                     translatedPath.append(translatedPart);
136                 } catch (UnsupportedEncodingException JavaDoc e) {
137                     // the situation that UTF-8 is not supported is quite theoretical, so throw a runtime exception
138
throw new RuntimeException JavaDoc("Problem in decodePath: UTF-8 encoding not supported.");
139                 }
140                 encodedcharsLength = 0;
141             } else {
142                 // a normal character
143
translatedPath.append(path.charAt(i));
144                 i++;
145             }
146         }
147         return translatedPath.toString();
148     }
149
150     /**
151      * Encode a path as required by the URL specification (<a HREF="http://www.ietf.org/rfc/rfc1738.txt">
152      * RFC 1738</a>). This differs from <code>java.net.URLEncoder.encode()</code> which encodes according
153      * to the <code>x-www-form-urlencoded</code> MIME format.
154      *
155      * @param path the path to encode
156      * @return the encoded path
157      */

158     public static String JavaDoc encodePath(String JavaDoc path) {
159        // stolen from org.apache.catalina.servlets.DefaultServlet ;)
160

161         /**
162          * Note: This code portion is very similar to URLEncoder.encode.
163          * Unfortunately, there is no way to specify to the URLEncoder which
164          * characters should be encoded. Here, ' ' should be encoded as "%20"
165          * and '/' shouldn't be encoded.
166          */

167
168         int maxBytesPerChar = 10;
169         StringBuffer JavaDoc rewrittenPath = new StringBuffer JavaDoc(path.length());
170         ByteArrayOutputStream JavaDoc buf = new ByteArrayOutputStream JavaDoc(maxBytesPerChar);
171         OutputStreamWriter JavaDoc writer = null;
172         try {
173             writer = new OutputStreamWriter JavaDoc(buf, "UTF8");
174         } catch (Exception JavaDoc e) {
175             e.printStackTrace();
176             writer = new OutputStreamWriter JavaDoc(buf);
177         }
178
179         for (int i = 0; i < path.length(); i++) {
180             int c = path.charAt(i);
181             if (safeCharacters.get(c)) {
182                 rewrittenPath.append((char)c);
183             } else {
184                 // convert to external encoding before hex conversion
185
try {
186                     writer.write(c);
187                     writer.flush();
188                 } catch(IOException JavaDoc e) {
189                     buf.reset();
190                     continue;
191                 }
192                 byte[] ba = buf.toByteArray();
193                 for (int j = 0; j < ba.length; j++) {
194                     // Converting each byte in the buffer
195
byte toEncode = ba[j];
196                     rewrittenPath.append('%');
197                     int low = (toEncode & 0x0f);
198                     int high = ((toEncode & 0xf0) >> 4);
199                     rewrittenPath.append(hexadecimal[high]);
200                     rewrittenPath.append(hexadecimal[low]);
201                 }
202                 buf.reset();
203             }
204         }
205         return rewrittenPath.toString();
206     }
207
208     /**
209      * Returns the path of the given resource.
210      *
211      * @param uri The URI of the resource
212      * @return the resource path
213      */

214     public static String JavaDoc getPath(String JavaDoc uri) {
215         int i = uri.lastIndexOf('/');
216         if (i > -1) {
217             return uri.substring(0, i);
218         }
219         i = uri.indexOf(':');
220         return (i > -1) ? uri.substring(i + 1, uri.length()) : "";
221     }
222
223     /**
224      * Remove path and file information from a filename returning only its
225      * extension component
226      *
227      * @param uri The filename
228      * @return The filename extension (with starting dot!) or null if filename extension is not found
229      */

230     public static String JavaDoc getExtension(String JavaDoc uri) {
231         int dot = uri.lastIndexOf('.');
232         if (dot > -1) {
233             uri = uri.substring(dot);
234             int slash = uri.lastIndexOf('/');
235             if (slash > -1) {
236                 return null;
237             } else {
238                 int sharp = uri.lastIndexOf('#');
239                 if (sharp > -1) {
240                     // uri starts with dot already
241
return uri.substring(0, sharp);
242                 } else {
243                     int mark = uri.lastIndexOf('?');
244                     if (mark > -1) {
245                         // uri starts with dot already
246
return uri.substring(0, mark);
247                     } else {
248                         return uri;
249                     }
250                 }
251             }
252         } else {
253             return null;
254         }
255     }
256
257     /**
258      * Absolutize a relative resource path on the given absolute base path.
259      *
260      * @param path The absolute base path
261      * @param resource The relative resource path
262      * @return The absolutized resource path
263      */

264     public static String JavaDoc absolutize(String JavaDoc path, String JavaDoc resource) {
265         if (StringUtils.isEmpty(path)) {
266             return resource;
267         } else if (StringUtils.isEmpty(resource)) {
268             return path;
269         } else if (resource.charAt(0) == '/') {
270             // Resource path is already absolute
271
return resource;
272         }
273
274         boolean slash = (path.charAt(path.length() - 1) == '/');
275         
276         StringBuffer JavaDoc b = new StringBuffer JavaDoc(path.length() + 1 + resource.length());
277         b.append(path);
278         if (!slash) {
279             b.append('/');
280         }
281         b.append(resource);
282         return b.toString();
283     }
284
285     /**
286      * Relativize an absolute resource on a given absolute path.
287      *
288      * @param path The absolute path
289      * @param absoluteResource The absolute resource
290      * @return the resource relative to the given path
291      */

292     public static String JavaDoc relativize(String JavaDoc path, String JavaDoc absoluteResource) {
293         if (StringUtils.isEmpty(path)) {
294             return absoluteResource;
295         }
296
297         if (path.charAt(path.length() - 1) != '/') {
298             path += "/";
299         }
300
301         if (absoluteResource.startsWith(path)) {
302             // resource is direct descentant
303
return absoluteResource.substring(path.length());
304         } else {
305             // resource is not direct descendant
306
int index = StringUtils.indexOfDifference(path, absoluteResource);
307             if (index > 0 && path.charAt(index-1) != '/') {
308                 index = path.substring(0, index).lastIndexOf('/');
309                 index++;
310             }
311             String JavaDoc pathDiff = path.substring(index);
312             String JavaDoc resource = absoluteResource.substring(index);
313             int levels = StringUtils.countMatches(pathDiff, "/");
314             StringBuffer JavaDoc b = new StringBuffer JavaDoc(levels * 3 + resource.length());
315             for (int i = 0; i < levels; i++) {
316                 b.append("../");
317             }
318             b.append(resource);
319             return b.toString();
320         }
321     }
322
323     /**
324      * Normalize a uri containing ../ and ./ paths.
325      *
326      * @param uri The uri path to normalize
327      * @return The normalized uri
328      */

329     public static String JavaDoc normalize(String JavaDoc uri) {
330         if ("".equals(uri)) {
331             return uri;
332         }
333         int leadingSlashes = 0;
334         for (leadingSlashes = 0 ; leadingSlashes < uri.length()
335                 && uri.charAt(leadingSlashes) == '/' ; ++leadingSlashes) {}
336         boolean isDir = (uri.charAt(uri.length() - 1) == '/');
337         StringTokenizer JavaDoc st = new StringTokenizer JavaDoc(uri, "/");
338         LinkedList JavaDoc clean = new LinkedList JavaDoc();
339         while (st.hasMoreTokens()) {
340             String JavaDoc token = st.nextToken();
341             if ("..".equals(token)) {
342                 if (! clean.isEmpty() && ! "..".equals(clean.getLast())) {
343                     clean.removeLast();
344                     if (! st.hasMoreTokens()) {
345                         isDir = true;
346                     }
347                 } else {
348                     clean.add("..");
349                 }
350             } else if (! ".".equals(token) && ! "".equals(token)) {
351                 clean.add(token);
352             }
353         }
354         StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
355         while (leadingSlashes-- > 0) {
356             sb.append('/');
357         }
358         for (Iterator JavaDoc it = clean.iterator() ; it.hasNext() ; ) {
359             sb.append(it.next());
360             if (it.hasNext()) {
361                 sb.append('/');
362             }
363         }
364         if (isDir && sb.length() > 0 && sb.charAt(sb.length() - 1) != '/') {
365             sb.append('/');
366         }
367         return sb.toString();
368     }
369
370     /**
371      * Remove parameters from a uri.
372      * Resulting Map will have either String for single value attributes,
373      * or String arrays for multivalue attributes.
374      *
375      * @param uri The uri path to deparameterize.
376      * @param parameters The map that collects parameters.
377      * @return The cleaned uri
378      */

379     public static String JavaDoc deparameterize(String JavaDoc uri, Map JavaDoc parameters) {
380         int i = uri.lastIndexOf('?');
381         if (i == -1) {
382             return uri;
383         }
384
385         String JavaDoc[] params = StringUtils.split(uri.substring(i + 1), '&');
386         for (int j = 0; j < params.length; j++) {
387             String JavaDoc p = params[j];
388             int k = p.indexOf('=');
389             if (k == -1) {
390                 break;
391             }
392             String JavaDoc name = p.substring(0, k);
393             String JavaDoc value = p.substring(k + 1);
394             Object JavaDoc values = parameters.get(name);
395             if (values == null) {
396                 parameters.put(name, value);
397             } else if (values.getClass().isArray()) {
398                 String JavaDoc[] v1 = (String JavaDoc[])values;
399                 String JavaDoc[] v2 = new String JavaDoc[v1.length + 1];
400                 System.arraycopy(v1, 0, v2, 0, v1.length);
401                 v2[v1.length] = value;
402                 parameters.put(name, v2);
403             } else {
404                 parameters.put(name, new String JavaDoc[]{values.toString(), value});
405             }
406         }
407         return uri.substring(0, i);
408     }
409
410     /**
411      * Add parameters stored in the Map to the uri string.
412      * Map can contain Object values which will be converted to the string,
413      * or Object arrays, which will be treated as multivalue attributes.
414      *
415      * @param uri The uri to add parameters into
416      * @param parameters The map containing parameters to be added
417      * @return The uri with added parameters
418      */

419     public static String JavaDoc parameterize(String JavaDoc uri, Map JavaDoc parameters) {
420         if (parameters.size() == 0) {
421             return uri;
422         }
423         
424         StringBuffer JavaDoc buffer = new StringBuffer JavaDoc(uri);
425         if (uri.indexOf('?') == -1) {
426             buffer.append('?');
427         } else {
428             buffer.append('&');
429         }
430         
431         for (Iterator JavaDoc i = parameters.entrySet().iterator(); i.hasNext();) {
432             Map.Entry JavaDoc entry = (Map.Entry JavaDoc)i.next();
433             if (entry.getValue().getClass().isArray()) {
434                 Object JavaDoc[] value = (Object JavaDoc[])entry.getValue();
435                 for (int j = 0; j < value.length; j++) {
436                     if (j > 0) {
437                         buffer.append('&');
438                     }
439                     buffer.append(entry.getKey());
440                     buffer.append('=');
441                     buffer.append(value[j]);
442                 }
443             } else {
444                 buffer.append(entry.getKey());
445                 buffer.append('=');
446                 buffer.append(entry.getValue());
447             }
448             if (i.hasNext()) {
449                 buffer.append('&');
450             }
451         }
452         return buffer.toString();
453     }
454
455     /**
456      * Create new <code>SourceParameters</code> with the same
457      * parameters as the current request
458      */

459     public static SourceParameters createParameters(Request request) {
460         final SourceParameters pars = new SourceParameters();
461
462         if (null != request) {
463             final Enumeration JavaDoc names = request.getParameterNames();
464             while (names.hasMoreElements()) {
465                 final String JavaDoc current = (String JavaDoc)names.nextElement();
466                 final String JavaDoc[] values = request.getParameterValues(current);
467                 if (null != values) {
468                     for(int i=0; i < values.length; i++) {
469                         pars.setParameter(current, values[i]);
470                     }
471                 }
472             }
473         }
474
475         return pars;
476     }
477
478     /**
479      * Remove any authorisation details from a URI
480      */

481     public static String JavaDoc removeAuthorisation(String JavaDoc uri) {
482         if (uri.indexOf("@")!=-1 && (uri.startsWith("ftp://") || uri.startsWith("http://"))) {
483             return uri.substring(0, uri.indexOf(":")+2)+uri.substring(uri.indexOf("@")+1);
484         }
485         return uri;
486     }
487
488     // FIXME Remove when JDK1.3 support is removed.
489
private static Method JavaDoc urlEncode;
490     private static Method JavaDoc urlDecode;
491
492     static {
493         if (SystemUtils.isJavaVersionAtLeast(140)) {
494             try {
495                 urlEncode = URLEncoder JavaDoc.class.getMethod("encode", new Class JavaDoc[]{String JavaDoc.class, String JavaDoc.class});
496                 urlDecode = URLDecoder JavaDoc.class.getMethod("decode", new Class JavaDoc[]{String JavaDoc.class, String JavaDoc.class});
497             } catch (NoSuchMethodException JavaDoc e) {
498                 // EMPTY
499
}
500         } else {
501             urlEncode = null;
502             urlDecode = null;
503         }
504         }
505
506     /**
507      * Pass through to the {@link java.net.URLEncoder}. If running under JDK &lt; 1.4,
508      * default encoding will always be used.
509      */

510     public static String JavaDoc encode(String JavaDoc s, String JavaDoc enc) throws UnsupportedEncodingException JavaDoc {
511         if (urlEncode != null) {
512             try {
513                 return (String JavaDoc)urlEncode.invoke(s, new Object JavaDoc[]{ s, enc } );
514             } catch (IllegalAccessException JavaDoc e) {
515                 // EMPTY
516
} catch (InvocationTargetException JavaDoc e) {
517                 if (e.getTargetException() instanceof UnsupportedEncodingException JavaDoc) {
518                     throw (UnsupportedEncodingException JavaDoc)e.getTargetException();
519                 } else if (e.getTargetException() instanceof RuntimeException JavaDoc) {
520                     throw (RuntimeException JavaDoc)e.getTargetException();
521                 }
522             }
523         }
524         return URLEncoder.encode(s);
525     }
526
527     /**
528      * Pass through to the {@link java.net.URLDecoder}. If running under JDK &lt; 1.4,
529      * default encoding will always be used.
530      */

531     public static String JavaDoc decode(String JavaDoc s, String JavaDoc enc) throws UnsupportedEncodingException JavaDoc {
532         if (urlDecode != null) {
533             try {
534                 return (String JavaDoc)urlDecode.invoke(s, new Object JavaDoc[]{ s, enc } );
535             } catch (IllegalAccessException JavaDoc e) {
536                 // EMPTY
537
} catch (InvocationTargetException JavaDoc e) {
538                 if (e.getTargetException() instanceof UnsupportedEncodingException JavaDoc) {
539                     throw (UnsupportedEncodingException JavaDoc)e.getTargetException();
540                 } else if (e.getTargetException() instanceof RuntimeException JavaDoc) {
541                     throw (RuntimeException JavaDoc)e.getTargetException();
542                 }
543             }
544         }
545         return URLDecoder.decode(s);
546     }
547 }
548
Popular Tags