home *** CD-ROM | disk | FTP | other *** search
/ Java 1.2 How-To / JavaHowTo.iso / 3rdParty / jbuilder / unsupported / JDK1.2beta3 / SOURCE / SRC.ZIP / java / net / URL.java < prev    next >
Encoding:
Java Source  |  1998-03-20  |  26.4 KB  |  765 lines

  1. /*
  2.  * @(#)URL.java    1.58 98/03/18
  3.  *
  4.  * Copyright 1995-1998 by Sun Microsystems, Inc.,
  5.  * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A.
  6.  * All rights reserved.
  7.  *
  8.  * This software is the confidential and proprietary information
  9.  * of Sun Microsystems, Inc. ("Confidential Information").  You
  10.  * shall not disclose such Confidential Information and shall use
  11.  * it only in accordance with the terms of the license agreement
  12.  * you entered into with Sun.
  13.  */
  14.  
  15. package java.net;
  16.  
  17. import java.io.IOException;
  18. import java.io.InputStream;
  19. import java.io.OutputStream;
  20. import java.util.Hashtable;
  21. import java.util.StringTokenizer;
  22.  
  23. /**
  24.  * Class <code>URL</code> represents a Uniform Resource 
  25.  * Locator, a pointer to a "resource" on the World 
  26.  * Wide Web. A resource can be something as simple as a file or a 
  27.  * directory, or it can be a reference to a more complicated object, 
  28.  * such as a query to a database or to a search engine. More 
  29.  * information on the types of URLs and their formats can be found at:
  30.  * <blockquote><pre>
  31.  *     http://www.ncsa.uiuc.edu/demoweb/url-primer.html
  32.  * </pre></blockquote>
  33.  * <p>
  34.  * In general, a URL can be broken into several parts. The previous 
  35.  * example of a URL indicates that the protocol to use is 
  36.  * <code>http</code> (HyperText Transport Protocol) and that the 
  37.  * information resides on a host machine named 
  38.  * <code>www.ncsa.uiuc.edu</code>. The information on that host 
  39.  * machine is named <code>demoweb/url-primer.html</code>. The exact 
  40.  * meaning of this name on the host machine is both protocol 
  41.  * dependent and host dependent. The information normally resides in 
  42.  * a file, but it could be generated on the fly. This component of 
  43.  * the URL is called the <i>file</i> component, even though the 
  44.  * information is not necessarily in a file. 
  45.  * <p>
  46.  * A URL can optionally specify a "port", which is the 
  47.  * port number to which the TCP connection is made on the remote host 
  48.  * machine. If the port is not specified, the default port for 
  49.  * the protocol is used instead. For example, the default port for 
  50.  * <code>http</code> is <code>80</code>. An alternative port could be 
  51.  * specified as: 
  52.  * <blockquote><pre>
  53.  *     http://www.ncsa.uiuc.edu:8080/demoweb/url-primer.html
  54.  * </pre></blockquote>
  55.  * <p>
  56.  * A URL may have appended to it an "anchor", also known 
  57.  * as a "ref" or a "reference". The anchor is 
  58.  * indicated by the sharp sign character "#" followed by 
  59.  * more characters. For example, 
  60.  * <blockquote><pre>
  61.  *     http://java.sun.com/index.html#chapter1
  62.  * </pre></blockquote>
  63.  * <p>
  64.  * This anchor is not technically part of the URL. Rather, it 
  65.  * indicates that after the specified resource is retrieved, the 
  66.  * application is specifically interested in that part of the 
  67.  * document that has the tag <code>chapter1</code> attached to it. The 
  68.  * meaning of a tag is resource specific. 
  69.  * <p>
  70.  * An application can also specify a "relative URL", 
  71.  * which contains only enough information to reach the resource 
  72.  * relative to another URL. Relative URLs are frequently used within 
  73.  * HTML pages. For example, if the contents of the URL:
  74.  * <blockquote><pre>
  75.  *     http://java.sun.com/index.html
  76.  * </pre></blockquote>
  77.  * contained within it the relative URL:
  78.  * <blockquote><pre>
  79.  *     FAQ.html
  80.  * </pre></blockquote>
  81.  * it would be a shorthand for:
  82.  * <blockquote><pre>
  83.  *     http://java.sun.com/FAQ.html
  84.  * </pre></blockquote>
  85.  * <p>
  86.  * The relative URL need not specify all the components of a URL. If 
  87.  * the protocol, host name, or port number is missing, the value is 
  88.  * inherited from the fully specified URL. The file component must be 
  89.  * specified. The optional anchor is not inherited. 
  90.  *
  91.  * @author  James Gosling
  92.  * @version 1.58, 03/18/98
  93.  * @since   JDK1.0
  94.  */
  95. public final class URL implements java.io.Serializable, Comparable {
  96.  
  97.     static final long serialVersionUID = -7627629688361524110L;
  98.  
  99.     /**
  100.      * The property which specifies the package prefix list to be scanned
  101.      * for protocol handlers.  The value of this property (if any) should
  102.      * be a vertical bar delimited list of package names to search through
  103.      * for a protocol handler to load.  The policy of this class is that
  104.      * all protocol handlers will be in a class called <protocolname>.Handler,
  105.      * and each package in the list is examined in turn for a matching
  106.      * handler.  If none are found (or the property is not specified), the
  107.      * default package prefix, sun.net.www.protocol, is used.  The search
  108.      * proceeds from the first package in the last to the last and stops
  109.      * when a match is found.
  110.      */
  111.     private static final String protocolPathProp = "java.protocol.handler.pkgs";
  112.  
  113.     /** 
  114.      * The protocol to use (ftp, http, nntp, ... etc.) . 
  115.      */
  116.     private String protocol;
  117.  
  118.     /** 
  119.      * The host name in which to connect to. 
  120.      */
  121.     private String host;
  122.  
  123.     /** 
  124.      * The protocol port to connect to. 
  125.      */
  126.     private int port = -1;
  127.  
  128.     /** 
  129.      * The specified file name on that host. 
  130.      */
  131.     private String file;
  132.  
  133.     /** 
  134.      * # reference. 
  135.      */
  136.     private String ref;
  137.  
  138.     /**
  139.      * The URLStreamHandler for this URL.
  140.      */
  141.     transient URLStreamHandler handler;
  142.  
  143.     /* Our hash code */
  144.     private int hashCode = -1;
  145.  
  146.     /** 
  147.      * Creates a <code>URL</code> object from the specified 
  148.      * <code>protocol</code>, <code>host</code>, <code>port</code> 
  149.      * number, and <code>file</code>. Specifying a <code>port</code> 
  150.      * number of <code>-1</code> indicates that the URL should use 
  151.      * the default port for the protocol. 
  152.      * <p>
  153.      * If this is the first URL object being created with the specified 
  154.      * protocol, a <i>stream protocol handler</i> object, an instance of 
  155.      * class <code>URLStreamHandler</code>, is created for that protocol:
  156.      * <ol>
  157.      * <li>If the application has previously set up an instance of
  158.      *     <code>URLStreamHandlerFactory</code> as the stream handler factory,
  159.      *     then the <code>createURLStreamHandler</code> method of that instance
  160.      *     is called with the protocol string as an argument to create the
  161.      *     stream protocol handler.
  162.      * <li>If no <code>URLStreamHandlerFactory</code> has yet been set up,
  163.      *     or if the factory's <code>createURLStreamHandler</code> method
  164.      *     returns <code>null</code>, then the constructor finds the 
  165.      *     value of the system property:
  166.      *     <blockquote><pre>
  167.      *         java.protocol.handler.pkgs
  168.      *     </pre></blockquote>
  169.      *     If the value of that system property is not <code>null</code>,
  170.      *     it is interpreted as a list of packages separated by a vertical
  171.      *     slash character '<code>|</code>'. The constructor tries to load 
  172.      *     the class named:
  173.      *     <blockquote><pre>
  174.      *         <<i>package</i>>.<<i>protocol</i>>.Handler
  175.      *     </pre></blockquote>
  176.      *     where <<i>package</i>> is replaced by the name of the package
  177.      *     and <<i>protocol</i>> is replaced by the name of the protocol.
  178.      *     If this class does not exist, or if the class exists but it is not
  179.      *     a subclass of <code>URLStreamHandler</code>, then the next package
  180.      *     in the list is tried.
  181.      * <li>If the previous step fails to find a protocol handler, then the
  182.      *     constructor tries to load the class named:
  183.      *     <blockquote><pre>
  184.      *         sun.net.www.protocol.<<i>protocol</i>>.Handler
  185.      *     </pre></blockquote>
  186.      *     If this class does not exist, or if the class exists but it is not a
  187.      *     subclass of <code>URLStreamHandler</code>, then a
  188.      *     <code>MalformedURLException</code> is thrown.
  189.      * </ol>
  190.      *
  191.      * @param      protocol   the name of the protocol.
  192.      * @param      host       the name of the host.
  193.      * @param      port       the port number.
  194.      * @param      file       the host file.
  195.      * @exception  MalformedURLException  if an unknown protocol is specified.
  196.      * @see        java.lang.System#getProperty(java.lang.String)
  197.      * @see        java.net.URL#setURLStreamHandlerFactory(java.net.URLStreamHandlerFactory)
  198.      * @see        java.net.URLStreamHandler
  199.      * @see        java.net.URLStreamHandlerFactory#createURLStreamHandler(java.lang.String)
  200.      */
  201.     public URL(String protocol, String host, int port, String file)
  202.     throws MalformedURLException {
  203.     this.protocol = protocol;
  204.     this.host = host;
  205.     this.port = port;
  206.     int ind = file.indexOf('#');
  207.     this.file = ind < 0 ? file: file.substring(0, ind);
  208.     this.ref = ind < 0 ? null: file.substring(ind + 1);
  209.     if ((handler = getURLStreamHandler(protocol)) == null) {
  210.         throw new MalformedURLException("unknown protocol: " + protocol);
  211.     }
  212.     }
  213.  
  214.     /** 
  215.      * Creates an absolute URL from the specified <code>protocol</code> 
  216.      * name, <code>host</code> name, and <code>file</code> name. The 
  217.      * default port for the specified protocol is used. 
  218.      * <p>
  219.      * This method is equivalent to calling the four-argument 
  220.      * constructor with the arguments being <code>protocol</code>, 
  221.      * <code>host</code>, <code>-1</code>, and <code>file</code>. 
  222.      *
  223.      * @param      protocol   the protocol to use.
  224.      * @param      host       the host to connect to.
  225.      * @param      file       the file on that host.
  226.      * @exception  MalformedURLException  if an unknown protocol is specified.
  227.      * @see        java.net.URL#URL(java.lang.String, java.lang.String, int, java.lang.String)
  228.      */
  229.     public URL(String protocol, String host, String file) throws MalformedURLException {
  230.     this(protocol, host, -1, file);
  231.     }
  232.  
  233.     /**
  234.      * Creates a <code>URL</code> object from the <code>String</code> 
  235.      * representation. 
  236.      * <p>
  237.      * This constructor is equivalent to a call to the two-argument 
  238.      * constructor with a <code>null</code> first argument. 
  239.      *
  240.      * @param      spec   the <code>String</code> to parse as a URL.
  241.      * @exception  MalformedURLException  If the string specifies an
  242.      *               unknown protocol.
  243.      * @see        java.net.URL#URL(java.net.URL, java.lang.String)
  244.      */
  245.     public URL(String spec) throws MalformedURLException {
  246.     this(null, spec);
  247.     }
  248.  
  249.     /** 
  250.      * Creates a URL by parsing the specification <code>spec</code> 
  251.      * within a specified context. If the <code>context</code> argument 
  252.      * is not <code>null</code> and the <code>spec</code> argument is a 
  253.      * partial URL specification, then any of the strings missing 
  254.      * components are inherited from the <code>context</code> argument. 
  255.      * <p>
  256.      * The specification given by the <code>String</code> argument is 
  257.      * parsed to determine if it specifies a protocol. If the 
  258.      * <code>String</code> contains an ASCII colon '<code>:</code>'
  259.      * character before the first occurrence of an ASCII slash character 
  260.      * '<code>/</code>', then the characters before the colon comprise 
  261.      * the protocol. 
  262.      * <ul>
  263.      * <li>If the <code>spec</code> argument does not specify a protocol:
  264.      *     <ul>
  265.      *     <li>If the context argument is not <code>null</code>, then the
  266.      *         protocol is copied from the context argument.
  267.      *     <li>If the context argument is <code>null</code>, then a
  268.      *         <code>MalformedURLException</code> is thrown.
  269.      *     </ul>
  270.      * <li>If the <code>spec</code> argument does specify a protocol:
  271.      *     <ul>
  272.      *     <li>If the context argument is <code>null</code>, or specifies a
  273.      *         different protocol than the specification argument, the context
  274.      *         argument is ignored.
  275.      *     <li>If the context argument is not <code>null</code> and specifies
  276.      *         the same protocol as the specification, the <code>host</code>,
  277.      *         <code>port</code> number, and <code>file</code> are copied from
  278.      *         the context argument into the newly created <code>URL</code>.
  279.      *     </ul>
  280.      * </ul>
  281.      * <p>
  282.      * The constructor then searches for an appropriate stream protocol 
  283.      * handler of type <code>URLStreamHandler</code> as outlined for:
  284.      * <blockquote><pre>
  285.      *     java.net.URL#URL(java.lang.String, java.lang.String, int,
  286.      *                      java.lang.String)
  287.      * </pre></blockquote>
  288.      * The stream protocol handler's 
  289.      * <code>parseURL</code> method is called to parse the remaining 
  290.      * fields of the specification that override any defaults set by the 
  291.      * context argument. 
  292.  
  293.      * @param      context   the context in which to parse the specification.
  294.      * @param      spec      a <code>String</code> representation of a URL.
  295.      * @exception  MalformedURLException  if no protocol is specified, or an
  296.      *               unknown protocol is found.
  297.      * @see        java.net.URL#URL(java.lang.String, java.lang.String, int, java.lang.String)
  298.      * @see        java.net.URLStreamHandler
  299.      * @see        java.net.URLStreamHandler#parseURL(java.net.URL, java.lang.String, int, int)
  300.      */
  301.     public URL(URL context, String spec) throws MalformedURLException {
  302.     String original = spec;
  303.     int i, limit, c;
  304.     int start = 0;
  305.     String newProtocol = null;
  306.     boolean aRef=false;
  307.  
  308.     try {
  309.         limit = spec.length();
  310.         while ((limit > 0) && (spec.charAt(limit - 1) <= ' ')) {
  311.         limit--;    //eliminate trailing whitespace
  312.         }
  313.         while ((start < limit) && (spec.charAt(start) <= ' ')) {
  314.         start++;    // eliminate leading whitespace
  315.         }
  316.  
  317.         if (spec.regionMatches(true, start, "url:", 0, 4)) {
  318.         start += 4;
  319.         }
  320.         if (start < spec.length() && spec.charAt(start) == '#') {
  321.         /* we're assuming this is a ref relative to the context URL.
  322.          * This means protocols cannot start w/ '#', but we must parse
  323.          * ref URL's like: "hello:there" w/ a ':' in them.
  324.          */
  325.         aRef=true;
  326.         }
  327.         for (i = start ; !aRef && (i < limit) && 
  328.              ((c = spec.charAt(i)) != '/') ; i++) {
  329.         if (c == ':') {
  330.             newProtocol = spec.substring(start, i).toLowerCase();
  331.             start = i + 1;
  332.             break;
  333.         }
  334.         }
  335.         // Only use our context if the protocols match.
  336.         if ((context != null) && ((newProtocol == null) ||
  337.                     newProtocol.equals(context.protocol))) {
  338.         protocol = context.protocol;
  339.         host = context.host;
  340.         port = context.port;
  341.         file = context.file;
  342.         } else {
  343.         protocol = newProtocol;
  344.         }
  345.  
  346.         if (protocol == null) {
  347.         throw new MalformedURLException("no protocol: "+original);
  348.         }
  349.  
  350.         if ((handler = getURLStreamHandler(protocol)) == null) {
  351.         throw new MalformedURLException("unknown protocol: "+protocol);
  352.         }
  353.  
  354.         i = spec.indexOf('#', start);
  355.         if (i >= 0) {
  356.         ref = spec.substring(i + 1, limit);
  357.         limit = i;
  358.         }
  359.         handler.parseURL(this, spec, start, limit);
  360.  
  361.     } catch(MalformedURLException e) {
  362.         throw e;
  363.     } catch(Exception e) {
  364.         throw new MalformedURLException(original + ": " + e);
  365.     }
  366.     }
  367.  
  368.     /**
  369.      * Sets the fields of the URL. This is not a public method so that 
  370.      * only URLStreamHandlers can modify URL fields. URLs are 
  371.      * otherwise constant.
  372.      *
  373.      * REMIND: this method will be moved to URLStreamHandler
  374.      *
  375.      * @param protocol the protocol to use
  376.      * @param host the host name to connecto to
  377.      * @param port the protocol port to connect to
  378.      * @param file the specified file name on that host
  379.      * @param ref the reference
  380.      */
  381.     protected void set(String protocol, String host, 
  382.                int port, String file, String ref) {
  383.     this.protocol = protocol;
  384.     this.host = host;
  385.     this.port = port;
  386.     this.file = file;
  387.     this.ref = ref;
  388.     }
  389.  
  390.     /**
  391.      * Returns the port number of this <code>URL</code>.
  392.      * Returns -1 if the port is not set.
  393.      *
  394.      * @return  the port number
  395.      */
  396.     public int getPort() {
  397.     return port;
  398.     }
  399.  
  400.     /**
  401.      * Returns the protocol name this <code>URL</code>.
  402.      *
  403.      * @return  the protocol of this <code>URL</code>.
  404.      */
  405.     public String getProtocol() {
  406.     return protocol;
  407.     }
  408.  
  409.     /**
  410.      * Returns the host name of this <code>URL</code>, if applicable.
  411.      * For "<code>file</code>" protocol, this is an empty string.
  412.      *
  413.      * @return  the host name of this <code>URL</code>.
  414.      */
  415.     public String getHost() {
  416.     return host;
  417.     }
  418.  
  419.     /**
  420.      * Returns the file name of this <code>URL</code>.
  421.      *
  422.      * @return  the file name of this <code>URL</code>.
  423.      */
  424.     public String getFile() {
  425.     return file;
  426.     }
  427.  
  428.     /**
  429.      * Returns the anchor (also known as the "reference") of this
  430.      * <code>URL</code>.
  431.      *
  432.      * @return  the anchor (also known as the "reference") of this
  433.      *          <code>URL</code>.
  434.      */
  435.     public String getRef() {
  436.     return ref;
  437.     }
  438.  
  439.     /** 
  440.      * Compares two URLs.  The result is <code>true</code> if and
  441.      * only if the argument is not <code>null</code> and is a
  442.      * <code>URL</code> object that represents the same
  443.      * <code>URL</code> as this object. Two URL objects are equal if
  444.      * they have the same protocol and reference the same host, the
  445.      * same port number on the host, and the same file and anchor on
  446.      * the host.
  447.      *
  448.      * @param   obj   the URL to compare against.
  449.      * @return  <code>true</code> if the objects are the same;
  450.      *          <code>false</code> otherwise.
  451.      */
  452.     public boolean equals(Object obj) {
  453.     if (ref == null) {
  454.         return (obj instanceof URL) && sameFile((URL)obj);
  455.     } else {
  456.         return (obj instanceof URL) && 
  457.         sameFile((URL)obj) && 
  458.         ref.equals(((URL)obj).ref);
  459.     }
  460.     }
  461.  
  462.     /** 
  463.      * Creates an integer suitable for hash table indexing.
  464.      *
  465.      * @return  a hash code for this <code>URL</code>.
  466.      */
  467.     public int hashCode() {
  468.  
  469.     if (hashCode == -1) {
  470.         hashCode = getComparable().hashCode();
  471.     }
  472.     return hashCode;
  473.     }
  474.     
  475.     /** 
  476.      * Compares a URL to another URL. The comparison is done on a
  477.      * canonical string representation of the URL, which includes the
  478.      * URL's protocol, ref, host, port and file.
  479.      *
  480.      * @param url the url to compare this to.
  481.      * 
  482.      * @see #getRef
  483.      * @see java.lang.Comparable
  484.      * @see java.lang.String#compareTo 
  485.      *
  486.      * @since JDK1.2
  487.      */
  488.     public int compareTo(Object url) {
  489.     URL actualUrl = (URL)url;
  490.     String compareRep = getComparable();
  491.     String compareRep2 = actualUrl.getComparable();
  492.     return compareRep.compareTo(compareRep2);
  493.     }
  494.  
  495.     /* comparable form of the URL, for comparison and hashcode only */
  496.     private String comparable;
  497.  
  498.     private String getComparable() {
  499.     if (comparable == null) {
  500.         String ref = getRef();
  501.         String host = getHost().toLowerCase();
  502.         int port = getPort();
  503.         String file = getFile();
  504.  
  505.         comparable = 
  506.         protocol +        
  507.         ((host == null) ? "" : host) +
  508.         port +
  509.         ((file == null) ? "" : file) +
  510.         ((ref == null) ? "" : ref);
  511.     }
  512.     return comparable;
  513.     }
  514.  
  515.     /**
  516.      * Compares the host components of two URLs.
  517.      * @param h1 the URL of the first host to compare 
  518.      * @param h2 the URL of the second host to compare 
  519.      * @return    true if and only if they are equal, false otherwise.
  520.      * @exception UnknownHostException If an unknown host is found.
  521.      */
  522.     boolean hostsEqual(String h1, String h2) {
  523.     if (h1 == null || h2 == null) {
  524.         return (h1 == h2);
  525.     }
  526.     if (h1.equals(h2)) {
  527.         return true;
  528.     }
  529.     // Have to resolve addresses before comparing, otherwise
  530.     // names like tachyon and tachyon.eng would compare different
  531.     try {
  532.         InetAddress a1 = InetAddress.getByName(h1);
  533.         InetAddress a2 = InetAddress.getByName(h2);
  534.         return a1.equals(a2);
  535.     } catch(UnknownHostException e) {
  536.     } catch(SecurityException e) {
  537.     }
  538.     return false;
  539.     }
  540.  
  541.     /**
  542.      * Compares two URLs, excluding the "ref" fields.
  543.      * Returns <code>true</code> if this <code>URL</code> and the 
  544.      * <code>other</code> argument both refer to the same resource.
  545.      * The two <code>URL</code>s might not both contain the same anchor. 
  546.      *
  547.      * @param   other   the <code>URL</code> to compare against.
  548.      * @return  <code>true</code> if they reference the same remote object;
  549.      *          <code>false</code> otherwise.
  550.      */
  551.     public boolean sameFile(URL other) {
  552.     // AVH: should we not user getPort to compare ports?
  553.     return protocol.equals(other.protocol) &&
  554.            hostsEqual(host, other.host) &&
  555.            (port == other.port) &&
  556.            file.equals(other.file);
  557.     }
  558.  
  559.     /**
  560.      * Constructs a string representation of this <code>URL</code>. The 
  561.      * string is created by calling the <code>toExternalForm</code> 
  562.      * method of the stream protocol handler for this object. 
  563.      *
  564.      * @return  a string representation of this object.
  565.      * @see     java.net.URL#URL(java.lang.String, java.lang.String, int, java.lang.String)
  566.      * @see     java.net.URLStreamHandler#toExternalForm(java.net.URL)
  567.      */
  568.     public String toString() {
  569.     return toExternalForm();
  570.     }
  571.  
  572.     /**
  573.      * Constructs a string representation of this <code>URL</code>. The 
  574.      * string is created by calling the <code>toExternalForm</code> 
  575.      * method of the stream protocol handler for this object. 
  576.      *
  577.      * @return  a string representation of this object.
  578.      * @see     java.net.URL#URL(java.lang.String, java.lang.String, int, java.lang.String)
  579.      * @see     java.net.URLStreamHandler#toExternalForm(java.net.URL)
  580.      */
  581.     public String toExternalForm() {
  582.     return handler.toExternalForm(this);
  583.     }
  584.  
  585.     /** 
  586.      * Returns a <code>URLConnection</code> object that represents a 
  587.      * connection to the remote object referred to by the <code>URL</code>.
  588.      *
  589.      * <p>A new connection is opened every time by calling the
  590.      * <code>openConnection</code> method of the protocol handler for
  591.      * this URL.
  592.      *
  593.      * @return     a <code>URLConnection</code> to the URL.
  594.      * @exception  IOException  if an I/O exception occurs.
  595.      * @see        java.net.URL#URL(java.lang.String, java.lang.String, 
  596.      *             int, java.lang.String)
  597.      * @see        java.net.URLConnection
  598.      * @see        java.net.URLStreamHandler#openConnection(java.net.URL)
  599.      */
  600.     public URLConnection openConnection() throws java.io.IOException {
  601.     return handler.openConnection(this);
  602.     }
  603.  
  604.     /**
  605.      * Opens a connection to this <code>URL</code> and returns an 
  606.      * <code>InputStream</code> for reading from that connection. This 
  607.      * method is a shorthand for:
  608.      * <blockquote><pre>
  609.      *     openConnection().getInputStream()
  610.      * </pre></blockquote>
  611.      *
  612.      * @return     an input stream for reading from the URL connection.
  613.      * @exception  IOException  if an I/O exception occurs.
  614.      * @see        java.net.URL#openConnection()
  615.      * @see        java.net.URLConnection#getInputStream()
  616.      */
  617.     public final InputStream openStream()             // REMIND: drop final
  618.     throws java.io.IOException
  619.     {
  620.     return openConnection().getInputStream();
  621.     }
  622.  
  623.     /**
  624.      * Returns the contents of this URL. This method is a shorthand for:
  625.      * <blockquote><pre>
  626.      *     openConnection().getContent()
  627.      * </pre></blockquote>
  628.      *
  629.      * @return     the contents of this URL.
  630.      * @exception  IOException  if an I/O exception occurs.
  631.      * @see        java.net.URLConnection#getContent()
  632.      */
  633.     public final Object getContent()                 // REMIND: drop final
  634.     throws java.io.IOException
  635.     {
  636.     return openConnection().getContent();
  637.     }
  638.  
  639.     /**
  640.      * The URLStreamHandler factory.
  641.      */
  642.     static URLStreamHandlerFactory factory;
  643.  
  644.     /**
  645.      * Sets an application's <code>URLStreamHandlerFactory</code>.
  646.      * This method can be called at most once in a given Java Virtual
  647.      * Machine.
  648.      *
  649.      *<p> The <code>URLStreamHandlerFactory</code> instance is used to
  650.      *construct a stream protocol handler from a protocol name.
  651.      *
  652.      * @param      fac   the desired factory.
  653.      * @exception  Error  if the application has already set a factory.
  654.      * @see        java.net.URL#URL(java.lang.String, java.lang.String, 
  655.      *             int, java.lang.String)
  656.      * @see        java.net.URLStreamHandlerFactory
  657.      */
  658.     public static synchronized void setURLStreamHandlerFactory(URLStreamHandlerFactory fac) {
  659.     if (factory != null) {
  660.         throw new Error("factory already defined");
  661.     }
  662.     SecurityManager security = System.getSecurityManager();
  663.     if (security != null) {
  664.         security.checkSetFactory();
  665.     }
  666.     handlers.clear();
  667.     factory = fac;
  668.     }
  669.  
  670.     /**
  671.      * A table of protocol handlers.
  672.      */
  673.     static Hashtable handlers = new Hashtable();
  674.  
  675.  
  676.     /**
  677.      * Returns the Stream Handler.
  678.      * @param protocol the protocol to use
  679.      */
  680.     static synchronized URLStreamHandler getURLStreamHandler(String protocol) {
  681.     URLStreamHandler handler = (URLStreamHandler)handlers.get(protocol);
  682.     if (handler == null) {
  683.         // Use the factory (if any)
  684.         if (factory != null) {
  685.         handler = factory.createURLStreamHandler(protocol);
  686.         }
  687.  
  688.         // Try java protocol handler
  689.         if (handler == null) {
  690.         String packagePrefixList = null;
  691.  
  692.         try {
  693.             java.security.AccessController.beginPrivileged();
  694.             packagePrefixList = System.getProperty(protocolPathProp,"");
  695.         } finally {
  696.             java.security.AccessController.endPrivileged();
  697.         }
  698.         if (packagePrefixList != "") {
  699.             packagePrefixList += "|";
  700.         }
  701.  
  702.         // REMIND: decide whether to allow the "null" class prefix
  703.         // or not.
  704.         packagePrefixList += "sun.net.www.protocol";
  705.  
  706.         StringTokenizer packagePrefixIter =
  707.             new StringTokenizer(packagePrefixList, "|");
  708.  
  709.         while (handler == null && 
  710.                packagePrefixIter.hasMoreTokens()) {
  711.  
  712.             String packagePrefix = 
  713.               packagePrefixIter.nextToken().trim();
  714.             try {
  715.                 String clsName = packagePrefix + "." + protocol +
  716.               ".Handler";
  717.             Class cls = Class.forName(clsName);
  718.             if (cls == null) {
  719.                 ClassLoader cl = ClassLoader.getBaseClassLoader();
  720.                 if (cl != null) {
  721.                     cls = cl.loadClass(clsName);
  722.                 }
  723.             }
  724.             if (cls != null) {
  725.                 handler  = 
  726.                   (URLStreamHandler)cls.newInstance();
  727.             }
  728.             } catch (Exception e) {
  729.             // any number of exceptions can get thrown here
  730.             }
  731.         }
  732.         }
  733.         if (handler != null) {
  734.         handlers.put(protocol, handler);
  735.         }
  736.     }
  737.     return handler;
  738.     }
  739.  
  740.     /** 
  741.      * WriteObject is called to save the state of the URL to an
  742.      * ObjectOutputStream The handler is not saved since it is
  743.      * specific to this system.  
  744.      */
  745.     private synchronized void writeObject(java.io.ObjectOutputStream s)
  746.         throws IOException
  747.     {
  748.     s.defaultWriteObject();    // write the fields
  749.     }
  750.  
  751.     /** 
  752.      * readObject is called to restore the state of the URL from the
  753.      * stream.  It reads the compoents of the URL and finds the local
  754.      * stream handler.  
  755.      */
  756.     private synchronized void readObject(java.io.ObjectInputStream s)
  757.          throws IOException, ClassNotFoundException
  758.     {
  759.     s.defaultReadObject();    // read the fields
  760.     if ((handler = getURLStreamHandler(protocol)) == null) {
  761.         throw new IOException("unknown protocol: " + protocol);
  762.     }
  763.     }
  764. }
  765.