home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 1997 May / Pcwk0597.iso / sybase / starbuck / java.z / URL.java < prev    next >
Text File  |  1996-05-03  |  12KB  |  431 lines

  1. /*
  2.  * @(#)URL.java    1.29 96/02/29
  3.  * 
  4.  * Copyright (c) 1994-1996 Sun Microsystems, Inc. All Rights Reserved.
  5.  * 
  6.  * Permission to use, copy, modify, and distribute this software and its
  7.  * documentation for NON-COMMERCIAL purposes and without fee is hereby
  8.  * granted provided that this copyright notice appears in all copies. Please
  9.  * refer to the file "copyright.html" for further important copyright and
  10.  * licensing information.
  11.  * 
  12.  * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF THE
  13.  * SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  14.  * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
  15.  * OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY
  16.  * LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR
  17.  * ITS DERIVATIVES.
  18.  */
  19.  
  20. package java.net;
  21.  
  22. import java.io.IOException;
  23. import java.io.InputStream;
  24. import java.io.OutputStream;
  25. import java.util.Hashtable;
  26. import java.util.StringTokenizer;
  27.  
  28. /**
  29.  * Class URL represents a Uniform Reference Locator -- a reference
  30.  * to an object on the World Wide Web. This is a constant object,
  31.  * once it is created, its fields cannot be changed.
  32.  *
  33.  * @version     1.29, 29 Feb 1996
  34.  * @author     James Gosling
  35.  */
  36.  
  37. public final class URL {
  38.     /**
  39.      * The property which specifies the package prefix list to be scanned
  40.      * for protocol handlers.  The value of this property (if any) should
  41.      * be a vertical bar delimited list of package names to search through
  42.      * for a protocol handler to load.  The policy of this class is that
  43.      * all protocol handlers will be in a class called <protocolname>.Handler,
  44.      * and each package in the list is examined in turn for a matching
  45.      * handler.  If none are found (or the property is not specified), the
  46.      * default package prefix, sun.net.www.protocol, is used.  The search
  47.      * proceeds from the first package in the last to the last and stops
  48.      * when a match is found.
  49.      */
  50.     private static final String protocolPathProp = "java.protocol.handler.pkgs";
  51.  
  52.     /** 
  53.      * The protocol to use (ftp, http, nntp, ... etc.) . 
  54.      */
  55.     private String protocol;
  56.  
  57.     /** 
  58.      * The host name in which to connect to. 
  59.      */
  60.     private String host;
  61.  
  62.     /** 
  63.      * The protocol port to connect to. 
  64.      */
  65.     private int port = -1;
  66.  
  67.     /** 
  68.      * The specified file name on that host. 
  69.      */
  70.     private String file;
  71.  
  72.     /** 
  73.      * # reference. 
  74.      */
  75.     private String ref;
  76.  
  77.     /**
  78.      * The URLStreamHandler for this URL.
  79.      */
  80.     URLStreamHandler handler;
  81.  
  82.     /** 
  83.      * Creates an absolute URL from the specified protocol,
  84.      * host, port and file.
  85.      * @param protocol the protocol to use
  86.      * @param host the host to connect to
  87.      * @param port the port at that host to connect to
  88.      * @param file the file on that host
  89.      * @exception MalformedURLException If an unknown protocol is 
  90.      * found. 
  91.      */
  92.     public URL(String protocol, String host, int port, String file)
  93.     throws MalformedURLException {
  94.     this.protocol = protocol;
  95.     this.host = host;
  96.     this.file = file;
  97.     this.port = port;
  98.     if ((handler = getURLStreamHandler(protocol)) == null) {
  99.         throw new MalformedURLException("unknown protocol: " + protocol);
  100.     }
  101.     }
  102.  
  103.     /** 
  104.      * Creates an absolute URL from the specified protocol,
  105.      * host, and file.  The port number used will be the default for the
  106.      * protocol.
  107.      * @param protocol the protocol to use
  108.      * @param host the host to connect to
  109.      * @param file the file on that host
  110.      * @exception MalformedURLException If an unknown protocol is 
  111.      * found. 
  112.      */
  113.     public URL(String protocol, String host, String file) throws MalformedURLException {
  114.     this(protocol, host, -1, file);
  115.     }
  116.  
  117.     /**
  118.      * Creates a URL from the unparsed absolute URL.
  119.      * @param spec the URL String to parse
  120.      */
  121.     public URL(String spec) throws MalformedURLException {
  122.     this(null, spec);
  123.     }
  124.  
  125.     /** 
  126.      * Creates a URL from the unparsed URL in the specified context.If
  127.      * spec is an absolute URL it is used as is. Otherwise it isparsed
  128.      * in terms of the context.  Context may be null (indicating no
  129.      * context).
  130.  
  131.      * @param context the context to parse the URL to
  132.      * @param spec the URL String to parse
  133.      * @exception MalformedURLException If the protocol is equal to null. 
  134.      */
  135.     public URL(URL context, String spec) throws MalformedURLException {
  136.     String original = spec;
  137.     int i, limit, c;
  138.     int start = 0;
  139.     String newProtocol = null;
  140.  
  141.     try {
  142.         limit = spec.length();
  143.         while ((limit > 0) && (spec.charAt(limit - 1) <= ' ')) {
  144.         limit--;    //eliminate trailing whitespace
  145.         }
  146.         while ((start < limit) && (spec.charAt(start) <= ' ')) {
  147.         start++;    // eliminate leading whitespace
  148.         }
  149.  
  150.         if (spec.regionMatches(true, start, "url:", 0, 4)) {
  151.         start += 4;
  152.         }
  153.         for (i = start ; (i < limit) && ((c = spec.charAt(i)) != '/') ; i++) {
  154.         if (c == ':') {
  155.             newProtocol = spec.substring(start, i).toLowerCase();
  156.             start = i + 1;
  157.             break;
  158.         }
  159.         }
  160.         // Only use our context if the protocols match.
  161.         if ((context != null) && ((newProtocol == null) ||
  162.                     newProtocol.equals(context.protocol))) {
  163.         protocol = context.protocol;
  164.         host = context.host;
  165.         port = context.port;
  166.         file = context.file;
  167.         } else {
  168.         protocol = newProtocol;
  169.         }
  170.  
  171.         if (protocol == null) {
  172.         throw new MalformedURLException("no protocol: "+original);
  173.         }
  174.  
  175.         if ((handler = getURLStreamHandler(protocol)) == null) {
  176.         throw new MalformedURLException("unknown protocol: "+protocol);
  177.         }
  178.  
  179.         i = spec.indexOf('#', start);
  180.         if (i >= 0) {
  181.         ref = spec.substring(i + 1, limit);
  182.         limit = i;
  183.         }
  184.         handler.parseURL(this, spec, start, limit);
  185.  
  186.     } catch(MalformedURLException e) {
  187.         throw e;
  188.     } catch(Exception e) {
  189.         throw new MalformedURLException(original + ": " + e);
  190.     }
  191.     }
  192.  
  193.     /**
  194.      * Sets the fields of the URL. This is not a public method so that 
  195.      * only URLStreamHandlers can modify URL fields. URLs are 
  196.      * otherwise constant.
  197.      *
  198.      * REMIND: this method will be moved to URLStreamHandler
  199.      *
  200.      * @param protocol the protocol to use
  201.      * @param host the host name to connecto to
  202.      * @param port the protocol port to connect to
  203.      * @param file the specified file name on that host
  204.      * @param ref the reference
  205.      */
  206.     protected void set(String protocol, String host, int port, String file, String ref) {
  207.     this.protocol = protocol;
  208.     this.host = host;
  209.     this.port = port;
  210.     this.file = file;
  211.     this.ref = ref;
  212.     }
  213.  
  214.     /**
  215.      * Gets the port number. Returns -1 if the port is not set.
  216.      */
  217.     public int getPort() {
  218.     return port;
  219.     }
  220.  
  221.     /**
  222.      * Gets the protocol name.
  223.      */
  224.     public String getProtocol() {
  225.     return protocol;
  226.     }
  227.  
  228.     /**
  229.      * Gets the host name.
  230.      */
  231.     public String getHost() {
  232.     return host;
  233.     }
  234.  
  235.     /**
  236.      * Gets the file name.
  237.      */
  238.     public String getFile() {
  239.     return file;
  240.     }
  241.  
  242.     /**
  243.      * Gets the ref.
  244.      */
  245.     public String getRef() {
  246.     return ref;
  247.     }
  248.  
  249.     /**
  250.      * Compares two URLs.
  251.      * @param    obj the URL to compare against.
  252.      * @return    true if and only if they are equal, false otherwise.
  253.      */
  254.     public boolean equals(Object obj) {
  255.     return (obj instanceof URL) && sameFile((URL)obj);
  256.     }
  257.  
  258.     /** 
  259.      * Creates an integer suitable for hash table indexing. 
  260.      */
  261.     public int hashCode() {
  262.     int inhash = 0;
  263.     if (!host.equals("")) {
  264.         try {
  265.         inhash = InetAddress.getByName(host).hashCode();
  266.         } catch(UnknownHostException e) {
  267.         }
  268.     }
  269.     return protocol.hashCode() ^ inhash ^ file.hashCode();
  270.     }
  271.  
  272.     /**
  273.      * Compares the host components of two URLs.
  274.      * @param h1 the URL of the first host to compare 
  275.      * @param h2 the URL of the second host to compare 
  276.      * @return    true if and only if they are equal, false otherwise.
  277.      * @exception UnknownHostException If an unknown host is found.
  278.      */
  279.     boolean hostsEqual(String h1, String h2) {
  280.     if (h1.equals(h2)) {
  281.         return true;
  282.     }
  283.     // Have to resolve addresses before comparing, otherwise
  284.     // names like tachyon and tachyon.eng would compare different
  285.     try {
  286.         InetAddress a1 = InetAddress.getByName(h1);
  287.         InetAddress a2 = InetAddress.getByName(h2);
  288.         return a1.equals(a2);
  289.     } catch(UnknownHostException e) {
  290.     } catch(SecurityException e) {
  291.     }
  292.     return false;
  293.     }
  294.  
  295.     /**
  296.      * Compares two URLs, excluding the "ref" fields: sameFile is true
  297.      * if the true references the same remote object, but not necessarily
  298.      * the same subpiece of that object.
  299.      * @param    other    the URL to compare against.
  300.      * @return    true if and only if they are equal, false otherwise.
  301.      */
  302.     public boolean sameFile(URL other) {
  303.     // AVH: should we not user getPort to compare ports?
  304.     return protocol.equals(other.protocol) &&
  305.            hostsEqual(host, other.host) &&
  306.            (port == other.port) &&
  307.            file.equals(other.file);
  308.     }
  309.  
  310.     /**
  311.      * Converts to a human-readable form.
  312.      * @return    the textual representation.
  313.      */
  314.     public String toString() {
  315.     return toExternalForm();
  316.     }
  317.  
  318.     /**
  319.      * Reverses the parsing of the URL.
  320.      * @return    the textual representation of the fully qualified URL (i.e.
  321.      *        after the context and canonicalization have been applied).
  322.      */
  323.     public String toExternalForm() {
  324.     return handler.toExternalForm(this);
  325.     }
  326.  
  327.     /** 
  328.      * Creates (if not already in existance) a URLConnection object that
  329.      * contains a connection to the remote object referred to by
  330.      * the URL.  Invokes the appropriate protocol handler.  Failure is
  331.      * indicated by throwing an exception.
  332.      * @exception IOException If an I/O exception has occurred.
  333.      * @see URLConnection
  334.      */
  335.     public URLConnection openConnection()
  336.     throws java.io.IOException
  337.     {
  338.     return handler.openConnection(this);
  339.     }
  340.  
  341.     /**
  342.      * Opens an input stream.
  343.      * @exception IOException If an I/O exception has occurred.
  344.      */
  345.     public final InputStream openStream()             // REMIND: drop final
  346.     throws java.io.IOException
  347.     {
  348.     return openConnection().getInputStream();
  349.     }
  350.  
  351.     /**
  352.      * Gets the contents from this opened connection.
  353.      * @exception IOException If an I/O exception has occurred.
  354.      */
  355.     public final Object getContent()                 // REMIND: drop final
  356.     throws java.io.IOException
  357.     {
  358.     return openConnection().getContent();
  359.     }
  360.  
  361.     /**
  362.      * The URLStreamHandler factory.
  363.      */
  364.     static URLStreamHandlerFactory factory;
  365.  
  366.     /**
  367.      * Sets the URLStreamHandler factory.
  368.      * @param fac the desired factory
  369.      * @exception Error If the factory has already been defined.
  370.      */
  371.     public static synchronized void setURLStreamHandlerFactory(URLStreamHandlerFactory fac) {
  372.     if (factory != null) {
  373.         throw new Error("factory already defined");
  374.     }
  375.     SecurityManager security = System.getSecurityManager();
  376.     if (security != null) {
  377.         security.checkSetFactory();
  378.     }
  379.     factory = fac;
  380.     }
  381.  
  382.     /**
  383.      * A table of protocol handlers.
  384.      */
  385.     static Hashtable handlers = new Hashtable();
  386.  
  387.     /**
  388.      * Gets the Stream Handler.
  389.      * @param protocol the protocol to use
  390.      */
  391.     static synchronized URLStreamHandler getURLStreamHandler(String protocol) {
  392.     URLStreamHandler handler = (URLStreamHandler)handlers.get(protocol);
  393.     if (handler == null) {
  394.         // Use the factory (if any)
  395.         if (factory != null) {
  396.         handler = factory.createURLStreamHandler(protocol);
  397.         }
  398.  
  399.         // Try java protocol handler
  400.         if (handler == null) {
  401.         String packagePrefixList =
  402.             System.getProperty(protocolPathProp, "");
  403.         if (packagePrefixList != "") {
  404.             packagePrefixList += "|";
  405.         }
  406.  
  407.         // REMIND: decide whether to allow the "null" class prefix
  408.         // or not.
  409.         packagePrefixList += "sun.net.www.protocol";
  410.  
  411.         StringTokenizer packagePrefixIter =
  412.             new StringTokenizer(packagePrefixList, "|");
  413.  
  414.         while (handler == null && packagePrefixIter.hasMoreTokens()) {
  415.             String packagePrefix = packagePrefixIter.nextToken().trim();
  416.             try {
  417.             String clname = packagePrefix + "." + protocol
  418.                 + ".Handler";
  419.             handler = (URLStreamHandler)Class.forName(clname).newInstance();
  420.             } catch (Exception e) {
  421.             }
  422.         }
  423.         }
  424.         if (handler != null) {
  425.         handlers.put(protocol, handler);
  426.         }
  427.     }
  428.     return handler;
  429.     }
  430. }
  431.