1. /*
  2. * @(#)URL.java 1.94 00/02/02
  3. *
  4. * Copyright 1995-2000 Sun Microsystems, Inc. All Rights Reserved.
  5. *
  6. * This software is the proprietary information of Sun Microsystems, Inc.
  7. * Use is subject to license terms.
  8. *
  9. */
  10. package java.net;
  11. import java.io.IOException;
  12. import java.io.InputStream;
  13. import java.io.OutputStream;
  14. import java.util.Hashtable;
  15. import java.util.StringTokenizer;
  16. /**
  17. * Class <code>URL</code> represents a Uniform Resource
  18. * Locator, a pointer to a "resource" on the World
  19. * Wide Web. A resource can be something as simple as a file or a
  20. * directory, or it can be a reference to a more complicated object,
  21. * such as a query to a database or to a search engine. More
  22. * information on the types of URLs and their formats can be found at:
  23. * <blockquote><pre>
  24. * http://www.ncsa.uiuc.edu/demoweb/url-primer.html
  25. * </pre></blockquote>
  26. * <p>
  27. * In general, a URL can be broken into several parts. The previous
  28. * example of a URL indicates that the protocol to use is
  29. * <code>http</code> (HyperText Transfer Protocol) and that the
  30. * information resides on a host machine named
  31. * <code>www.ncsa.uiuc.edu</code>. The information on that host
  32. * machine is named <code>/demoweb/url-primer.html</code>. The exact
  33. * meaning of this name on the host machine is both protocol
  34. * dependent and host dependent. The information normally resides in
  35. * a file, but it could be generated on the fly. This component of
  36. * the URL is called the <i>path</i> component.
  37. * <p>
  38. * A URL can optionally specify a "port", which is the
  39. * port number to which the TCP connection is made on the remote host
  40. * machine. If the port is not specified, the default port for
  41. * the protocol is used instead. For example, the default port for
  42. * <code>http</code> is <code>80</code>. An alternative port could be
  43. * specified as:
  44. * <blockquote><pre>
  45. * http://www.ncsa.uiuc.edu:8080/demoweb/url-primer.html
  46. * </pre></blockquote>
  47. * <p>
  48. * A URL may have appended to it a "fragment", also known
  49. * as a "ref" or a "reference". The fragment is indicated by the sharp
  50. * sign character "#" followed by more characters. For example,
  51. * <blockquote><pre>
  52. * http://java.sun.com/index.html#chapter1
  53. * </pre></blockquote>
  54. * <p>
  55. * This fragment is not technically part of the URL. Rather, it
  56. * indicates that after the specified resource is retrieved, the
  57. * application is specifically interested in that part of the
  58. * document that has the tag <code>chapter1</code> attached to it. The
  59. * meaning of a tag is resource specific.
  60. * <p>
  61. * An application can also specify a "relative URL",
  62. * which contains only enough information to reach the resource
  63. * relative to another URL. Relative URLs are frequently used within
  64. * HTML pages. For example, if the contents of the URL:
  65. * <blockquote><pre>
  66. * http://java.sun.com/index.html
  67. * </pre></blockquote>
  68. * contained within it the relative URL:
  69. * <blockquote><pre>
  70. * FAQ.html
  71. * </pre></blockquote>
  72. * it would be a shorthand for:
  73. * <blockquote><pre>
  74. * http://java.sun.com/FAQ.html
  75. * </pre></blockquote>
  76. * <p>
  77. * The relative URL need not specify all the components of a URL. If
  78. * the protocol, host name, or port number is missing, the value is
  79. * inherited from the fully specified URL. The file component must be
  80. * specified. The optional fragment is not inherited.
  81. *
  82. * @author James Gosling
  83. * @version 1.94, 02/02/00
  84. * @since JDK1.0
  85. */
  86. public final class URL implements java.io.Serializable {
  87. static final long serialVersionUID = -7627629688361524110L;
  88. /**
  89. * The property which specifies the package prefix list to be scanned
  90. * for protocol handlers. The value of this property (if any) should
  91. * be a vertical bar delimited list of package names to search through
  92. * for a protocol handler to load. The policy of this class is that
  93. * all protocol handlers will be in a class called <protocolname>.Handler,
  94. * and each package in the list is examined in turn for a matching
  95. * handler. If none are found (or the property is not specified), the
  96. * default package prefix, sun.net.www.protocol, is used. The search
  97. * proceeds from the first package in the list to the last and stops
  98. * when a match is found.
  99. */
  100. private static final String protocolPathProp = "java.protocol.handler.pkgs";
  101. /**
  102. * The protocol to use (ftp, http, nntp, ... etc.) .
  103. */
  104. private String protocol;
  105. /**
  106. * The host name in which to connect to.
  107. */
  108. private String host;
  109. /**
  110. * The protocol port to connect to.
  111. */
  112. private int port = -1;
  113. /**
  114. * The specified file name on that host.
  115. */
  116. private String file;
  117. /**
  118. * The query part of this URL.
  119. */
  120. private transient String query;
  121. /**
  122. * The authority part of this URL.
  123. */
  124. private String authority;
  125. /**
  126. * The path part of this URL.
  127. */
  128. private transient String path;
  129. /**
  130. * The userinfo part of this URL.
  131. */
  132. private transient String userInfo;
  133. /**
  134. * # reference.
  135. */
  136. private String ref;
  137. /**
  138. * The host's IP address, used in equals and hashCode.
  139. * Computed on demand. An uninitialized or unknown hostAddress is null.
  140. */
  141. transient InetAddress hostAddress;
  142. /**
  143. * The URLStreamHandler for this URL.
  144. */
  145. transient URLStreamHandler handler;
  146. /* Our hash code. */
  147. private int hashCode = -1;
  148. /**
  149. * Creates a <code>URL</code> object from the specified
  150. * <code>protocol</code>, <code>host</code>, <code>port</code>
  151. * number, and <code>file</code>. Specifying a <code>port</code>
  152. * number of <code>-1</code> indicates that the URL should use
  153. * the default port for the protocol.
  154. * <p>
  155. * If this is the first URL object being created with the specified
  156. * protocol, a <i>stream protocol handler</i> object, an instance of
  157. * class <code>URLStreamHandler</code>, is created for that protocol:
  158. * <ol>
  159. * <li>If the application has previously set up an instance of
  160. * <code>URLStreamHandlerFactory</code> as the stream handler factory,
  161. * then the <code>createURLStreamHandler</code> method of that instance
  162. * is called with the protocol string as an argument to create the
  163. * stream protocol handler.
  164. * <li>If no <code>URLStreamHandlerFactory</code> has yet been set up,
  165. * or if the factory's <code>createURLStreamHandler</code> method
  166. * returns <code>null</code>, then the constructor finds the
  167. * value of the system property:
  168. * <blockquote><pre>
  169. * java.protocol.handler.pkgs
  170. * </pre></blockquote>
  171. * If the value of that system property is not <code>null</code>,
  172. * it is interpreted as a list of packages separated by a vertical
  173. * slash character '<code>|</code>'. The constructor tries to load
  174. * the class named:
  175. * <blockquote><pre>
  176. * <<i>package</i>>.<<i>protocol</i>>.Handler
  177. * </pre></blockquote>
  178. * where <<i>package</i>> is replaced by the name of the package
  179. * and <<i>protocol</i>> is replaced by the name of the protocol.
  180. * If this class does not exist, or if the class exists but it is not
  181. * a subclass of <code>URLStreamHandler</code>, then the next package
  182. * in the list is tried.
  183. * <li>If the previous step fails to find a protocol handler, then the
  184. * constructor tries to load the class named:
  185. * <blockquote><pre>
  186. * sun.net.www.protocol.<<i>protocol</i>>.Handler
  187. * </pre></blockquote>
  188. * If this class does not exist, or if the class exists but it is not a
  189. * subclass of <code>URLStreamHandler</code>, then a
  190. * <code>MalformedURLException</code> is thrown.
  191. * </ol>
  192. *
  193. * @param protocol the name of the protocol to use.
  194. * @param host the name of the host.
  195. * @param port the port number on the host.
  196. * @param file the file on the host
  197. * @exception MalformedURLException if an unknown protocol is specified.
  198. * @see java.lang.System#getProperty(java.lang.String)
  199. * @see java.net.URL#setURLStreamHandlerFactory(java.net.URLStreamHandlerFactory)
  200. * @see java.net.URLStreamHandler
  201. * @see java.net.URLStreamHandlerFactory#createURLStreamHandler(java.lang.String)
  202. */
  203. public URL(String protocol, String host, int port, String file)
  204. throws MalformedURLException
  205. {
  206. this(protocol, host, port, file, null);
  207. }
  208. /**
  209. * Creates a URL from the specified <code>protocol</code>
  210. * name, <code>host</code> name, and <code>file</code> name. The
  211. * default port for the specified protocol is used.
  212. * <p>
  213. * This method is equivalent to calling the four-argument
  214. * constructor with the arguments being <code>protocol</code>,
  215. * <code>host</code>, <code>-1</code>, and <code>file</code>.
  216. *
  217. * @param protocol the name of the protocol to use.
  218. * @param host the name of the host.
  219. * @param file the file on the host.
  220. * @exception MalformedURLException if an unknown protocol is specified.
  221. * @see java.net.URL#URL(java.lang.String, java.lang.String, int, java.lang.String)
  222. */
  223. public URL(String protocol, String host, String file) throws MalformedURLException {
  224. this(protocol, host, -1, file);
  225. }
  226. /**
  227. * Creates a <code>URL</code> object from the specified
  228. * <code>protocol</code>, <code>host</code>, <code>port</code>
  229. * number, <code>file</code>, and <code>handler</code>. Specifying
  230. * a <code>port</code> number of <code>-1</code> indicates that
  231. * the URL should use the default port for the protocol. Specifying
  232. * a <code>handler</code> of <code>null</code> indicates that the URL
  233. * should use a default stream handler for the protocol, as outlined
  234. * for:
  235. * java.net.URL#URL(java.lang.String, java.lang.String, int,
  236. * java.lang.String)
  237. *
  238. * <p>If the handler is not null and there is a security manager,
  239. * the security manager's <code>checkPermission</code>
  240. * method is called with a
  241. * <code>NetPermission("specifyStreamHandler")</code> permission.
  242. * This may result in a SecurityException.
  243. *
  244. * @param protocol the name of the protocol to use.
  245. * @param host the name of the host.
  246. * @param port the port number on the host.
  247. * @param file the file on the host
  248. * @param handler the stream handler for the URL.
  249. * @exception MalformedURLException if an unknown protocol is specified.
  250. * @exception SecurityException
  251. * if a security manager exists and its
  252. * <code>checkPermission</code> method doesn't allow
  253. * specifying a stream handler explicitly.
  254. * @see java.lang.System#getProperty(java.lang.String)
  255. * @see java.net.URL#setURLStreamHandlerFactory(java.net.URLStreamHandlerFactory)
  256. * @see java.net.URLStreamHandler
  257. * @see java.net.URLStreamHandlerFactory#createURLStreamHandler(java.lang.String)
  258. * @see SecurityManager#checkPermission
  259. * @see java.net.NetPermission
  260. */
  261. public URL(String protocol, String host, int port, String file,
  262. URLStreamHandler handler)
  263. throws MalformedURLException
  264. {
  265. if (handler != null) {
  266. SecurityManager sm = System.getSecurityManager();
  267. if (sm != null) {
  268. // check for permission to specify a handler
  269. checkSpecifyHandler(sm);
  270. }
  271. }
  272. this.protocol = protocol;
  273. this.host = host;
  274. int ind = file.indexOf('#');
  275. this.file = ind < 0 ? file: file.substring(0, ind);
  276. this.ref = ind < 0 ? null: file.substring(ind + 1);
  277. int q = file.lastIndexOf('?');
  278. if (q != -1) {
  279. query = file.substring(q+1);
  280. path = file.substring(0, q);
  281. } else
  282. path = file;
  283. // Note: we don't do validation of the URL here. Too risky to change
  284. // right now, but worth considering for future reference. -br
  285. if (handler == null &&
  286. (handler = getURLStreamHandler(protocol)) == null) {
  287. throw new MalformedURLException("unknown protocol: " + protocol);
  288. }
  289. this.handler = handler;
  290. this.port = port;
  291. if (host != null && host.length() > 0) {
  292. authority = (port == -1) ? host : host + ":" + port;
  293. }
  294. }
  295. /**
  296. * Creates a <code>URL</code> object from the <code>String</code>
  297. * representation.
  298. * <p>
  299. * This constructor is equivalent to a call to the two-argument
  300. * constructor with a <code>null</code> first argument.
  301. *
  302. * @param spec the <code>String</code> to parse as a URL.
  303. * @exception MalformedURLException If the string specifies an
  304. * unknown protocol.
  305. * @see java.net.URL#URL(java.net.URL, java.lang.String)
  306. */
  307. public URL(String spec) throws MalformedURLException {
  308. this(null, spec);
  309. }
  310. /**
  311. * Creates a URL by parsing the given spec within a specified context.
  312. *
  313. * The new URL is created from the given context URL and the spec
  314. * argument as described in RFC2396 "Uniform Resource Identifiers : Generic
  315. * Syntax" :
  316. * <blockquote><pre>
  317. * <scheme>://<authority><path>?<query>#<fragment>
  318. * </pre></blockquote>
  319. * The reference is parsed into the scheme, authority, path, query and
  320. * fragment parts. If the path component is empty and the scheme,
  321. * authority, and query components are undefined, then the new URL is a
  322. * reference to the current document. Otherwise the any fragment and query
  323. * parts present in the spec are used in the new URL.
  324. *
  325. * If the scheme component is defined in the given spec and does not match
  326. * the scheme of the context, then the new URL is created as an absolute
  327. * URL based on the spec alone. Otherwise the scheme component is inherited
  328. * from the context URL.
  329. *
  330. * If the authority component is present in the spec then the spec is
  331. * treated as absolute and the spec authority and path will replace the
  332. * context authority and path. If the authority component is absent in the
  333. * spec then the authority of the new URL will be inherited from the
  334. * context.
  335. *
  336. * If the spec's path component begins with a slash character "/" then the
  337. * path is treated as absolute and the spec path replaces the context path.
  338. * Otherwise the path is treated as a relative path and is appended to the
  339. * context path. The path is canonicalized through the removal of directory
  340. * changes made by occurences of ".." and ".".
  341. *
  342. * For a more detailed description of URL parsing, refer to RFC2396.
  343. *
  344. * @param context the context in which to parse the specification.
  345. * @param spec the <code>String</code> to parse as a URL.
  346. * @exception MalformedURLException if no protocol is specified, or an
  347. * unknown protocol is found.
  348. * @see java.net.URL#URL(java.lang.String, java.lang.String, int, java.lang.String)
  349. * @see java.net.URLStreamHandler
  350. * @see java.net.URLStreamHandler#parseURL(java.net.URL, java.lang.String, int, int)
  351. */
  352. public URL(URL context, String spec) throws MalformedURLException {
  353. this(context, spec, null);
  354. }
  355. /**
  356. * Creates a URL by parsing the given spec with the specified handler
  357. * within a specified context. If the handler is null, the parsing
  358. * occurs as with the two argument constructor.
  359. *
  360. * @param context the context in which to parse the specification.
  361. * @param spec the <code>String</code> to parse as a URL.
  362. * @param handler the stream handler for the URL.
  363. * @exception MalformedURLException if no protocol is specified, or an
  364. * unknown protocol is found.
  365. * @exception SecurityException
  366. * if a security manager exists and its
  367. * <code>checkPermission</code> method doesn't allow
  368. * specifying a stream handler.
  369. * @see java.net.URL#URL(java.lang.String, java.lang.String, int, java.lang.String)
  370. * @see java.net.URLStreamHandler
  371. * @see java.net.URLStreamHandler#parseURL(java.net.URL, java.lang.String, int, int)
  372. */
  373. public URL(URL context, String spec, URLStreamHandler handler)
  374. throws MalformedURLException
  375. {
  376. String original = spec;
  377. int i, limit, c;
  378. int start = 0;
  379. String newProtocol = null;
  380. boolean aRef=false;
  381. // Check for permission to specify a handler
  382. if (handler != null) {
  383. SecurityManager sm = System.getSecurityManager();
  384. if (sm != null) {
  385. checkSpecifyHandler(sm);
  386. }
  387. }
  388. try {
  389. limit = spec.length();
  390. while ((limit > 0) && (spec.charAt(limit - 1) <= ' ')) {
  391. limit--; //eliminate trailing whitespace
  392. }
  393. while ((start < limit) && (spec.charAt(start) <= ' ')) {
  394. start++; // eliminate leading whitespace
  395. }
  396. if (spec.regionMatches(true, start, "url:", 0, 4)) {
  397. start += 4;
  398. }
  399. if (start < spec.length() && spec.charAt(start) == '#') {
  400. /* we're assuming this is a ref relative to the context URL.
  401. * This means protocols cannot start w/ '#', but we must parse
  402. * ref URL's like: "hello:there" w/ a ':' in them.
  403. */
  404. aRef=true;
  405. }
  406. for (i = start ; !aRef && (i < limit) &&
  407. ((c = spec.charAt(i)) != '/') ; i++) {
  408. if (c == ':') {
  409. String s = spec.substring(start, i).toLowerCase();
  410. if (isValidProtocol(s)) {
  411. newProtocol = s;
  412. start = i + 1;
  413. }
  414. break;
  415. }
  416. }
  417. // Only use our context if the protocols match.
  418. protocol = newProtocol;
  419. if ((context != null) && ((newProtocol == null) ||
  420. newProtocol.equalsIgnoreCase(context.protocol))) {
  421. // inherit the protocol handler from the context
  422. // if not specified to the contructor
  423. if (handler == null) {
  424. handler = context.handler;
  425. }
  426. // If the context is a hierarchical URL scheme and the spec
  427. // contains a matching scheme then maintain backwards
  428. // compatibility and treat it as if the spec didn't contain
  429. // the scheme; see 5.2.3 of RFC2396
  430. if (context.path != null && context.path.startsWith("/"))
  431. newProtocol = null;
  432. if (newProtocol == null) {
  433. protocol = context.protocol;
  434. authority = context.authority;
  435. userInfo = context.userInfo;
  436. host = context.host;
  437. port = context.port;
  438. file = context.file;
  439. }
  440. }
  441. if (protocol == null) {
  442. throw new MalformedURLException("no protocol: "+original);
  443. }
  444. // Get the protocol handler if not specified or the protocol
  445. // of the context could not be used
  446. if (handler == null &&
  447. (handler = getURLStreamHandler(protocol)) == null) {
  448. throw new MalformedURLException("unknown protocol: "+protocol);
  449. }
  450. this.handler = handler;
  451. i = spec.indexOf('#', start);
  452. if (i >= 0) {
  453. ref = spec.substring(i + 1, limit);
  454. limit = i;
  455. }
  456. handler.parseURL(this, spec, start, limit);
  457. } catch(MalformedURLException e) {
  458. throw e;
  459. } catch(Exception e) {
  460. throw new MalformedURLException(e.toString());
  461. }
  462. }
  463. /*
  464. * Returns true if specified string is a valid protocol name.
  465. */
  466. private boolean isValidProtocol(String protocol) {
  467. int len = protocol.length();
  468. if (len < 1)
  469. return false;
  470. char c = protocol.charAt(0);
  471. if (!Character.isLetter(c))
  472. return false;
  473. for (int i = 1; i < len; i++) {
  474. c = protocol.charAt(i);
  475. if (!Character.isLetterOrDigit(c) && c != '.' && c != '+' &&
  476. c != '-') {
  477. return false;
  478. }
  479. }
  480. return true;
  481. }
  482. /*
  483. * Checks for permission to specify a stream handler.
  484. */
  485. private void checkSpecifyHandler(SecurityManager sm) {
  486. if (specifyHandlerPerm == null) {
  487. specifyHandlerPerm = new NetPermission("specifyStreamHandler");
  488. }
  489. sm.checkPermission(specifyHandlerPerm);
  490. }
  491. private static NetPermission specifyHandlerPerm;
  492. /**
  493. * Sets the fields of the URL. This is not a public method so that
  494. * only URLStreamHandlers can modify URL fields. URLs are
  495. * otherwise constant.
  496. *
  497. * @param protocol the name of the protocol to use
  498. * @param host the name of the host
  499. @param port the port number on the host
  500. * @param file the file on the host
  501. * @param ref the internal reference in the URL
  502. */
  503. protected void set(String protocol, String host,
  504. int port, String file, String ref) {
  505. synchronized (this) {
  506. this.protocol = protocol;
  507. this.host = host;
  508. authority = port == -1 ? host : host + ":" + port;
  509. this.port = port;
  510. this.file = file;
  511. this.ref = ref;
  512. /* This is very important. We must recompute this after the
  513. * URL has been changed. */
  514. hashCode = -1;
  515. hostAddress = null;
  516. int q = file.lastIndexOf('?');
  517. if (q != -1) {
  518. query = file.substring(q+1);
  519. path = file.substring(0, q);
  520. } else
  521. path = file;
  522. }
  523. }
  524. /**
  525. * Sets the specified 8 fields of the URL. This is not a public method so
  526. * that only URLStreamHandlers can modify URL fields. URLs are otherwise
  527. * constant.
  528. *
  529. * @param protocol the name of the protocol to use
  530. * @param host the name of the host
  531. * @param port the port number on the host
  532. * @param authority the authority part for the url
  533. * @param userInfo the username and password
  534. * @param path the file on the host
  535. * @param ref the internal reference in the URL
  536. * @param query the query part of this URL
  537. */
  538. protected void set(String protocol, String host, int port,
  539. String authority, String userInfo, String path,
  540. String query, String ref) {
  541. synchronized (this) {
  542. this.protocol = protocol;
  543. this.host = host;
  544. this.port = port;
  545. this.file = query == null ? path : path + "?" + query;
  546. this.userInfo = userInfo;
  547. this.path = path;
  548. this.ref = ref;
  549. /* This is very important. We must recompute this after the
  550. * URL has been changed. */
  551. hashCode = -1;
  552. hostAddress = null;
  553. this.query = query;
  554. this.authority = authority;
  555. }
  556. }
  557. /**
  558. * Returns the query part of this <code>URL</code>.
  559. *
  560. * @return the query part of this <code>URL</code>.
  561. */
  562. public String getQuery() {
  563. return query;
  564. }
  565. /**
  566. * Returns the path part of this <code>URL</code>.
  567. *
  568. * @return the path part of this <code>URL</code>.
  569. */
  570. public String getPath() {
  571. return path;
  572. }
  573. /**
  574. * Returns the userInfo part of this <code>URL</code>.
  575. *
  576. * @return the userInfo part of this <code>URL</code>.
  577. */
  578. public String getUserInfo() {
  579. return userInfo;
  580. }
  581. /**
  582. * Returns the authority part of this <code>URL</code>.
  583. *
  584. * @return the authority part of this <code>URL</code>.
  585. */
  586. public String getAuthority() {
  587. return authority;
  588. }
  589. /**
  590. * Returns the port number of this <code>URL</code>.
  591. * Returns -1 if the port is not set.
  592. *
  593. * @return the port number
  594. */
  595. public int getPort() {
  596. return port;
  597. }
  598. /**
  599. * Returns the protocol name of this <code>URL</code>.
  600. *
  601. * @return the protocol of this <code>URL</code>.
  602. */
  603. public String getProtocol() {
  604. return protocol;
  605. }
  606. /**
  607. * Returns the host name of this <code>URL</code>, if applicable.
  608. *
  609. * @return the host name of this <code>URL</code>.
  610. */
  611. public String getHost() {
  612. return host;
  613. }
  614. /**
  615. * Returns the file name of this <code>URL</code>.
  616. *
  617. * @return the file name of this <code>URL</code>.
  618. */
  619. public String getFile() {
  620. return file;
  621. }
  622. /**
  623. * Returns the anchor (also known as the "reference") of this
  624. * <code>URL</code>.
  625. *
  626. * @return the anchor (also known as the "reference") of this
  627. * <code>URL</code>.
  628. */
  629. public String getRef() {
  630. return ref;
  631. }
  632. /**
  633. * Compares two URLs. The result is <code>true</code> if and
  634. * only if the argument is not <code>null</code> and is a
  635. * <code>URL</code> object that represents the same
  636. * <code>URL</code> as this object. Two URL objects are equal if
  637. * they have the same protocol and reference the same host, the
  638. * same port number on the host, and the same file and anchor on
  639. * the host.
  640. *
  641. * @param obj the URL to compare against.
  642. * @return <code>true</code> if the objects are the same;
  643. * <code>false</code> otherwise.
  644. */
  645. public boolean equals(Object obj) {
  646. if (!(obj instanceof URL))
  647. return false;
  648. URL u2 = (URL)obj;
  649. return handler.equals(this, u2);
  650. }
  651. /**
  652. * Creates an integer suitable for hash table indexing.
  653. *
  654. * @return a hash code for this <code>URL</code>.
  655. */
  656. public synchronized int hashCode() {
  657. if (hashCode != -1)
  658. return hashCode;
  659. hashCode = handler.hashCode(this);
  660. return hashCode;
  661. }
  662. /**
  663. * Compares two URLs, excluding the "ref" fields.
  664. * Returns <code>true</code> if this <code>URL</code> and the
  665. * <code>other</code> argument both refer to the same resource.
  666. * The two <code>URL</code>s might not both contain the same anchor.
  667. *
  668. * @param other the <code>URL</code> to compare against.
  669. * @return <code>true</code> if they reference the same remote object;
  670. * <code>false</code> otherwise.
  671. */
  672. public boolean sameFile(URL other) {
  673. return handler.sameFile(this, other);
  674. }
  675. /**
  676. * Constructs a string representation of this <code>URL</code>. The
  677. * string is created by calling the <code>toExternalForm</code>
  678. * method of the stream protocol handler for this object.
  679. *
  680. * @return a string representation of this object.
  681. * @see java.net.URL#URL(java.lang.String, java.lang.String, int, java.lang.String)
  682. * @see java.net.URLStreamHandler#toExternalForm(java.net.URL)
  683. */
  684. public String toString() {
  685. return toExternalForm();
  686. }
  687. /**
  688. * Constructs a string representation of this <code>URL</code>. The
  689. * string is created by calling the <code>toExternalForm</code>
  690. * method of the stream protocol handler for this object.
  691. *
  692. * @return a string representation of this object.
  693. * @see java.net.URL#URL(java.lang.String, java.lang.String, int, java.lang.String)
  694. * @see java.net.URLStreamHandler#toExternalForm(java.net.URL)
  695. */
  696. public String toExternalForm() {
  697. return handler.toExternalForm(this);
  698. }
  699. /**
  700. * Returns a <code>URLConnection</code> object that represents a
  701. * connection to the remote object referred to by the <code>URL</code>.
  702. *
  703. * <p>A new connection is opened every time by calling the
  704. * <code>openConnection</code> method of the protocol handler for
  705. * this URL.
  706. *
  707. * <p>If for the URL's protocol (such as HTTP or JAR), there
  708. * exists a public, specialized URLConnection subclass belonging
  709. * to one of the following packages or one of their subpackages:
  710. * java.lang, java.io, java.util, java.net, the connection
  711. * returned will be of that subclass. For example, for HTTP an
  712. * HttpURLConnection will be returned, and for JAR a
  713. * JarURLConnection will be returned.
  714. *
  715. * @return a <code>URLConnection</code> to the URL.
  716. * @exception IOException if an I/O exception occurs.
  717. * @see java.net.URL#URL(java.lang.String, java.lang.String,
  718. * int, java.lang.String)
  719. * @see java.net.URLConnection
  720. * @see java.net.URLStreamHandler#openConnection(java.net.URL)
  721. */
  722. public URLConnection openConnection() throws java.io.IOException {
  723. return handler.openConnection(this);
  724. }
  725. /**
  726. * Opens a connection to this <code>URL</code> and returns an
  727. * <code>InputStream</code> for reading from that connection. This
  728. * method is a shorthand for:
  729. * <blockquote><pre>
  730. * openConnection().getInputStream()
  731. * </pre></blockquote>
  732. *
  733. * @return an input stream for reading from the URL connection.
  734. * @exception IOException if an I/O exception occurs.
  735. * @see java.net.URL#openConnection()
  736. * @see java.net.URLConnection#getInputStream()
  737. */
  738. public final InputStream openStream() throws java.io.IOException {
  739. return openConnection().getInputStream();
  740. }
  741. /**
  742. * Returns the contents of this URL. This method is a shorthand for:
  743. * <blockquote><pre>
  744. * openConnection().getContent()
  745. * </pre></blockquote>
  746. *
  747. * @return the contents of this URL.
  748. * @exception IOException if an I/O exception occurs.
  749. * @see java.net.URLConnection#getContent()
  750. */
  751. public final Object getContent() throws java.io.IOException {
  752. return openConnection().getContent();
  753. }
  754. /**
  755. * Returns the contents of this URL. This method is a shorthand for:
  756. * <blockquote><pre>
  757. * openConnection().getContent(Class[])
  758. * </pre></blockquote>
  759. *
  760. * @return the content object of this URL that is the first match of
  761. * the types specified in the classes array.
  762. * null if none of the requested types are supported.
  763. * @exception IOException if an I/O exception occurs.
  764. * @see java.net.URLConnection#getContent(Class[])
  765. */
  766. public final Object getContent(Class[] classes)
  767. throws java.io.IOException {
  768. return openConnection().getContent(classes);
  769. }
  770. /**
  771. * The URLStreamHandler factory.
  772. */
  773. static URLStreamHandlerFactory factory;
  774. /**
  775. * Sets an application's <code>URLStreamHandlerFactory</code>.
  776. * This method can be called at most once in a given Java Virtual
  777. * Machine.
  778. *
  779. *<p> The <code>URLStreamHandlerFactory</code> instance is used to
  780. *construct a stream protocol handler from a protocol name.
  781. *
  782. * <p> If there is a security manager, this method first calls
  783. * the security manager's <code>checkSetFactory</code> method
  784. * to ensure the operation is allowed.
  785. * This could result in a SecurityException.
  786. *
  787. * @param fac the desired factory.
  788. * @exception Error if the application has already set a factory.
  789. * @exception SecurityException if a security manager exists and its
  790. * <code>checkSetFactory</code> method doesn't allow the operation.
  791. * @see java.net.URL#URL(java.lang.String, java.lang.String,
  792. * int, java.lang.String)
  793. * @see java.net.URLStreamHandlerFactory
  794. * @see SecurityManager#checkSetFactory
  795. */
  796. public static void setURLStreamHandlerFactory(URLStreamHandlerFactory fac) {
  797. synchronized (streamHandlerLock) {
  798. if (factory != null) {
  799. throw new Error("factory already defined");
  800. }
  801. SecurityManager security = System.getSecurityManager();
  802. if (security != null) {
  803. security.checkSetFactory();
  804. }
  805. handlers.clear();
  806. factory = fac;
  807. }
  808. }
  809. /**
  810. * A table of protocol handlers.
  811. */
  812. static Hashtable handlers = new Hashtable();
  813. private static Object streamHandlerLock = new Object();
  814. /**
  815. * Returns the Stream Handler.
  816. * @param protocol the protocol to use
  817. */
  818. static URLStreamHandler getURLStreamHandler(String protocol) {
  819. URLStreamHandler handler = (URLStreamHandler)handlers.get(protocol);
  820. if (handler == null) {
  821. boolean checkedWithFactory = false;
  822. // Use the factory (if any)
  823. if (factory != null) {
  824. handler = factory.createURLStreamHandler(protocol);
  825. checkedWithFactory = true;
  826. }
  827. // Try java protocol handler
  828. if (handler == null) {
  829. String packagePrefixList = null;
  830. packagePrefixList
  831. = (String) java.security.AccessController.doPrivileged(
  832. new sun.security.action.GetPropertyAction(protocolPathProp,""));
  833. if (packagePrefixList != "") {
  834. packagePrefixList += "|";
  835. }
  836. // REMIND: decide whether to allow the "null" class prefix
  837. // or not.
  838. packagePrefixList += "sun.net.www.protocol";
  839. StringTokenizer packagePrefixIter =
  840. new StringTokenizer(packagePrefixList, "|");
  841. while (handler == null &&
  842. packagePrefixIter.hasMoreTokens()) {
  843. String packagePrefix =
  844. packagePrefixIter.nextToken().trim();
  845. try {
  846. String clsName = packagePrefix + "." + protocol +
  847. ".Handler";
  848. Class cls = null;
  849. try {
  850. cls = Class.forName(clsName);
  851. } catch (ClassNotFoundException e) {
  852. ClassLoader cl = ClassLoader.getSystemClassLoader();
  853. if (cl != null) {
  854. cls = cl.loadClass(clsName);
  855. }
  856. }
  857. if (cls != null) {
  858. handler =
  859. (URLStreamHandler)cls.newInstance();
  860. }
  861. } catch (Exception e) {
  862. // any number of exceptions can get thrown here
  863. }
  864. }
  865. }
  866. synchronized (streamHandlerLock) {
  867. URLStreamHandler handler2 = null;
  868. // Check again with hashtable just in case another
  869. // thread created a handler since we last checked
  870. handler2 = (URLStreamHandler)handlers.get(protocol);
  871. if (handler2 != null) {
  872. return handler2;
  873. }
  874. // Check with factory if another thread set a
  875. // factory since our last check
  876. if (!checkedWithFactory && factory != null) {
  877. handler2 = factory.createURLStreamHandler(protocol);
  878. }
  879. if (handler2 != null) {
  880. // The handler from the factory must be given more
  881. // importance. Discard the default handler that
  882. // this thread created.
  883. handler = handler2;
  884. }
  885. // Insert this handler into the hashtable
  886. if (handler != null) {
  887. handlers.put(protocol, handler);
  888. }
  889. }
  890. }
  891. return handler;
  892. }
  893. /**
  894. * WriteObject is called to save the state of the URL to an
  895. * ObjectOutputStream. The handler is not saved since it is
  896. * specific to this system.
  897. *
  898. * @serialData the default write object value. When read back in,
  899. * the reader must ensure that calling getURLStreamHandler with
  900. * the protocol variable returns a valid URLStreamHandler and
  901. * throw an IOException if it does not.
  902. */
  903. private synchronized void writeObject(java.io.ObjectOutputStream s)
  904. throws IOException
  905. {
  906. s.defaultWriteObject(); // write the fields
  907. }
  908. /**
  909. * readObject is called to restore the state of the URL from the
  910. * stream. It reads the components of the URL and finds the local
  911. * stream handler.
  912. */
  913. private synchronized void readObject(java.io.ObjectInputStream s)
  914. throws IOException, ClassNotFoundException
  915. {
  916. s.defaultReadObject(); // read the fields
  917. if ((handler = getURLStreamHandler(protocol)) == null) {
  918. throw new IOException("unknown protocol: " + protocol);
  919. }
  920. // Construct authority part
  921. if (authority == null &&
  922. ((host != null && host.length() > 0) || port != -1)) {
  923. if (host == null)
  924. host = "";
  925. authority = (port == -1) ? host : host + ":" + port;
  926. // Handle hosts with userInfo in them
  927. int at = host.lastIndexOf('@');
  928. if (at != -1) {
  929. userInfo = host.substring(0, at);
  930. host = host.substring(at+1);
  931. }
  932. } else if (authority != null) {
  933. // Construct user info part
  934. int ind = authority.indexOf('@');
  935. if (ind != -1)
  936. userInfo = authority.substring(0, ind);
  937. }
  938. // Construct path and query part
  939. String path = null;
  940. String query = null;
  941. if (file != null) {
  942. // Fix: only do this if hierarchical?
  943. int q = file.lastIndexOf('?');
  944. if (q != -1) {
  945. query = file.substring(q+1);
  946. path = file.substring(0, q);
  947. } else
  948. path = file;
  949. }
  950. }
  951. }