KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > java > net > URL


1 /*
2  * @(#)URL.java 1.130 04/08/25
3  *
4  * Copyright 2004 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.OutputStream JavaDoc;
13 import java.util.Hashtable JavaDoc;
14 import java.util.StringTokenizer JavaDoc;
15 import sun.security.util.SecurityConstants;
16
17 /**
18  * Class <code>URL</code> represents a Uniform Resource
19  * Locator, a pointer to a "resource" on the World
20  * Wide Web. A resource can be something as simple as a file or a
21  * directory, or it can be a reference to a more complicated object,
22  * such as a query to a database or to a search engine. More
23  * information on the types of URLs and their formats can be found at:
24  * <blockquote>
25  * <a HREF="http://archive.ncsa.uiuc.edu/SDG/Software/Mosaic/Demo/url-primer.html">
26  * <i>http://archive.ncsa.uiuc.edu/SDG/Software/Mosaic/Demo/url-primer.html</i></a>
27  * </blockquote>
28  * <p>
29  * In general, a URL can be broken into several parts. The previous
30  * example of a URL indicates that the protocol to use is
31  * <code>http</code> (HyperText Transfer Protocol) and that the
32  * information resides on a host machine named
33  * <code>www.ncsa.uiuc.edu</code>. The information on that host
34  * machine is named <code>/SDG/Software/Mosaic/Demo/url-primer.html</code>. The exact
35  * meaning of this name on the host machine is both protocol
36  * dependent and host dependent. The information normally resides in
37  * a file, but it could be generated on the fly. This component of
38  * the URL is called the <i>path</i> component.
39  * <p>
40  * A URL can optionally specify a "port", which is the
41  * port number to which the TCP connection is made on the remote host
42  * machine. If the port is not specified, the default port for
43  * the protocol is used instead. For example, the default port for
44  * <code>http</code> is <code>80</code>. An alternative port could be
45  * specified as:
46  * <blockquote><pre>
47  * http://archive.ncsa.uiuc.edu:80/SDG/Software/Mosaic/Demo/url-primer.html
48  * </pre></blockquote>
49  * <p>
50  * The syntax of <code>URL</code> is defined by <a
51  * HREF="http://www.ietf.org/rfc/rfc2396.txt""><i>RFC&nbsp;2396: Uniform
52  * Resource Identifiers (URI): Generic Syntax</i></a>, amended by <a
53  * HREF="http://www.ietf.org/rfc/rfc2732.txt"><i>RFC&nbsp;2732: Format for
54  * Literal IPv6 Addresses in URLs</i></a>. The Literal IPv6 address format
55  * also supports scope_ids. The syntax and usage of scope_ids is described
56  * <a HREF="Inet6Address.html#scoped">here</a>.
57  * <p>
58  * A URL may have appended to it a "fragment", also known
59  * as a "ref" or a "reference". The fragment is indicated by the sharp
60  * sign character "#" followed by more characters. For example,
61  * <blockquote><pre>
62  * http://java.sun.com/index.html#chapter1
63  * </pre></blockquote>
64  * <p>
65  * This fragment is not technically part of the URL. Rather, it
66  * indicates that after the specified resource is retrieved, the
67  * application is specifically interested in that part of the
68  * document that has the tag <code>chapter1</code> attached to it. The
69  * meaning of a tag is resource specific.
70  * <p>
71  * An application can also specify a "relative URL",
72  * which contains only enough information to reach the resource
73  * relative to another URL. Relative URLs are frequently used within
74  * HTML pages. For example, if the contents of the URL:
75  * <blockquote><pre>
76  * http://java.sun.com/index.html
77  * </pre></blockquote>
78  * contained within it the relative URL:
79  * <blockquote><pre>
80  * FAQ.html
81  * </pre></blockquote>
82  * it would be a shorthand for:
83  * <blockquote><pre>
84  * http://java.sun.com/FAQ.html
85  * </pre></blockquote>
86  * <p>
87  * The relative URL need not specify all the components of a URL. If
88  * the protocol, host name, or port number is missing, the value is
89  * inherited from the fully specified URL. The file component must be
90  * specified. The optional fragment is not inherited.
91  * <p>
92  * The URL class does not itself encode or decode any URL components
93  * according to the escaping mechanism defined in RFC2396. It is the
94  * responsibility of the caller to encode any fields, which need to be
95  * escaped prior to calling URL, and also to decode any escaped fields,
96  * that are returned from URL. Furthermore, because URL has no knowledge
97  * of URL escaping, it does not recognise equivalence between the encoded
98  * or decoded form of the same URL. For example, the two URLs:<br>
99  * <pre> http://foo.com/hello world/ and http://foo.com/hello%20world</pre>
100  * would be considered not equal to each other.
101  * <p>
102  * Note, the {@link java.net.URI} class does perform escaping of its
103  * component fields in certain circumstances. The recommended way
104  * to manage the encoding and decoding of URLs is to use {@link java.net.URI},
105  * and to convert between these two classes using {@link #toURI()} and
106  * {@link URI#toURL()}.
107  * <p>
108  * The {@link URLEncoder} and {@link URLDecoder} classes can also be
109  * used, but only for HTML form encoding, which is not the same
110  * as the encoding scheme defined in RFC2396.
111  *
112  * @author James Gosling
113  * @version 1.130, 08/25/04
114  * @since JDK1.0
115  */

