KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > java > net > URLStreamHandler


1 /*
2  * @(#)URLStreamHandler.java 1.73 06/04/07
3  *
4  * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  */

7
8 package java.net;
9
10 import java.io.IOException JavaDoc;
11 import java.io.InputStream JavaDoc;
12 import java.io.File JavaDoc;
13 import java.io.OutputStream JavaDoc;
14 import java.util.Hashtable JavaDoc;
15 import sun.net.util.IPAddressUtil;
16 import sun.net.www.ParseUtil;
17
18 /**
19  * The abstract class <code>URLStreamHandler</code> is the common
20  * superclass for all stream protocol handlers. A stream protocol
21  * handler knows how to make a connection for a particular protocol
22  * type, such as <code>http</code>, <code>ftp</code>, or
23  * <code>gopher</code>.
24  * <p>
25  * In most cases, an instance of a <code>URLStreamHandler</code>
26  * subclass is not created directly by an application. Rather, the
27  * first time a protocol name is encountered when constructing a
28  * <code>URL</code>, the appropriate stream protocol handler is
29  * automatically loaded.
30  *
31  * @author James Gosling
32  * @version 1.73, 04/07/06
33  * @see java.net.URL#URL(java.lang.String, java.lang.String, int, java.lang.String)
34  * @since JDK1.0
35  */

