URL.java 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808
  1. /* URL.java -- Uniform Resource Locator Class
  2. Copyright (C) 1998, 1999, 2000, 2002 Free Software Foundation, Inc.
  3. This file is part of GNU Classpath.
  4. GNU Classpath is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2, or (at your option)
  7. any later version.
  8. GNU Classpath is distributed in the hope that it will be useful, but
  9. WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with GNU Classpath; see the file COPYING. If not, write to the
  14. Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
  15. 02111-1307 USA.
  16. Linking this library statically or dynamically with other modules is
  17. making a combined work based on this library. Thus, the terms and
  18. conditions of the GNU General Public License cover the whole
  19. combination.
  20. As a special exception, the copyright holders of this library give you
  21. permission to link this library with independent modules to produce an
  22. executable, regardless of the license terms of these independent
  23. modules, and to copy and distribute the resulting executable under
  24. terms of your choice, provided that you also meet, for each linked
  25. independent module, the terms and conditions of the license of that
  26. module. An independent module is a module which is not derived from
  27. or based on this library. If you modify this library, you may extend
  28. this exception to your version of the library, but you are not
  29. obligated to do so. If you do not wish to do so, delete this
  30. exception statement from your version. */
  31. package java.net;
  32. import java.io.InputStream;
  33. import java.io.IOException;
  34. import java.io.Serializable;
  35. import java.io.ObjectInputStream;
  36. import java.io.ObjectOutputStream;
  37. import java.util.Hashtable;
  38. import java.util.StringTokenizer;
  39. /*
  40. * Written using on-line Java Platform 1.2 API Specification, as well
  41. * as "The Java Class Libraries", 2nd edition (Addison-Wesley, 1998).
  42. * Status: Believed complete and correct.
  43. */
  44. /**
  45. * This final class represents an Internet Uniform Resource Locator (URL).
  46. * For details on the syntax of URL's and what they can be used for,
  47. * refer to RFC 1738, available from <a
  48. * href="http://ds.internic.net/rfcs/rfc1738.txt">http://ds.internic.net/rfcs/rfc1738.txt</a>
  49. * <p>
  50. * There are a great many protocols supported by URL's such as "http",
  51. * "ftp", and "file". This object can handle any arbitrary URL for which
  52. * a URLStreamHandler object can be written. Default protocol handlers
  53. * are provided for the "http" and "ftp" protocols. Additional protocols
  54. * handler implementations may be provided in the future. In any case,
  55. * an application or applet can install its own protocol handlers that
  56. * can be "chained" with other protocol hanlders in the system to extend
  57. * the base functionality provided with this class. (Note, however, that
  58. * unsigned applets cannot access properties by default or install their
  59. * own protocol handlers).
  60. * <p>
  61. * This chaining is done via the system property java.protocol.handler.pkgs
  62. * If this property is set, it is assumed to be a "|" separated list of
  63. * package names in which to attempt locating protocol handlers. The
  64. * protocol handler is searched for by appending the string
  65. * ".<protocol>.Handler" to each packed in the list until a hander is found.
  66. * If a protocol handler is not found in this list of packages, or if the
  67. * property does not exist, then the default protocol handler of
  68. * "gnu.java.net.<protocol>.Handler" is tried. If this is
  69. * unsuccessful, a MalformedURLException is thrown.
  70. * <p>
  71. * All of the constructor methods of URL attempt to load a protocol
  72. * handler and so any needed protocol handlers must be installed when
  73. * the URL is constructed.
  74. * <p>
  75. * Here is an example of how URL searches for protocol handlers. Assume
  76. * the value of java.protocol.handler.pkgs is "com.foo|com.bar" and the
  77. * URL is "news://comp.lang.java.programmer". URL would looking the
  78. * following places for protocol handlers:
  79. * <p><pre>
  80. * com.foo.news.Handler
  81. * com.bar.news.Handler
  82. * gnu.java.net.news.Handler
  83. * </pre><p>
  84. * If the protocol handler is not found in any of those locations, a
  85. * MalformedURLException would be thrown.
  86. * <p>
  87. * Please note that a protocol handler must be a subclass of
  88. * URLStreamHandler.
  89. *
  90. * @author Aaron M. Renn (arenn@urbanophile.com)
  91. * @author Warren Levy <warrenl@cygnus.com>
  92. *
  93. * @see URLStreamHandler
  94. */
  95. public final class URL implements Serializable
  96. {
  97. /**
  98. * The name of the protocol for this URL.
  99. * The protocol is always stored in lower case.
  100. */
  101. private String protocol;
  102. /**
  103. * The "authority" portion of the URL.
  104. */
  105. private String authority;
  106. /**
  107. * The hostname or IP address of this protocol.
  108. * This includes a possible user. For example <code>joe@some.host.net</code>.
  109. */
  110. private String host;
  111. /**
  112. * The port number of this protocol or -1 if the port number used is
  113. * the default for this protocol.
  114. */
  115. private int port = -1; // Initialize for constructor using context.
  116. /**
  117. * The "file" portion of the URL. It is defined as <code>path[?query]</code>.
  118. */
  119. private String file;
  120. /**
  121. * The anchor portion of the URL.
  122. */
  123. private String ref;
  124. /**
  125. * This is the hashCode for this URL
  126. */
  127. private int hashCode = 0;
  128. /**
  129. * The protocol handler in use for this URL
  130. */
  131. transient private URLStreamHandler handler;
  132. /**
  133. * This a table where we cache protocol handlers to avoid the overhead
  134. * of looking them up each time.
  135. */
  136. private static Hashtable handlers = new Hashtable();
  137. /**
  138. * If an application installs its own protocol handler factory, this is
  139. * where we keep track of it.
  140. */
  141. private static URLStreamHandlerFactory factory;
  142. private static final long serialVersionUID = -7627629688361524110L;
  143. /**
  144. * Constructs a URL and loads a protocol handler for the values passed as
  145. * arguments.
  146. *
  147. * @param protocol The protocol for this URL ("http", "ftp", etc)
  148. * @param host The hostname or IP address to connect to
  149. * @param port The port number to use, or -1 to use the protocol's
  150. * default port
  151. * @param file The "file" portion of the URL.
  152. *
  153. * @exception MalformedURLException If a protocol handler cannot be loaded or
  154. * a parse error occurs.
  155. */
  156. public URL(String protocol, String host, int port, String file)
  157. throws MalformedURLException
  158. {
  159. this(protocol, host, port, file, null);
  160. }
  161. /**
  162. * Constructs a URL and loads a protocol handler for the values passed in
  163. * as arugments. Uses the default port for the protocol.
  164. *
  165. * @param protocol The protocol for this URL ("http", "ftp", etc)
  166. * @param host The hostname or IP address for this URL
  167. * @param file The "file" portion of this URL.
  168. *
  169. * @exception MalformedURLException If a protocol handler cannot be loaded or
  170. * a parse error occurs.
  171. */
  172. public URL(String protocol, String host, String file)
  173. throws MalformedURLException
  174. {
  175. this(protocol, host, -1, file, null);
  176. }
  177. /**
  178. * This method initializes a new instance of <code>URL</code> with the
  179. * specified protocol, host, port, and file. Additionally, this method
  180. * allows the caller to specify a protocol handler to use instead of
  181. * the default. If this handler is specified, the caller must have
  182. * the "specifyStreamHandler" permission (see <code>NetPermission</code>)
  183. * or a <code>SecurityException</code> will be thrown.
  184. *
  185. * @param protocol The protocol for this URL ("http", "ftp", etc)
  186. * @param host The hostname or IP address to connect to
  187. * @param port The port number to use, or -1 to use the protocol's default
  188. * port
  189. * @param file The "file" portion of the URL.
  190. * @param handler The protocol handler to use with this URL.
  191. *
  192. * @exception MalformedURLException If no protocol handler can be loaded
  193. * for the specified protocol.
  194. * @exception SecurityException If the <code>SecurityManager</code> exists
  195. * and does not allow the caller to specify its own protocol handler.
  196. *
  197. * @since 1.2
  198. */
  199. public URL(String protocol, String host, int port, String file,
  200. URLStreamHandler handler) throws MalformedURLException
  201. {
  202. if (protocol == null)
  203. throw new MalformedURLException("null protocol");
  204. this.protocol = protocol.toLowerCase();
  205. if (handler != null)
  206. {
  207. SecurityManager s = System.getSecurityManager();
  208. if (s != null)
  209. s.checkPermission (new NetPermission ("specifyStreamHandler"));
  210. this.handler = handler;
  211. }
  212. else
  213. this.handler = getURLStreamHandler(protocol);
  214. if (this.handler == null)
  215. throw new MalformedURLException (
  216. "Protocol handler not found: " + protocol);
  217. this.host = host;
  218. this.port = port;
  219. this.authority = null;
  220. int hashAt = file.indexOf('#');
  221. if (hashAt < 0)
  222. {
  223. this.file = file;
  224. this.ref = null;
  225. }
  226. else
  227. {
  228. this.file = file.substring(0, hashAt);
  229. this.ref = file.substring(hashAt + 1);
  230. }
  231. hashCode = hashCode(); // Used for serialization.
  232. }
  233. /**
  234. * Initializes a URL from a complete string specification such as
  235. * "http://www.urbanophile.com/arenn/". First the protocol name is parsed
  236. * out of the string. Then a handler is located for that protocol and
  237. * the parseURL() method of that protocol handler is used to parse the
  238. * remaining fields.
  239. *
  240. * @param spec The complete String representation of a URL
  241. *
  242. * @exception MalformedURLException If a protocol handler cannot be found
  243. * or the URL cannot be parsed
  244. */
  245. public URL(String spec) throws MalformedURLException
  246. {
  247. this((URL) null, spec, (URLStreamHandler) null);
  248. }
  249. /*
  250. * This method parses a String representation of a URL within the
  251. * context of an existing URL. Principally this means that any
  252. * fields not present the URL are inheritied from the context URL.
  253. * This allows relative URL's to be easily constructed. If the
  254. * context argument is null, then a complete URL must be specified
  255. * in the URL string. If the protocol parsed out of the URL is
  256. * different from the context URL's protocol, then then URL String
  257. * is also expected to be a complete URL.
  258. *
  259. * @param context The context on which to parse the specification
  260. * @param spec The string to parse an URL
  261. *
  262. * @exception MalformedURLException If a protocol handler cannot be found
  263. * for the URL cannot be parsed
  264. */
  265. public URL(URL context, String spec) throws MalformedURLException
  266. {
  267. this(context, spec, (URLStreamHandler) null);
  268. }
  269. /**
  270. * Creates an URL from given arguments
  271. * This method parses a String representation of a URL within the
  272. * context of an existing URL. Principally this means that any fields
  273. * not present the URL are inheritied from the context URL. This allows
  274. * relative URL's to be easily constructed. If the context argument is
  275. * null, then a complete URL must be specified in the URL string.
  276. * If the protocol parsed out of the URL is different
  277. * from the context URL's protocol, then then URL String is also
  278. * expected to be a complete URL.
  279. * <p>
  280. * Additionally, this method allows the caller to specify a protocol handler
  281. * to use instead of the default. If this handler is specified, the caller
  282. * must have the "specifyStreamHandler" permission
  283. * (see <code>NetPermission</code>) or a <code>SecurityException</code>
  284. * will be thrown.
  285. *
  286. * @param context The context in which to parse the specification
  287. * @param spec The string to parse as an URL
  288. * @param handler The stream handler for the URL
  289. *
  290. * @exception MalformedURLException If a protocol handler cannot be found
  291. * or the URL cannot be parsed
  292. * @exception SecurityException If the <code>SecurityManager</code> exists
  293. * and does not allow the caller to specify its own protocol handler.
  294. *
  295. * @since 1.2
  296. */
  297. public URL(URL context, String spec, URLStreamHandler handler)
  298. throws MalformedURLException
  299. {
  300. /* A protocol is defined by the doc as the substring before a ':'
  301. * as long as the ':' occurs before any '/'.
  302. *
  303. * If context is null, then spec must be an absolute URL.
  304. *
  305. * The relative URL need not specify all the components of a URL.
  306. * If the protocol, host name, or port number is missing, the value
  307. * is inherited from the context. A bare file component is appended
  308. * to the context's file. The optional anchor is not inherited.
  309. */
  310. // If this is an absolute URL, then ignore context completely.
  311. // An absolute URL must have chars prior to "://" but cannot have a colon
  312. // right after the "://". The second colon is for an optional port value
  313. // and implies that the host from the context is used if available.
  314. int colon;
  315. if ((colon = spec.indexOf("://", 1)) > 0 &&
  316. ! spec.regionMatches(colon, "://:", 0, 4))
  317. context = null;
  318. int slash;
  319. if ((colon = spec.indexOf(':')) > 0 &&
  320. (colon < (slash = spec.indexOf('/')) || slash < 0))
  321. {
  322. // Protocol specified in spec string.
  323. protocol = spec.substring(0, colon).toLowerCase();
  324. if (context != null && context.protocol.equals(protocol))
  325. {
  326. // The 1.2 doc specifically says these are copied to the new URL.
  327. host = context.host;
  328. port = context.port;
  329. file = context.file;
  330. authority = context.authority;
  331. }
  332. }
  333. else if (context != null)
  334. {
  335. // Protocol NOT specified in spec string.
  336. // Use context fields (except ref) as a foundation for relative URLs.
  337. colon = -1;
  338. protocol = context.protocol;
  339. host = context.host;
  340. port = context.port;
  341. file = context.file;
  342. authority = context.authority;
  343. }
  344. else // Protocol NOT specified in spec. and no context available.
  345. throw new
  346. MalformedURLException("Absolute URL required with null context");
  347. if (handler != null)
  348. {
  349. SecurityManager s = System.getSecurityManager ();
  350. if (s != null)
  351. s.checkPermission (new NetPermission ("specifyStreamHandler"));
  352. this.handler = handler;
  353. }
  354. else
  355. this.handler = getURLStreamHandler(protocol);
  356. if (this.handler == null)
  357. throw new MalformedURLException("Protocol handler not found: "
  358. + protocol);
  359. // JDK 1.2 doc for parseURL specifically states that any '#' ref
  360. // is to be excluded by passing the 'limit' as the indexOf the '#'
  361. // if one exists, otherwise pass the end of the string.
  362. int hashAt = spec.indexOf('#', colon + 1);
  363. this.handler.parseURL(this, spec, colon + 1,
  364. hashAt < 0 ? spec.length() : hashAt);
  365. if (hashAt >= 0)
  366. ref = spec.substring(hashAt + 1);
  367. hashCode = hashCode(); // Used for serialization.
  368. }
  369. /**
  370. * Test another URL for equality with this one. This will be true only if
  371. * the argument is non-null and all of the fields in the URL's match
  372. * exactly (ie, protocol, host, port, file, and ref). Overrides
  373. * Object.equals(), implemented by calling the equals method of the handler.
  374. *
  375. * @param url The URL to compare with
  376. *
  377. * @return true if the URL is equal, false otherwise
  378. */
  379. public boolean equals(Object obj)
  380. {
  381. if (obj == null || ! (obj instanceof URL))
  382. return false;
  383. URL uObj = (URL) obj;
  384. return handler.equals (this, uObj);
  385. }
  386. /**
  387. * Returns the contents of this URL as an object by first opening a
  388. * connection, then calling the getContent() method against the connection
  389. *
  390. * @return A content object for this URL
  391. * @exception IOException If opening the connection or getting the
  392. * content fails.
  393. *
  394. * @since 1.3
  395. */
  396. public final Object getContent() throws IOException
  397. {
  398. return openConnection().getContent();
  399. }
  400. /**
  401. * Gets the contents of this URL
  402. *
  403. * @exception IOException If an error occurs
  404. */
  405. public final Object getContent (Class[] classes) throws IOException
  406. {
  407. // FIXME: implement this
  408. return getContent();
  409. }
  410. /**
  411. * Returns the file portion of the URL.
  412. * Defined as <code>path[?query]</code>.
  413. * Returns the empty string if there is no file portion.
  414. */
  415. public String getFile()
  416. {
  417. return file == null ? "" : file;
  418. }
  419. /**
  420. * Returns the path of the URL. This is the part of the file before any '?'
  421. * character.
  422. *
  423. * @since 1.3
  424. */
  425. public String getPath()
  426. {
  427. int quest = file.indexOf('?');
  428. return quest < 0 ? file : file.substring(0, quest);
  429. }
  430. /**
  431. * Returns the authority of the URL
  432. *
  433. * @since 1.3
  434. */
  435. public String getAuthority()
  436. {
  437. return authority;
  438. }
  439. /**
  440. * Returns the host of the URL
  441. */
  442. public String getHost()
  443. {
  444. int at = (host == null) ? -1 : host.indexOf('@');
  445. return at < 0 ? host : host.substring(at + 1, host.length());
  446. }
  447. /**
  448. * Returns the port number of this URL or -1 if the default port number is
  449. * being used.
  450. *
  451. * @return The port number
  452. *
  453. * @see #getDefaultPort()
  454. */
  455. public int getPort()
  456. {
  457. return port;
  458. }
  459. /**
  460. * Returns the default port of the URL. If the StreamHandler for the URL
  461. * protocol does not define a default port it returns -1.
  462. */
  463. public int getDefaultPort()
  464. {
  465. return handler.getDefaultPort();
  466. }
  467. /**
  468. * Returns the protocol of the URL
  469. */
  470. public String getProtocol()
  471. {
  472. return protocol;
  473. }
  474. /**
  475. * Returns the ref (sometimes called the "# reference" or "anchor") portion
  476. * of the URL.
  477. *
  478. * @return The ref
  479. */
  480. public String getRef()
  481. {
  482. return ref;
  483. }
  484. /**
  485. * Returns the user information of the URL. This is the part of the host
  486. * name before the '@'.
  487. *
  488. * @return the user at a particular host or null when no user defined.
  489. */
  490. public String getUserInfo ()
  491. {
  492. int at = host.indexOf('@');
  493. return at < 0 ? null : host.substring(0, at);
  494. }
  495. /**
  496. * Returns the query of the URL. This is the part of the file before the
  497. * '?'.
  498. *
  499. * @ return the query part of the file, or null when there is no query part.
  500. */
  501. public String getQuery ()
  502. {
  503. int quest = file.indexOf('?');
  504. return quest < 0 ? null : file.substring(quest + 1, file.length());
  505. }
  506. /**
  507. * Returns a hashcode computed by the URLStreamHandler of this URL
  508. */
  509. public int hashCode()
  510. {
  511. if (hashCode != 0)
  512. return hashCode; // Use cached value if available.
  513. else
  514. return handler.hashCode (this);
  515. }
  516. /**
  517. * Returns a URLConnection object that represents a connection to the remote
  518. * object referred to by the URL. The URLConnection is created by calling the
  519. * openConnection() method of the protocol handler
  520. *
  521. * @return A URLConnection for this URL
  522. * @exception IOException If an error occurs
  523. */
  524. public URLConnection openConnection() throws IOException
  525. {
  526. return handler.openConnection(this);
  527. }
  528. /**
  529. * Opens a connection to this URL and returns an InputStream for reading
  530. * from that connection
  531. *
  532. * @exception IOException If an error occurs
  533. */
  534. public final InputStream openStream() throws IOException
  535. {
  536. return openConnection().getInputStream();
  537. }
  538. /**
  539. * Tests whether or not another URL refers to the same "file" as this one.
  540. * This will be true if and only if the passed object is not null, is a
  541. * URL, and matches all fields but the ref (ie, protocol, host, port,
  542. * and file);
  543. *
  544. * @param url The URL object to test with
  545. *
  546. * @return true if URL matches this URL's file, false otherwise
  547. */
  548. public boolean sameFile(URL other)
  549. {
  550. return handler.sameFile(this, other);
  551. }
  552. /**
  553. * Sets the specified fields of the URL. This is not a public method so
  554. * that only URLStreamHandlers can modify URL fields. This might be called
  555. * by the <code>parseURL()</code> method in that class. URLs are otherwise
  556. * constant.
  557. *
  558. * @param protocol The protocol name for this URL
  559. * @param host The hostname or IP address for this URL
  560. * @param port The port number of this URL
  561. * @param file The "file" portion of this URL.
  562. * @param ref The anchor portion of this URL.
  563. */
  564. protected void set(String protocol, String host, int port, String file,
  565. String ref)
  566. {
  567. // TBD: Theoretically, a poorly written StreamHandler could pass an
  568. // invalid protocol. It will cause the handler to be set to null
  569. // thus overriding a valid handler. Callers of this method should
  570. // be aware of this.
  571. this.handler = getURLStreamHandler(protocol);
  572. this.protocol = protocol.toLowerCase();
  573. this.authority = null;
  574. this.port = port;
  575. this.host = host;
  576. this.file = file;
  577. this.ref = ref;
  578. hashCode = hashCode(); // Used for serialization.
  579. }
  580. /**
  581. * Sets the specified fields of the URL. This is not a public method so
  582. * that only URLStreamHandlers can modify URL fields. URLs are otherwise
  583. * constant.
  584. *
  585. * @since 1.3
  586. */
  587. protected void set(String protocol, String host, int port,
  588. String authority, String userInfo,
  589. String path, String query, String ref)
  590. {
  591. // TBD: Theoretically, a poorly written StreamHandler could pass an
  592. // invalid protocol. It will cause the handler to be set to null
  593. // thus overriding a valid handler. Callers of this method should
  594. // be aware of this.
  595. this.handler = getURLStreamHandler(protocol);
  596. this.protocol = protocol.toLowerCase();
  597. if (userInfo == null)
  598. this.host = host;
  599. else
  600. this.host = userInfo + "@" + host;
  601. this.port = port;
  602. if (query == null)
  603. this.file = path;
  604. else
  605. this.file = path + "?" + query;
  606. this.ref = ref;
  607. hashCode = hashCode(); // Used for serialization.
  608. }
  609. /**
  610. * Sets the URLStreamHandlerFactory for this class. This factory is
  611. * responsible for returning the appropriate protocol handler for
  612. * a given URL.
  613. *
  614. * @param fac The URLStreamHandlerFactory class to use
  615. *
  616. * @exception Error If the factory is alread set.
  617. * @exception SecurityException If a security manager exists and its
  618. * checkSetFactory method doesn't allow the operation
  619. */
  620. public static synchronized void
  621. setURLStreamHandlerFactory(URLStreamHandlerFactory fac)
  622. {
  623. if (factory != null)
  624. throw new Error("URLStreamHandlerFactory already set");
  625. // Throw an exception if an extant security mgr precludes
  626. // setting the factory.
  627. SecurityManager s = System.getSecurityManager();
  628. if (s != null)
  629. s.checkSetFactory();
  630. factory = fac;
  631. }
  632. /**
  633. * Returns a String representing this URL. The String returned is
  634. * created by calling the protocol handler's toExternalForm() method.
  635. *
  636. * @return A string for this URL
  637. */
  638. public String toExternalForm()
  639. {
  640. // Identical to toString().
  641. return handler.toExternalForm(this);
  642. }
  643. /**
  644. * Returns a String representing this URL. Identical to toExternalForm().
  645. * The value returned is created by the protocol handler's
  646. * toExternalForm method. Overrides Object.toString()
  647. *
  648. * @return A string for this URL
  649. */
  650. public String toString()
  651. {
  652. // Identical to toExternalForm().
  653. return handler.toExternalForm(this);
  654. }
  655. private static synchronized URLStreamHandler
  656. getURLStreamHandler(String protocol)
  657. {
  658. URLStreamHandler handler;
  659. // See if a handler has been cached for this protocol.
  660. if ((handler = (URLStreamHandler) handlers.get(protocol)) != null)
  661. return handler;
  662. // If a non-default factory has been set, use it to find the protocol.
  663. if (factory != null)
  664. handler = factory.createURLStreamHandler(protocol);
  665. else if (protocol.equals ("core"))
  666. {
  667. handler = new gnu.gcj.protocol.core.Handler ();
  668. }
  669. else if (protocol.equals ("file"))
  670. {
  671. // This is an interesting case. It's tempting to think that we
  672. // could call Class.forName ("gnu.gcj.protocol.file.Handler") to
  673. // get the appropriate class. Unfortunately, if we do that the
  674. // program will never terminate, because getURLStreamHandler is
  675. // eventually called by Class.forName.
  676. //
  677. // Treating "file" as a special case is the minimum that will
  678. // fix this problem. If other protocols are required in a
  679. // statically linked application they will need to be handled in
  680. // the same way as "file".
  681. handler = new gnu.gcj.protocol.file.Handler ();
  682. }
  683. // Non-default factory may have returned null or a factory wasn't set.
  684. // Use the default search algorithm to find a handler for this protocol.
  685. if (handler == null)
  686. {
  687. // Get the list of packages to check and append our default handler
  688. // to it, along with the JDK specified default as a last resort.
  689. // Except in very unusual environments the JDK specified one shouldn't
  690. // ever be needed (or available).
  691. String propVal = System.getProperty("java.protocol.handler.pkgs");
  692. propVal = (propVal == null) ? "" : (propVal + "|");
  693. propVal = propVal + "gnu.gcj.protocol|sun.net.www.protocol";
  694. StringTokenizer pkgPrefix = new StringTokenizer(propVal, "|");
  695. do
  696. {
  697. String facName = pkgPrefix.nextToken() + "." + protocol +
  698. ".Handler";
  699. try
  700. {
  701. handler =
  702. (URLStreamHandler) Class.forName(facName).newInstance();
  703. }
  704. catch (Exception e)
  705. {
  706. // Can't instantiate; handler still null, go on to next element.
  707. }
  708. } while ((handler == null ||
  709. ! (handler instanceof URLStreamHandler)) &&
  710. pkgPrefix.hasMoreTokens());
  711. }
  712. // Update the hashtable with the new protocol handler.
  713. if (handler != null)
  714. if (handler instanceof URLStreamHandler)
  715. handlers.put(protocol, handler);
  716. else
  717. handler = null;
  718. return handler;
  719. }
  720. private void readObject(ObjectInputStream ois)
  721. throws IOException, ClassNotFoundException
  722. {
  723. ois.defaultReadObject();
  724. this.handler = getURLStreamHandler(protocol);
  725. if (this.handler == null)
  726. throw new IOException("Handler for protocol " + protocol + " not found");
  727. }
  728. private void writeObject(ObjectOutputStream oos) throws IOException
  729. {
  730. oos.defaultWriteObject();
  731. }
  732. }