116 public final class URL implements java.io.Serializable JavaDoc {
117
118     static final long serialVersionUID = -7627629688361524110L;
119
120     /**
121      * The property which specifies the package prefix list to be scanned
122      * for protocol handlers. The value of this property (if any) should
123      * be a vertical bar delimited list of package names to search through
124      * for a protocol handler to load. The policy of this class is that
125      * all protocol handlers will be in a class called <protocolname>.Handler,
126      * and each package in the list is examined in turn for a matching
127      * handler. If none are found (or the property is not specified), the
128      * default package prefix, sun.net.www.protocol, is used. The search
129      * proceeds from the first package in the list to the last and stops
130      * when a match is found.
131      */

132     private static final String JavaDoc protocolPathProp = "java.protocol.handler.pkgs";
133
134     /**
135      * The protocol to use (ftp, http, nntp, ... etc.) .
136      * @serial
137      */

138     private String JavaDoc protocol;
139
140     /**
141      * The host name to connect to.
142      * @serial
143      */

144     private String JavaDoc host;
145
146     /**
147      * The protocol port to connect to.
148      * @serial
149      */

150     private int port = -1;
151
152     /**
153      * The specified file name on that host. <code>file</code> is
154      * defined as <code>path[?query]</code>
155      * @serial
156      */

157     private String JavaDoc file;
158
159     /**
160      * The query part of this URL.
161      */

162     private transient String JavaDoc query;
163
164     /**
165      * The authority part of this URL.
166      * @serial
167      */

168     private String JavaDoc authority;
169
170     /**
171      * The path part of this URL.
172      */

173     private transient String JavaDoc path;
174
175     /**
176      * The userinfo part of this URL.
177      */

178     private transient String JavaDoc userInfo;
179
180     /**
181      * # reference.
182      * @serial
183      */

184     private String JavaDoc ref;
185
186     /**
187      * The host's IP address, used in equals and hashCode.
188      * Computed on demand. An uninitialized or unknown hostAddress is null.
189      */

190     transient InetAddress JavaDoc hostAddress;
191
192     /**
193      * The URLStreamHandler for this URL.
194      */

195     transient URLStreamHandler JavaDoc handler;
196
197     /* Our hash code.
198      * @serial
199      */

200     private int hashCode = -1;
201
202     /**
203      * Creates a <code>URL</code> object from the specified
204      * <code>protocol</code>, <code>host</code>, <code>port</code>
205      * number, and <code>file</code>.<p>
206      *
207      * <code>host</code> can be expressed as a host name or a literal
208      * IP address. If IPv6 literal address is used, it should be
209      * enclosed in square brackets (<tt>'['</tt> and <tt>']'</tt>), as
210      * specified by <a
211      * HREF="http://www.ietf.org/rfc/rfc2732.txt">RFC&nbsp;2732</a>;
212      * However, the literal IPv6 address format defined in <a
213      * HREF="http://www.ietf.org/rfc/rfc2373.txt"><i>RFC&nbsp;2373: IP
214      * Version 6 Addressing Architecture</i></a> is also accepted.<p>
215      *
216      * Specifying a <code>port</code> number of <code>-1</code>
217      * indicates that the URL should use the default port for the
218      * protocol.<p>
219      *
220      * If this is the first URL object being created with the specified
221      * protocol, a <i>stream protocol handler</i> object, an instance of
222      * class <code>URLStreamHandler</code>, is created for that protocol:
223      * <ol>
224      * <li>If the application has previously set up an instance of
225      * <code>URLStreamHandlerFactory</code> as the stream handler factory,
226      * then the <code>createURLStreamHandler</code> method of that instance
227      * is called with the protocol string as an argument to create the
228      * stream protocol handler.
229      * <li>If no <code>URLStreamHandlerFactory</code> has yet been set up,
230      * or if the factory's <code>createURLStreamHandler</code> method
231      * returns <code>null</code>, then the constructor finds the
232      * value of the system property:
233      * <blockquote><pre>
234      * java.protocol.handler.pkgs
235      * </pre></blockquote>
236      * If the value of that system property is not <code>null</code>,
237      * it is interpreted as a list of packages separated by a vertical
238      * slash character '<code>|</code>'. The constructor tries to load
239      * the class named:
240      * <blockquote><pre>
241      * &lt;<i>package</i>&gt;.&lt;<i>protocol</i>&gt;.Handler
242      * </pre></blockquote>
243      * where &lt;<i>package</i>&gt; is replaced by the name of the package
244      * and &lt;<i>protocol</i>&gt; is replaced by the name of the protocol.
245      * If this class does not exist, or if the class exists but it is not
246      * a subclass of <code>URLStreamHandler</code>, then the next package
247      * in the list is tried.
248      * <li>If the previous step fails to find a protocol handler, then the
249      * constructor tries to load from a system default package.
250      * <blockquote><pre>
251      * &lt;<i>system default package</i>&gt;.&lt;<i>protocol</i>&gt;.Handler
252      * </pre></blockquote>
253      * If this class does not exist, or if the class exists but it is not a
254      * subclass of <code>URLStreamHandler</code>, then a
255      * <code>MalformedURLException</code> is thrown.
256      * </ol>
257      *
258      * <p>Protocol handlers for the following protocols are guaranteed
259      * to exist on the search path :-
260      * <blockquote><pre>
261      * http, https, ftp, file, and jar
262      * </pre></blockquote>
263      * Protocol handlers for additional protocols may also be
264      * available.
265      *
266      * <p>No validation of the inputs is performed by this constructor.
267      *
268      * @param protocol the name of the protocol to use.
269      * @param host the name of the host.
270      * @param port the port number on the host.
271      * @param file the file on the host
272      * @exception MalformedURLException if an unknown protocol is specified.
273      * @see java.lang.System#getProperty(java.lang.String)
274      * @see java.net.URL#setURLStreamHandlerFactory(
275      * java.net.URLStreamHandlerFactory)
276      * @see java.net.URLStreamHandler
277      * @see java.net.URLStreamHandlerFactory#createURLStreamHandler(
278      * java.lang.String)
279      */

280     public URL(String JavaDoc protocol, String JavaDoc host, int port, String JavaDoc file)
281     throws MalformedURLException JavaDoc
282     {
283     this(protocol, host, port, file, null);
284     }
285
286     /**
287      * Creates a URL from the specified <code>protocol</code>
288      * name, <code>host</code> name, and <code>file</code> name. The
289      * default port for the specified protocol is used.
290      * <p>
291      * This method is equivalent to calling the four-argument
292      * constructor with the arguments being <code>protocol</code>,
293      * <code>host</code>, <code>-1</code>, and <code>file</code>.
294      *
295      * No validation of the inputs is performed by this constructor.
296      *
297      * @param protocol the name of the protocol to use.
298      * @param host the name of the host.
299      * @param file the file on the host.
300      * @exception MalformedURLException if an unknown protocol is specified.
301      * @see java.net.URL#URL(java.lang.String, java.lang.String,
302      * int, java.lang.String)
303      */

304     public URL(String JavaDoc protocol, String JavaDoc host, String JavaDoc file)
305         throws MalformedURLException JavaDoc {
306     this(protocol, host, -1, file);
307     }
308
309     /**
310      * Creates a <code>URL</code> object from the specified
311      * <code>protocol</code>, <code>host</code>, <code>port</code>
312      * number, <code>file</code>, and <code>handler</code>. Specifying
313      * a <code>port</code> number of <code>-1</code> indicates that
314      * the URL should use the default port for the protocol. Specifying
315      * a <code>handler</code> of <code>null</code> indicates that the URL
316      * should use a default stream handler for the protocol, as outlined
317      * for:
318      * java.net.URL#URL(java.lang.String, java.lang.String, int,
319      * java.lang.String)
320      *
321      * <p>If the handler is not null and there is a security manager,
322      * the security manager's <code>checkPermission</code>
323      * method is called with a
324      * <code>NetPermission("specifyStreamHandler")</code> permission.
325      * This may result in a SecurityException.
326      *
327      * No validation of the inputs is performed by this constructor.
328      *
329      * @param protocol the name of the protocol to use.
330      * @param host the name of the host.
331      * @param port the port number on the host.
332      * @param file the file on the host
333      * @param handler the stream handler for the URL.
334      * @exception MalformedURLException if an unknown protocol is specified.
335      * @exception SecurityException
336      * if a security manager exists and its
337      * <code>checkPermission</code> method doesn't allow
338      * specifying a stream handler explicitly.
339      * @see java.lang.System#getProperty(java.lang.String)
340      * @see java.net.URL#setURLStreamHandlerFactory(
341      * java.net.URLStreamHandlerFactory)
342      * @see java.net.URLStreamHandler
343      * @see java.net.URLStreamHandlerFactory#createURLStreamHandler(
344      * java.lang.String)
345      * @see SecurityManager#checkPermission
346      * @see java.net.NetPermission
347      */

348     public URL(String JavaDoc protocol, String JavaDoc host, int port, String JavaDoc file,
349            URLStreamHandler JavaDoc handler) throws MalformedURLException JavaDoc {
350     if (handler != null) {
351             SecurityManager JavaDoc sm = System.getSecurityManager();
352             if (sm != null) {
353                 // check for permission to specify a handler
354
checkSpecifyHandler(sm);
355             }
356         }
357
358     protocol = protocol.toLowerCase();
359         this.protocol = protocol;
360     if (host != null) {
361
362             /**
363          * if host is a literal IPv6 address,
364              * we will make it conform to RFC 2732
365          */

366             if (host != null && host.indexOf(':') >= 0
367                     && !host.startsWith("[")) {
368                 host = "["+host+"]";
369             }
370             this.host = host;
371
372         if (port < -1) {
373         throw new MalformedURLException JavaDoc("Invalid port number :" +
374                                                     port);
375         }
376             this.port = port;
377         authority = (port == -1) ? host : host + ":" + port;
378     }
379
380     Parts parts = new Parts(file);
381         path = parts.getPath();
382         query = parts.getQuery();
383
384         if (query != null) {
385             this.file = path + "?" + query;
386         } else {
387             this.file = path;
388         }
389     ref = parts.getRef();
390
391     // Note: we don't do validation of the URL here. Too risky to change
392
// right now, but worth considering for future reference. -br
393
if (handler == null &&
394             (handler = getURLStreamHandler(protocol)) == null) {
395             throw new MalformedURLException JavaDoc("unknown protocol: " + protocol);
396         }
397         this.handler = handler;
398     }
399
400     /**
401      * Creates a <code>URL</code> object from the <code>String</code>
402      * representation.
403      * <p>
404      * This constructor is equivalent to a call to the two-argument
405      * constructor with a <code>null</code> first argument.
406      *
407      * @param spec the <code>String</code> to parse as a URL.
408      * @exception MalformedURLException If the string specifies an
409      * unknown protocol.
410      * @see java.net.URL#URL(java.net.URL, java.lang.String)
411      */

412     public URL(String JavaDoc spec) throws MalformedURLException JavaDoc {
413     this(null, spec);
414     }
415
416     /**
417      * Creates a URL by parsing the given spec within a specified context.
418      *
419      * The new URL is created from the given context URL and the spec
420      * argument as described in
421      * RFC2396 &quot;Uniform Resource Identifiers : Generic * Syntax&quot; :
422      * <blockquote><pre>
423      * &lt;scheme&gt;://&lt;authority&gt;&lt;path&gt;?&lt;query&gt;#&lt;fragment&gt;
424      * </pre></blockquote>
425      * The reference is parsed into the scheme, authority, path, query and
426      * fragment parts. If the path component is empty and the scheme,
427      * authority, and query components are undefined, then the new URL is a
428      * reference to the current document. Otherwise, the fragment and query
429      * parts present in the spec are used in the new URL.
430      * <p>
431      * If the scheme component is defined in the given spec and does not match
432      * the scheme of the context, then the new URL is created as an absolute
433      * URL based on the spec alone. Otherwise the scheme component is inherited
434      * from the context URL.
435      * <p>
436      * If the authority component is present in the spec then the spec is
437      * treated as absolute and the spec authority and path will replace the
438      * context authority and path. If the authority component is absent in the
439      * spec then the authority of the new URL will be inherited from the
440      * context.
441      * <p>
442      * If the spec's path component begins with a slash character
443      * &quot;/&quot; then the
444      * path is treated as absolute and the spec path replaces the context path.
445      * <p>
446      * Otherwise, the path is treated as a relative path and is appended to the
447      * context path, as described in RFC2396. Also, in this case,
448      * the path is canonicalized through the removal of directory
449      * changes made by occurences of &quot;..&quot; and &quot;.&quot;.
450      * <p>
451      * For a more detailed description of URL parsing, refer to RFC2396.
452      *
453      * @param context the context in which to parse the specification.
454      * @param spec the <code>String</code> to parse as a URL.
455      * @exception MalformedURLException if no protocol is specified, or an
456      * unknown protocol is found.
457      * @see java.net.URL#URL(java.lang.String, java.lang.String,
458      * int, java.lang.String)
459      * @see java.net.URLStreamHandler
460      * @see java.net.URLStreamHandler#parseURL(java.net.URL,
461      * java.lang.String, int, int)
462      */

463     public URL(URL JavaDoc context, String JavaDoc spec) throws MalformedURLException JavaDoc {
464     this(context, spec, null);
465     }
466
467     /**
468      * Creates a URL by parsing the given spec with the specified handler
469      * within a specified context. If the handler is null, the parsing
470      * occurs as with the two argument constructor.
471      *
472      * @param context the context in which to parse the specification.
473      * @param spec the <code>String</code> to parse as a URL.
474      * @param handler the stream handler for the URL.
475      * @exception MalformedURLException if no protocol is specified, or an
476      * unknown protocol is found.
477      * @exception SecurityException
478      * if a security manager exists and its
479      * <code>checkPermission</code> method doesn't allow
480      * specifying a stream handler.
481      * @see java.net.URL#URL(java.lang.String, java.lang.String,
482      * int, java.lang.String)
483      * @see java.net.URLStreamHandler
484      * @see java.net.URLStreamHandler#parseURL(java.net.URL,
485      * java.lang.String, int, int)
486      */

487     public URL(URL JavaDoc context, String JavaDoc spec, URLStreamHandler JavaDoc handler)
488     throws MalformedURLException JavaDoc
489     {
490     String JavaDoc original = spec;
491     int i, limit, c;
492     int start = 0;
493     String JavaDoc newProtocol = null;
494     boolean aRef=false;
495     boolean isRelative = false;
496
497     // Check for permission to specify a handler
498
if (handler != null) {
499         SecurityManager JavaDoc sm = System.getSecurityManager();
500         if (sm != null) {
501         checkSpecifyHandler(sm);
502         }
503     }
504
505     try {
506         limit = spec.length();
507         while ((limit > 0) && (spec.charAt(limit - 1) <= ' ')) {
508         limit--; //eliminate trailing whitespace
509
}
510         while ((start < limit) && (spec.charAt(start) <= ' ')) {
511         start++; // eliminate leading whitespace
512
}
513
514         if (spec.regionMatches(true, start, "url:", 0, 4)) {
515         start += 4;
516         }
517         if (start < spec.length() && spec.charAt(start) == '#') {
518         /* we're assuming this is a ref relative to the context URL.
519          * This means protocols cannot start w/ '#', but we must parse
520          * ref URL's like: "hello:there" w/ a ':' in them.
521          */

522         aRef=true;
523         }
524         for (i = start ; !aRef && (i < limit) &&
525              ((c = spec.charAt(i)) != '/') ; i++) {
526         if (c == ':') {
527
528             String JavaDoc s = spec.substring(start, i).toLowerCase();
529             if (isValidProtocol(s)) {
530             newProtocol = s;
531             start = i + 1;
532             }
533             break;
534         }
535         }
536
537         // Only use our context if the protocols match.
538
protocol = newProtocol;
539         if ((context != null) && ((newProtocol == null) ||
540                 newProtocol.equalsIgnoreCase(context.protocol))) {
541                 // inherit the protocol handler from the context
542
// if not specified to the contructor
543
if (handler == null) {
544             handler = context.handler;
545         }
546
547                 // If the context is a hierarchical URL scheme and the spec
548
// contains a matching scheme then maintain backwards
549
// compatibility and treat it as if the spec didn't contain
550
// the scheme; see 5.2.3 of RFC2396
551
if (context.path != null && context.path.startsWith("/"))
552             newProtocol = null;
553
554                 if (newProtocol == null) {
555                     protocol = context.protocol;
556             authority = context.authority;
557             userInfo = context.userInfo;
558                     host = context.host;
559                     port = context.port;
560                     file = context.file;
561             path = context.path;
562             isRelative = true;
563                 }
564         }
565
566         if (protocol == null) {
567         throw new MalformedURLException JavaDoc("no protocol: "+original);
568         }
569
570         // Get the protocol handler if not specified or the protocol
571
// of the context could not be used
572
if (handler == null &&
573             (handler = getURLStreamHandler(protocol)) == null) {
574         throw new MalformedURLException JavaDoc("unknown protocol: "+protocol);
575         }
576
577         this.handler = handler;
578
579         i = spec.indexOf('#', start);
580         if (i >= 0) {
581         ref = spec.substring(i + 1, limit);
582         limit = i;
583         }
584         
585         /*
586          * Handle special case inheritance of query and fragment
587          * implied by RFC2396 section 5.2.2.
588          */

589         if (isRelative && start == limit) {
590         query = context.query;
591         if (ref == null) {
592             ref = context.ref;
593         }
594         }
595
596         handler.parseURL(this, spec, start, limit);
597
598     } catch(MalformedURLException JavaDoc e) {
599         throw e;
600     } catch(Exception JavaDoc e) {
601         throw new MalformedURLException JavaDoc(e.getMessage());
602     }
603     }
604
605     /*
606      * Returns true if specified string is a valid protocol name.
607      */

608     private boolean isValidProtocol(String JavaDoc protocol) {
609     int len = protocol.length();
610         if (len < 1)
611             return false;
612         char c = protocol.charAt(0);
613         if (!Character.isLetter(c))
614             return false;
615     for (int i = 1; i < len; i++) {
616         c = protocol.charAt(i);
617         if (!Character.isLetterOrDigit(c) && c != '.' && c != '+' &&
618         c != '-') {
619         return false;
620         }
621     }
622     return true;
623     }
624
625     /*
626      * Checks for permission to specify a stream handler.
627      */

628     private void checkSpecifyHandler(SecurityManager JavaDoc sm) {
629     sm.checkPermission(SecurityConstants.SPECIFY_HANDLER_PERMISSION);
630     }
631
632     /**
633      * Sets the fields of the URL. This is not a public method so that
634      * only URLStreamHandlers can modify URL fields. URLs are
635      * otherwise constant.
636      *
637      * @param protocol the name of the protocol to use
638      * @param host the name of the host
639        @param port the port number on the host
640      * @param file the file on the host
641      * @param ref the internal reference in the URL
642      */

643     protected void set(String JavaDoc protocol, String JavaDoc host,
644                int port, String JavaDoc file, String JavaDoc ref) {
645     synchronized (this) {
646         this.protocol = protocol;
647         this.host = host;
648             authority = port == -1 ? host : host + ":" + port;
649         this.port = port;
650         this.file = file;
651         this.ref = ref;
652         /* This is very important. We must recompute this after the
653          * URL has been changed. */

654         hashCode = -1;
655             hostAddress = null;
656             int q = file.lastIndexOf('?');
657             if (q != -1) {
658                 query = file.substring(q+1);
659                 path = file.substring(0, q);
660             } else
661                 path = file;
662     }
663     }
664
665     /**
666      * Sets the specified 8 fields of the URL. This is not a public method so
667      * that only URLStreamHandlers can modify URL fields. URLs are otherwise
668      * constant.
669      *
670      * @param protocol the name of the protocol to use
671      * @param host the name of the host
672      * @param port the port number on the host
673      * @param authority the authority part for the url
674      * @param userInfo the username and password
675      * @param path the file on the host
676      * @param ref the internal reference in the URL
677      * @param query the query part of this URL
678      * @since 1.3
679      */

680     protected void set(String JavaDoc protocol, String JavaDoc host, int port,
681                        String JavaDoc authority, String JavaDoc userInfo, String JavaDoc path,
682                        String JavaDoc query, String JavaDoc ref) {
683     synchronized (this) {
684         this.protocol = protocol;
685         this.host = host;
686         this.port = port;
687         this.file = query == null ? path : path + "?" + query;
688             this.userInfo = userInfo;
689             this.path = path;
690         this.ref = ref;
691         /* This is very important. We must recompute this after the
692          * URL has been changed. */

693         hashCode = -1;
694             hostAddress = null;
695             this.query = query;
696             this.authority = authority;
697     }
698     }
699
700     /**
701      * Gets the query part of this <code>URL</code>.
702      *
703      * @return the query part of this <code>URL</code>,
704      * or <CODE>null</CODE> if one does not exist
705      * @since 1.3
706      */

707     public String JavaDoc getQuery() {
708     return query;
709     }
710
711     /**
712      * Gets the path part of this <code>URL</code>.
713      *
714      * @return the path part of this <code>URL</code>, or an
715      * empty string if one does not exist
716      * @since 1.3
717      */

718     public String JavaDoc getPath() {
719     return path;
720     }
721
722     /**
723      * Gets the userInfo part of this <code>URL</code>.
724      *
725      * @return the userInfo part of this <code>URL</code>, or
726      * <CODE>null</CODE> if one does not exist
727      */

728     public String JavaDoc getUserInfo() {
729     return userInfo;
730     }
731
732     /**
733      * Gets the authority part of this <code>URL</code>.
734      *
735      * @return the authority part of this <code>URL</code>
736      * @since 1.3
737      */

738     public String JavaDoc getAuthority() {
739     return authority;
740     }
741
742     /**
743      * Gets the port number of this <code>URL</code>.
744      *
745      * @return the port number, or -1 if the port is not set
746      */

747     public int getPort() {
748     return port;
749     }
750
751     /**
752      * Gets the default port number of the protocol associated
753      * with this <code>URL</code>. If the URL scheme or the URLStreamHandler
754      * for the URL do not define a default port number,
755      * then -1 is returned.
756      *
757      * @return the port number
758      */

759     public int getDefaultPort() {
760     return handler.getDefaultPort();
761     }
762
763     /**
764      * Gets the protocol name of this <code>URL</code>.
765      *
766      * @return the protocol of this <code>URL</code>.
767      */

768     public String JavaDoc getProtocol() {
769     return protocol;
770     }
771
772     /**
773      * Gets the host name of this <code>URL</code>, if applicable.
774      * The format of the host conforms to RFC 2732, i.e. for a
775      * literal IPv6 address, this method will return the IPv6 address
776      * enclosed in square brackets (<tt>'['</tt> and <tt>']'</tt>).
777      *
778      * @return the host name of this <code>URL</code>.
779      */

780     public String JavaDoc getHost() {
781     return host;
782     }
783
784     /**
785      * Gets the file name of this <code>URL</code>.
786      * The returned file portion will be
787      * the same as <CODE>getPath()</CODE>, plus the concatenation of
788      * the value of <CODE>getQuery()</CODE>, if any. If there is
789      * no query portion, this method and <CODE>getPath()</CODE> will
790      * return identical results.
791      *
792      * @return the file name of this <code>URL</code>,
793      * or an empty string if one does not exist
794      */

795     public String JavaDoc getFile() {
796     return file;
797     }
798
799     /**
800      * Gets the anchor (also known as the "reference") of this
801      * <code>URL</code>.
802      *
803      * @return the anchor (also known as the "reference") of this
804      * <code>URL</code>, or <CODE>null</CODE> if one does not exist
805      */

806     public String JavaDoc getRef() {
807     return ref;
808     }
809
810     /**
811      * Compares this URL for equality with another object.<p>
812      *
813      * If the given object is not a URL then this method immediately returns
814      * <code>false</code>.<p>
815      *
816      * Two URL objects are equal if they have the same protocol, reference
817      * equivalent hosts, have the same port number on the host, and the same
818      * file and fragment of the file.<p>
819      *
820      * Two hosts are considered equivalent if both host names can be resolved
821      * into the same IP addresses; else if either host name can't be
822      * resolved, the host names must be equal without regard to case; or both
823      * host names equal to null.<p>
824      *
825      * Since hosts comparison requires name resolution, this operation is a
826      * blocking operation. <p>
827      *
828      * Note: The defined behavior for <code>equals</code> is known to
829      * be inconsistent with virtual hosting in HTTP.
830      *
831      * @param obj the URL to compare against.
832      * @return <code>true</code> if the objects are the same;
833      * <code>false</code> otherwise.
834      */

835     public boolean equals(Object JavaDoc obj) {
836         if (!(obj instanceof URL JavaDoc))
837             return false;
838     URL JavaDoc u2 = (URL JavaDoc)obj;
839
840         return handler.equals(this, u2);
841     }
842
843     /**
844      * Creates an integer suitable for hash table indexing.<p>
845      *
846      * The hash code is based upon all the URL components relevant for URL
847      * comparison. As such, this operation is a blocking operation.<p>
848      *
849      * @return a hash code for this <code>URL</code>.
850      */

851     public synchronized int hashCode() {
852     if (hashCode != -1)
853             return hashCode;
854
855         hashCode = handler.hashCode(this);
856     return hashCode;
857     }
858
859     /**
860      * Compares two URLs, excluding the fragment component.<p>
861      *
862      * Returns <code>true</code> if this <code>URL</code> and the
863      * <code>other</code> argument are equal without taking the
864      * fragment component into consideration.
865      *
866      * @param other the <code>URL</code> to compare against.
867      * @return <code>true</code> if they reference the same remote object;
868      * <code>false</code> otherwise.
869      */

870     public boolean sameFile(URL JavaDoc other) {
871         return handler.sameFile(this, other);
872     }
873
874     /**
875      * Constructs a string representation of this <code>URL</code>. The
876      * string is created by calling the <code>toExternalForm</code>
877      * method of the stream protocol handler for this object.
878      *
879      * @return a string representation of this object.
880      * @see java.net.URL#URL(java.lang.String, java.lang.String, int,
881      * java.lang.String)
882      * @see java.net.URLStreamHandler#toExternalForm(java.net.URL)
883      */

884     public String JavaDoc toString() {
885     return toExternalForm();
886     }
887
888     /**
889      * Constructs a string representation of this <code>URL</code>. The
890      * string is created by calling the <code>toExternalForm</code>
891      * method of the stream protocol handler for this object.
892      *
893      * @return a string representation of this object.
894      * @see java.net.URL#URL(java.lang.String, java.lang.String,
895      * int, java.lang.String)
896      * @see java.net.URLStreamHandler#toExternalForm(java.net.URL)
897      */

898     public String JavaDoc toExternalForm() {
899     return handler.toExternalForm(this);
900     }
901
902     /**
903      * Returns a {@link java.net.URI} equivalent to this URL.
904      * This method functions in the same way as <code>new URI (this.toString())</code>.
905      * <p>Note, any URL instance that complies with RFC 2396 can be converted
906      * to a URI. However, some URLs that are not strictly in compliance
907      * can not be converted to a URI.
908      *
909      * @exception URISyntaxException if this URL is not formatted strictly according to
910      * to RFC2396 and cannot be converted to a URI.
911      *
912      * @return a URI instance equivalent to this URL.
913      * @since 1.5
914      */

915     public URI JavaDoc toURI() throws URISyntaxException JavaDoc {
916     return new URI JavaDoc (toString());
917     }
918      
919     /**
920      * Returns a <code>URLConnection</code> object that represents a
921      * connection to the remote object referred to by the <code>URL</code>.
922      *
923      * <p>A new connection is opened every time by calling the
924      * <code>openConnection</code> method of the protocol handler for
925      * this URL.
926      *
927      * <p>If for the URL's protocol (such as HTTP or JAR), there
928      * exists a public, specialized URLConnection subclass belonging
929      * to one of the following packages or one of their subpackages:
930      * java.lang, java.io, java.util, java.net, the connection
931      * returned will be of that subclass. For example, for HTTP an
932      * HttpURLConnection will be returned, and for JAR a
933      * JarURLConnection will be returned.
934      *
935      * @return a <code>URLConnection</code> to the URL.
936      * @exception IOException if an I/O exception occurs.
937      * @see java.net.URL#URL(java.lang.String, java.lang.String,
938      * int, java.lang.String)
939      * @see java.net.URLConnection
940      * @see java.net.URLStreamHandler#openConnection(java.net.URL)
941      */

942     public URLConnection JavaDoc openConnection() throws java.io.IOException JavaDoc {
943     return handler.openConnection(this);
944     }
945
946     /**
947      * Same as openConnection(), except that the connection will be
948      * made through the specified proxy; Protocol handlers that do not
949      * support proxing will ignore the proxy parameter and make a
950      * normal connection.
951      *
952      * Calling this method preempts the system's default ProxySelector
953      * settings.
954      *
955      * @param proxy the Proxy through which this connection
956      * will be made. If direct connection is desired,
957      * Proxy.NO_PROXY should be specified.
958      * @return a <code>URLConnection</code> to the URL.
959      * @exception IOException if an I/O exception occurs.
960      * @exception SecurityException if a security manager is present
961      * and the caller doesn't have permission to connect
962      * to the proxy.
963      * @exception IllegalArgumentException will be thrown if proxy is null,
964      * or proxy has the wrong type
965      * @exception UnsupportedOperationException if the subclass that
966      * implements the protocol handler doesn't support
967      * this method.
968      * @see java.net.URL#URL(java.lang.String, java.lang.String,
969      * int, java.lang.String)
970      * @see java.net.URLConnection
971      * @see java.net.URLStreamHandler#openConnection(java.net.URL,
972      * java.net.Proxy)
973      * @since 1.5
974      */

975     public URLConnection JavaDoc openConnection(Proxy JavaDoc proxy)
976     throws java.io.IOException JavaDoc {
977     if (proxy == null) {
978         throw new IllegalArgumentException JavaDoc("proxy can not be null");
979     }
980     
981     SecurityManager JavaDoc sm = System.getSecurityManager();
982     if (proxy.type() != Proxy.Type.DIRECT && sm != null) {
983         InetSocketAddress JavaDoc epoint = (InetSocketAddress JavaDoc) proxy.address();
984         if (epoint.isUnresolved())
985         sm.checkConnect(epoint.getHostName(), epoint.getPort());
986         else
987         sm.checkConnect(epoint.getAddress().getHostAddress(),
988                 epoint.getPort());
989     }
990     return handler.openConnection(this, proxy);
991     }
992
993     /**
994      * Opens a connection to this <code>URL</code> and returns an
995      * <code>InputStream</code> for reading from that connection. This
996      * method is a shorthand for:
997      * <blockquote><pre>
998      * openConnection().getInputStream()
999      * </pre></blockquote>
1000     *
1001     * @return an input stream for reading from the URL connection.
1002     * @exception IOException if an I/O exception occurs.
1003     * @see java.net.URL#openConnection()
1004     * @see java.net.URLConnection#getInputStream()
1005     */

1006    public final InputStream JavaDoc openStream() throws java.io.IOException JavaDoc {
1007    return openConnection().getInputStream();
1008    }
1009
1010    /**
1011     * Gets the contents of this URL. This method is a shorthand for:
1012     * <blockquote><pre>
1013     * openConnection().getContent()
1014     * </pre></blockquote>
1015     *
1016     * @return the contents of this URL.
1017     * @exception IOException if an I/O exception occurs.
1018     * @see java.net.URLConnection#getContent()
1019     */

1020    public final Object JavaDoc getContent() throws java.io.IOException JavaDoc {
1021    return openConnection().getContent();
1022    }
1023
1024    /**
1025     * Gets the contents of this URL. This method is a shorthand for:
1026     * <blockquote><pre>
1027     * openConnection().getContent(Class[])
1028     * </pre></blockquote>
1029     *
1030     * @param classes an array of Java types
1031     * @return the content object of this URL that is the first match of
1032     * the types specified in the classes array.
1033     * null if none of the requested types are supported.
1034     * @exception IOException if an I/O exception occurs.
1035     * @see java.net.URLConnection#getContent(Class[])
1036     * @since 1.3
1037     */

1038    public final Object JavaDoc getContent(Class JavaDoc[] classes)
1039    throws java.io.IOException JavaDoc {
1040    return openConnection().getContent(classes);
1041    }
1042
1043    /**
1044     * The URLStreamHandler factory.
1045     */

1046    static URLStreamHandlerFactory JavaDoc factory;
1047
1048    /**
1049     * Sets an application's <code>URLStreamHandlerFactory</code>.
1050     * This method can be called at most once in a given Java Virtual
1051     * Machine.
1052     *
1053     *<p> The <code>URLStreamHandlerFactory</code> instance is used to
1054     *construct a stream protocol handler from a protocol name.
1055     *
1056     * <p> If there is a security manager, this method first calls
1057     * the security manager's <code>checkSetFactory</code> method
1058     * to ensure the operation is allowed.
1059     * This could result in a SecurityException.
1060     *
1061     * @param fac the desired factory.
1062     * @exception Error if the application has already set a factory.
1063     * @exception SecurityException if a security manager exists and its
1064     * <code>checkSetFactory</code> method doesn't allow
1065     * the operation.
1066     * @see java.net.URL#URL(java.lang.String, java.lang.String,
1067     * int, java.lang.String)
1068     * @see java.net.URLStreamHandlerFactory
1069     * @see SecurityManager#checkSetFactory
1070     */

1071    public static void setURLStreamHandlerFactory(URLStreamHandlerFactory JavaDoc fac) {
1072    synchronized (streamHandlerLock) {
1073        if (factory != null) {
1074        throw new Error JavaDoc("factory already defined");
1075        }
1076        SecurityManager JavaDoc security = System.getSecurityManager();
1077        if (security != null) {
1078        security.checkSetFactory();
1079        }
1080        handlers.clear();
1081        factory = fac;
1082    }
1083    }
1084
1085    /**
1086     * A table of protocol handlers.
1087     */

1088    static Hashtable JavaDoc handlers = new Hashtable JavaDoc();
1089    private static Object JavaDoc streamHandlerLock = new Object JavaDoc();
1090
1091    /**
1092     * Returns the Stream Handler.
1093     * @param protocol the protocol to use
1094     */

1095    static URLStreamHandler JavaDoc getURLStreamHandler(String JavaDoc protocol) {
1096
1097    URLStreamHandler JavaDoc handler = (URLStreamHandler JavaDoc)handlers.get(protocol);
1098    if (handler == null) {
1099
1100        boolean checkedWithFactory = false;
1101
1102        // Use the factory (if any)
1103
if (factory != null) {
1104        handler = factory.createURLStreamHandler(protocol);
1105        checkedWithFactory = true;
1106        }
1107
1108        // Try java protocol handler
1109
if (handler == null) {
1110        String JavaDoc packagePrefixList = null;
1111
1112        packagePrefixList
1113            = (String JavaDoc) java.security.AccessController.doPrivileged(
1114                    new sun.security.action.GetPropertyAction(
1115                protocolPathProp,""));
1116        if (packagePrefixList != "") {
1117            packagePrefixList += "|";
1118        }
1119
1120        // REMIND: decide whether to allow the "null" class prefix
1121
// or not.
1122
packagePrefixList += "sun.net.www.protocol";
1123
1124        StringTokenizer JavaDoc packagePrefixIter =
1125            new StringTokenizer JavaDoc(packagePrefixList, "|");
1126
1127        while (handler == null &&
1128               packagePrefixIter.hasMoreTokens()) {
1129
1130            String JavaDoc packagePrefix =
1131              packagePrefixIter.nextToken().trim();
1132            try {
1133                String JavaDoc clsName = packagePrefix + "." + protocol +
1134              ".Handler";
1135            Class JavaDoc cls = null;
1136            try {
1137                            cls = Class.forName(clsName);
1138                        } catch (ClassNotFoundException JavaDoc e) {
1139                ClassLoader JavaDoc cl = ClassLoader.getSystemClassLoader();
1140                if (cl != null) {
1141                    cls = cl.loadClass(clsName);
1142                }
1143            }
1144            if (cls != null) {
1145                handler =
1146                  (URLStreamHandler JavaDoc)cls.newInstance();
1147            }
1148            } catch (Exception JavaDoc e) {
1149            // any number of exceptions can get thrown here
1150
}
1151        }
1152        }
1153
1154        synchronized (streamHandlerLock) {
1155
1156        URLStreamHandler JavaDoc handler2 = null;
1157
1158        // Check again with hashtable just in case another
1159
// thread created a handler since we last checked
1160
handler2 = (URLStreamHandler JavaDoc)handlers.get(protocol);
1161
1162        if (handler2 != null) {
1163            return handler2;
1164        }
1165
1166        // Check with factory if another thread set a
1167
// factory since our last check
1168
if (!checkedWithFactory && factory != null) {
1169            handler2 = factory.createURLStreamHandler(protocol);
1170        }
1171
1172        if (handler2 != null) {
1173            // The handler from the factory must be given more
1174
// importance. Discard the default handler that
1175
// this thread created.
1176
handler = handler2;
1177        }
1178
1179        // Insert this handler into the hashtable
1180
if (handler != null) {
1181            handlers.put(protocol, handler);
1182        }
1183
1184        }
1185    }
1186
1187    return handler;
1188
1189    }
1190
1191    /**
1192     * WriteObject is called to save the state of the URL to an
1193     * ObjectOutputStream. The handler is not saved since it is
1194     * specific to this system.
1195     *
1196     * @serialData the default write object value. When read back in,
1197     * the reader must ensure that calling getURLStreamHandler with
1198     * the protocol variable returns a valid URLStreamHandler and
1199     * throw an IOException if it does not.
1200     */

1201    private synchronized void writeObject(java.io.ObjectOutputStream JavaDoc s)
1202        throws IOException JavaDoc
1203    {
1204    s.defaultWriteObject(); // write the fields
1205
}
1206
1207    /**
1208     * readObject is called to restore the state of the URL from the
1209     * stream. It reads the components of the URL and finds the local
1210     * stream handler.
1211     */

1212    private synchronized void readObject(java.io.ObjectInputStream JavaDoc s)
1213         throws IOException JavaDoc, ClassNotFoundException JavaDoc
1214    {
1215    s.defaultReadObject(); // read the fields
1216
if ((handler = getURLStreamHandler(protocol)) == null) {
1217        throw new IOException JavaDoc("unknown protocol: " + protocol);
1218    }
1219
1220        // Construct authority part
1221
if (authority == null &&
1222        ((host != null && host.length() > 0) || port != -1)) {
1223        if (host == null)
1224        host = "";
1225            authority = (port == -1) ? host : host + ":" + port;
1226
1227            // Handle hosts with userInfo in them
1228
int at = host.lastIndexOf('@');
1229            if (at != -1) {
1230                userInfo = host.substring(0, at);
1231                host = host.substring(at+1);
1232        }
1233        } else if (authority != null) {
1234            // Construct user info part
1235
int ind = authority.indexOf('@');
1236            if (ind != -1)
1237                userInfo = authority.substring(0, ind);
1238    }
1239
1240        // Construct path and query part
1241
path = null;
1242        query = null;
1243        if (file != null) {
1244        // Fix: only do this if hierarchical?
1245
int q = file.lastIndexOf('?');
1246            if (q != -1) {
1247                query = file.substring(q+1);
1248                path = file.substring(0, q);
1249            } else
1250                path = file;
1251        }
1252    }
1253}
1254
1255class Parts {
1256    String JavaDoc path, query, ref;
1257    
1258    Parts(String JavaDoc file) {
1259    int ind = file.indexOf('#');
1260    ref = ind < 0 ? null: file.substring(ind + 1);
1261    file = ind < 0 ? file: file.substring(0, ind);
1262    int q = file.lastIndexOf('?');
1263    if (q != -1) {
1264        query = file.substring(q+1);
1265        path = file.substring(0, q);
1266    } else {
1267        path = file;
1268    }
1269    }
1270    
1271    String JavaDoc getPath() {
1272    return path;
1273    }
1274    
1275    String JavaDoc getQuery() {
1276    return query;
1277    }
1278    
1279    String JavaDoc getRef() {
1280    return ref;
1281    }
1282}
1283
1284
Popular Tags