36 public abstract class URLStreamHandler {
37     /**
38      * Opens a connection to the object referenced by the
39      * <code>URL</code> argument.
40      * This method should be overridden by a subclass.
41      *
42      * <p>If for the handler's protocol (such as HTTP or JAR), there
43      * exists a public, specialized URLConnection subclass belonging
44      * to one of the following packages or one of their subpackages:
45      * java.lang, java.io, java.util, java.net, the connection
46      * returned will be of that subclass. For example, for HTTP an
47      * HttpURLConnection will be returned, and for JAR a
48      * JarURLConnection will be returned.
49      *
50      * @param u the URL that this connects to.
51      * @return a <code>URLConnection</code> object for the <code>URL</code>.
52      * @exception IOException if an I/O error occurs while opening the
53      * connection.
54      */

55     abstract protected URLConnection JavaDoc openConnection(URL JavaDoc u) throws IOException JavaDoc;
56
57     /**
58      * Same as openConnection(URL), except that the connection will be
59      * made through the specified proxy; Protocol handlers that do not
60      * support proxying will ignore the proxy parameter and make a
61      * normal connection.
62      *
63      * Calling this method preempts the system's default ProxySelector
64      * settings.
65      *
66      * @param u the URL that this connects to.
67      * @param p the proxy through which the connection will be made.
68      * If direct connection is desired, Proxy.NO_PROXY
69      * should be specified.
70      * @return a <code>URLConnection</code> object for the <code>URL</code>.
71      * @exception IOException if an I/O error occurs while opening the
72      * connection.
73      * @exception IllegalArgumentException if either u or p is null,
74      * or p has the wrong type.
75      * @exception UnsupportedOperationException if the subclass that
76      * implements the protocol doesn't support this method.
77      * @since 1.5
78      */

79     protected URLConnection JavaDoc openConnection(URL JavaDoc u, Proxy JavaDoc p) throws IOException JavaDoc {
80     throw new UnsupportedOperationException JavaDoc("Method not implemented.");
81     }
82
83     /**
84      * Parses the string representation of a <code>URL</code> into a
85      * <code>URL</code> object.
86      * <p>
87      * If there is any inherited context, then it has already been
88      * copied into the <code>URL</code> argument.
89      * <p>
90      * The <code>parseURL</code> method of <code>URLStreamHandler</code>
91      * parses the string representation as if it were an
92      * <code>http</code> specification. Most URL protocol families have a
93      * similar parsing. A stream protocol handler for a protocol that has
94      * a different syntax must override this routine.
95      *
96      * @param u the <code>URL</code> to receive the result of parsing
97      * the spec.
98      * @param spec the <code>String</code> representing the URL that
99      * must be parsed.
100      * @param start the character index at which to begin parsing. This is
101      * just past the '<code>:</code>' (if there is one) that
102      * specifies the determination of the protocol name.
103      * @param limit the character position to stop parsing at. This is the
104      * end of the string or the position of the
105      * "<code>#</code>" character, if present. All information
106      * after the sharp sign indicates an anchor.
107      */

108     protected void parseURL(URL JavaDoc u, String JavaDoc spec, int start, int limit) {
109         // These fields may receive context content if this was relative URL
110
String JavaDoc protocol = u.getProtocol();
111         String JavaDoc authority = u.getAuthority();
112         String JavaDoc userInfo = u.getUserInfo();
113         String JavaDoc host = u.getHost();
114         int port = u.getPort();
115         String JavaDoc path = u.getPath();
116     String JavaDoc query = u.getQuery();
117
118         // This field has already been parsed
119
String JavaDoc ref = u.getRef();
120
121     boolean isRelPath = false;
122     boolean queryOnly = false;
123
124 // FIX: should not assume query if opaque
125
// Strip off the query part
126
if (start < limit) {
127             int queryStart = spec.indexOf('?');
128             queryOnly = queryStart == start;
129             if ((queryStart != -1) && (queryStart < limit)) {
130                 query = spec.substring(queryStart+1, limit);
131                 if (limit > queryStart)
132                     limit = queryStart;
133                 spec = spec.substring(0, queryStart);
134             }
135     }
136
137     int i = 0;
138         // Parse the authority part if any
139
boolean isUNCName = (start <= limit - 4) &&
140                         (spec.charAt(start) == '/') &&
141                         (spec.charAt(start + 1) == '/') &&
142                         (spec.charAt(start + 2) == '/') &&
143                         (spec.charAt(start + 3) == '/');
144     if (!isUNCName && (start <= limit - 2) && (spec.charAt(start) == '/') &&
145         (spec.charAt(start + 1) == '/')) {
146         start += 2;
147         i = spec.indexOf('/', start);
148             if (i < 0) {
149             i = spec.indexOf('?', start);
150         if (i < 0)
151                     i = limit;
152         }
153
154             host = authority = spec.substring(start, i);
155
156             int ind = authority.indexOf('@');
157             if (ind != -1) {
158                 userInfo = authority.substring(0, ind);
159                 host = authority.substring(ind+1);
160         } else {
161         userInfo = null;
162         }
163         if (host != null) {
164         // If the host is surrounded by [ and ] then its an IPv6
165
// literal address as specified in RFC2732
166
if (host.length()>0 && (host.charAt(0) == '[')) {
167             if ((ind = host.indexOf(']')) > 2) {
168             
169             String JavaDoc nhost = host ;
170             host = nhost.substring(0,ind+1);
171             if (!IPAddressUtil.
172                 isIPv6LiteralAddress(host.substring(1, ind))) {
173                 throw new IllegalArgumentException JavaDoc(
174                 "Invalid host: "+ host);
175             }
176
177             port = -1 ;
178             if (nhost.length() > ind+1) {
179                 if (nhost.charAt(ind+1) == ':') {
180                 ++ind ;
181                 // port can be null according to RFC2396
182
if (nhost.length() > (ind + 1)) {
183                     port = Integer.parseInt(nhost.substring(ind+1));
184                 }
185                 } else {
186                 throw new IllegalArgumentException JavaDoc(
187                     "Invalid authority field: " + authority);
188                 }
189             }
190             } else {
191             throw new IllegalArgumentException JavaDoc(
192                 "Invalid authority field: " + authority);
193             }
194         } else {
195             ind = host.indexOf(':');
196             port = -1;
197             if (ind >= 0) {
198             // port can be null according to RFC2396
199
if (host.length() > (ind + 1)) {
200                 port = Integer.parseInt(host.substring(ind + 1));
201             }
202             host = host.substring(0, ind);
203             }
204         }
205         } else {
206         host = "";
207         }
208         if (port < -1)
209         throw new IllegalArgumentException JavaDoc("Invalid port number :" +
210                            port);
211         start = i;
212         // If the authority is defined then the path is defined by the
213
// spec only; See RFC 2396 Section 5.2.4.
214
if (authority != null && authority.length() > 0)
215                 path = "";
216     }
217
218     if (host == null) {
219         host = "";
220     }
221
222         // Parse the file path if any
223
if (start < limit) {
224         if (spec.charAt(start) == '/') {
225         path = spec.substring(start, limit);
226         } else if (path != null && path.length() > 0) {
227         isRelPath = true;
228         int ind = path.lastIndexOf('/');
229         String JavaDoc seperator = "";
230         if (ind == -1 && authority != null)
231             seperator = "/";
232         path = path.substring(0, ind + 1) + seperator +
233                  spec.substring(start, limit);
234                     
235         } else {
236         String JavaDoc seperator = (authority != null) ? "/" : "";
237         path = seperator + spec.substring(start, limit);
238         }
239     } else if (queryOnly && path != null) {
240             int ind = path.lastIndexOf('/');
241             if (ind < 0)
242                 ind = 0;
243             path = path.substring(0, ind) + "/";
244         }
245     if (path == null)
246         path = "";
247
248     if (isRelPath) {
249             // Remove embedded /./
250
while ((i = path.indexOf("/./")) >= 0) {
251             path = path.substring(0, i) + path.substring(i + 2);
252         }
253             // Remove embedded /../ if possible
254
i = 0;
255         while ((i = path.indexOf("/../", i)) >= 0) {
256         /*
257          * A "/../" will cancel the previous segment and itself,
258          * unless that segment is a "/../" itself
259          * i.e. "/a/b/../c" becomes "/a/c"
260          * but "/../../a" should stay unchanged
261          */

262             if (i > 0 && (limit = path.lastIndexOf('/', i - 1)) >= 0 &&
263             (path.indexOf("/../", limit) != 0)) {
264             path = path.substring(0, limit) + path.substring(i + 3);
265             i = 0;
266             } else {
267             i = i + 3;
268         }
269         }
270             // Remove trailing .. if possible
271
while (path.endsWith("/..")) {
272                 i = path.indexOf("/..");
273             if ((limit = path.lastIndexOf('/', i - 1)) >= 0) {
274             path = path.substring(0, limit+1);
275             } else {
276             break;
277         }
278         }
279         // Remove starting .
280
if (path.startsWith("./") && path.length() > 2)
281                 path = path.substring(2);
282
283             // Remove trailing .
284
if (path.endsWith("/."))
285                 path = path.substring(0, path.length() -1);
286     }
287
288     setURL(u, protocol, host, port, authority, userInfo, path, query, ref);
289     }
290
291     /**
292      * Returns the default port for a URL parsed by this handler. This method
293      * is meant to be overidden by handlers with default port numbers.
294      * @return the default port for a <code>URL</code> parsed by this handler.
295      * @since 1.3
296      */

297     protected int getDefaultPort() {
298         return -1;
299     }
300
301     /**
302      * Provides the default equals calculation. May be overidden by handlers
303      * for other protocols that have different requirements for equals().
304      * This method requires that none of its arguments is null. This is
305      * guaranteed by the fact that it is only called by java.net.URL class.
306      * @param u1 a URL object
307      * @param u2 a URL object
308      * @return <tt>true</tt> if the two urls are
309      * considered equal, ie. they refer to the same
310      * fragment in the same file.
311      * @since 1.3
312      */

313     protected boolean equals(URL JavaDoc u1, URL JavaDoc u2) {
314         String JavaDoc ref1 = u1.getRef();
315         String JavaDoc ref2 = u2.getRef();
316         return (ref1 == ref2 || (ref1 != null && ref1.equals(ref2))) &&
317                sameFile(u1, u2);
318     }
319
320     /**
321      * Provides the default hash calculation. May be overidden by handlers for
322      * other protocols that have different requirements for hashCode
323      * calculation.
324      * @param u a URL object
325      * @return an <tt>int</tt> suitable for hash table indexing
326      * @since 1.3
327      */

328     protected int hashCode(URL JavaDoc u) {
329         int h = 0;
330
331         // Generate the protocol part.
332
String JavaDoc protocol = u.getProtocol();
333         if (protocol != null)
334         h += protocol.hashCode();
335
336         // Generate the host part.
337
InetAddress JavaDoc addr = getHostAddress(u);
338     if (addr != null) {
339         h += addr.hashCode();
340     } else {
341             String JavaDoc host = u.getHost();
342             if (host != null)
343             h += host.toLowerCase().hashCode();
344         }
345
346         // Generate the file part.
347
String JavaDoc file = u.getFile();
348     if (file != null)
349         h += file.hashCode();
350
351         // Generate the port part.
352
if (u.getPort() == -1)
353             h += getDefaultPort();
354     else
355             h += u.getPort();
356
357         // Generate the ref part.
358
String JavaDoc ref = u.getRef();
359     if (ref != null)
360             h += ref.hashCode();
361
362     return h;
363     }
364
365     /**
366      * Compare two urls to see whether they refer to the same file,
367      * i.e., having the same protocol, host, port, and path.
368      * This method requires that none of its arguments is null. This is
369      * guaranteed by the fact that it is only called indirectly
370      * by java.net.URL class.
371      * @param u1 a URL object
372      * @param u2 a URL object
373      * @return true if u1 and u2 refer to the same file
374      * @since 1.3
375      */

376     protected boolean sameFile(URL JavaDoc u1, URL JavaDoc u2) {
377         // Compare the protocols.
378
if (!((u1.getProtocol() == u2.getProtocol()) ||
379               (u1.getProtocol() != null &&
380                u1.getProtocol().equalsIgnoreCase(u2.getProtocol()))))
381             return false;
382
383     // Compare the files.
384
if (!(u1.getFile() == u2.getFile() ||
385               (u1.getFile() != null && u1.getFile().equals(u2.getFile()))))
386         return false;
387
388     // Compare the ports.
389
int port1, port2;
390         port1 = (u1.getPort() != -1) ? u1.getPort() : u1.handler.getDefaultPort();
391         port2 = (u2.getPort() != -1) ? u2.getPort() : u2.handler.getDefaultPort();
392     if (port1 != port2)
393         return false;
394
395     // Compare the hosts.
396
if (!hostsEqual(u1, u2))
397             return false;
398
399         return true;
400     }
401
402     /**
403      * Get the IP address of our host. An empty host field or a DNS failure
404      * will result in a null return.
405      *
406      * @param u a URL object
407      * @return an <code>InetAddress</code> representing the host
408      * IP address.
409      * @since 1.3
410      */

411     protected synchronized InetAddress JavaDoc getHostAddress(URL JavaDoc u) {
412     if (u.hostAddress != null)
413             return u.hostAddress;
414     
415         String JavaDoc host = u.getHost();
416         if (host == null || host.equals("")) {
417             return null;
418         } else {
419             try {
420                 u.hostAddress = InetAddress.getByName(host);
421             } catch (UnknownHostException JavaDoc ex) {
422                 return null;
423             } catch (SecurityException JavaDoc se) {
424                 return null;
425             }
426         }
427     return u.hostAddress;
428     }
429
430     /**
431      * Compares the host components of two URLs.
432      * @param u1 the URL of the first host to compare
433      * @param u2 the URL of the second host to compare
434      * @return <tt>true</tt> if and only if they
435      * are equal, <tt>false</tt> otherwise.
436      * @since 1.3
437      */

438     protected boolean hostsEqual(URL JavaDoc u1, URL JavaDoc u2) {
439     InetAddress JavaDoc a1 = getHostAddress(u1);
440         InetAddress JavaDoc a2 = getHostAddress(u2);
441     // if we have internet address for both, compare them
442
if (a1 != null && a2 != null) {
443         return a1.equals(a2);
444         // else, if both have host names, compare them
445
} else if (u1.getHost() != null && u2.getHost() != null)
446             return u1.getHost().equalsIgnoreCase(u2.getHost());
447      else
448             return u1.getHost() == null && u2.getHost() == null;
449     }
450
451     /**
452      * Converts a <code>URL</code> of a specific protocol to a
453      * <code>String</code>.
454      *
455      * @param u the URL.
456      * @return a string representation of the <code>URL</code> argument.
457      */

458     protected String JavaDoc toExternalForm(URL JavaDoc u) {
459
460     // pre-compute length of StringBuffer
461
int len = u.getProtocol().length() + 1;
462     if (u.getAuthority() != null && u.getAuthority().length() > 0)
463         len += 2 + u.getAuthority().length();
464     if (u.getPath() != null) {
465         len += u.getPath().length();
466     }
467     if (u.getQuery() != null) {
468         len += 1 + u.getQuery().length();
469     }
470     if (u.getRef() != null)
471         len += 1 + u.getRef().length();
472
473     StringBuffer JavaDoc result = new StringBuffer JavaDoc(len);
474     result.append(u.getProtocol());
475         result.append(":");
476         if (u.getAuthority() != null && u.getAuthority().length() > 0) {
477             result.append("//");
478             result.append(u.getAuthority());
479         }
480         if (u.getPath() != null) {
481             result.append(u.getPath());
482         }
483         if (u.getQuery() != null) {
484             result.append('?');
485             result.append(u.getQuery());
486         }
487     if (u.getRef() != null) {
488         result.append("#");
489             result.append(u.getRef());
490     }
491     return result.toString();
492     }
493
494     /**
495      * Sets the fields of the <code>URL</code> argument to the indicated values.
496      * Only classes derived from URLStreamHandler are supposed to be able
497      * to call the set method on a URL.
498      *
499      * @param u the URL to modify.
500      * @param protocol the protocol name.
501      * @param host the remote host value for the URL.
502      * @param port the port on the remote machine.
503      * @param authority the authority part for the URL.
504      * @param userInfo the userInfo part of the URL.
505      * @param path the path component of the URL.
506      * @param query the query part for the URL.
507      * @param ref the reference.
508      * @exception SecurityException if the protocol handler of the URL is
509      * different from this one
510      * @see java.net.URL#set(java.lang.String, java.lang.String, int, java.lang.String, java.lang.String)
511      * @since 1.3
512      */

513        protected void setURL(URL JavaDoc u, String JavaDoc protocol, String JavaDoc host, int port,
514                      String JavaDoc authority, String JavaDoc userInfo, String JavaDoc path,
515                              String JavaDoc query, String JavaDoc ref) {
516     if (this != u.handler) {
517         throw new SecurityException JavaDoc("handler for url different from " +
518                     "this handler");
519     }
520     // ensure that no one can reset the protocol on a given URL.
521
u.set(u.getProtocol(), host, port, authority, userInfo, path, query, ref);
522     }
523
524     /**
525      * Sets the fields of the <code>URL</code> argument to the indicated values.
526      * Only classes derived from URLStreamHandler are supposed to be able
527      * to call the set method on a URL.
528      *
529      * @param u the URL to modify.
530      * @param protocol the protocol name. This value is ignored since 1.2.
531      * @param host the remote host value for the URL.
532      * @param port the port on the remote machine.
533      * @param file the file.
534      * @param ref the reference.
535      * @exception SecurityException if the protocol handler of the URL is
536      * different from this one
537      * @deprecated Use setURL(URL, String, String, int, String, String, String,
538      * String);
539      */

540     @Deprecated JavaDoc
541     protected void setURL(URL JavaDoc u, String JavaDoc protocol, String JavaDoc host, int port,
542                           String JavaDoc file, String JavaDoc ref) {
543         /*
544          * Only old URL handlers call this, so assume that the host
545          * field might contain "user:passwd@host". Fix as necessary.
546          */

547         String JavaDoc authority = null;
548         String JavaDoc userInfo = null;
549         if (host != null && host.length() != 0) {
550         authority = (port == -1) ? host : host + ":" + port;
551             int at = host.lastIndexOf('@');
552             if (at != -1) {
553                 userInfo = host.substring(0, at);
554                 host = host.substring(at+1);
555             }
556         }
557         
558         /*
559          * Assume file might contain query part. Fix as necessary.
560          */

561         String JavaDoc path = null;
562         String JavaDoc query = null;
563         if (file != null) {
564             int q = file.lastIndexOf('?');
565             if (q != -1) {
566                 query = file.substring(q+1);
567                 path = file.substring(0, q);
568             } else
569                 path = file;
570         }
571         setURL(u, protocol, host, port, authority, userInfo, path, query, ref);
572     }
573 }
574
Popular Tags