emul/src/main/java/java/net/URL.java
author Jaroslav Tulach <jtulach@netbeans.org>
Tue, 30 Oct 2012 09:14:17 +0100
branchjdk7-b147
changeset 121 b93908ede23a
child 122 0a582b5a2737
permissions -rw-r--r--
Few more classes needed for ClassLoader and Class methods
jtulach@120
     1
/*
jtulach@120
     2
 * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved.
jtulach@120
     3
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
jtulach@120
     4
 *
jtulach@120
     5
 * This code is free software; you can redistribute it and/or modify it
jtulach@120
     6
 * under the terms of the GNU General Public License version 2 only, as
jtulach@120
     7
 * published by the Free Software Foundation.  Oracle designates this
jtulach@120
     8
 * particular file as subject to the "Classpath" exception as provided
jtulach@120
     9
 * by Oracle in the LICENSE file that accompanied this code.
jtulach@120
    10
 *
jtulach@120
    11
 * This code is distributed in the hope that it will be useful, but WITHOUT
jtulach@120
    12
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
jtulach@120
    13
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
jtulach@120
    14
 * version 2 for more details (a copy is included in the LICENSE file that
jtulach@120
    15
 * accompanied this code).
jtulach@120
    16
 *
jtulach@120
    17
 * You should have received a copy of the GNU General Public License version
jtulach@120
    18
 * 2 along with this work; if not, write to the Free Software Foundation,
jtulach@120
    19
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
jtulach@120
    20
 *
jtulach@120
    21
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
jtulach@120
    22
 * or visit www.oracle.com if you need additional information or have any
jtulach@120
    23
 * questions.
jtulach@120
    24
 */
jtulach@120
    25
jtulach@120
    26
package java.net;
jtulach@120
    27
jtulach@120
    28
import java.io.IOException;
jtulach@120
    29
import java.io.InputStream;
jtulach@120
    30
import java.io.OutputStream;
jtulach@120
    31
import java.util.Hashtable;
jtulach@120
    32
import java.util.StringTokenizer;
jtulach@120
    33
import sun.security.util.SecurityConstants;
jtulach@120
    34
jtulach@120
    35
/**
jtulach@120
    36
 * Class <code>URL</code> represents a Uniform Resource
jtulach@120
    37
 * Locator, a pointer to a "resource" on the World
jtulach@120
    38
 * Wide Web. A resource can be something as simple as a file or a
jtulach@120
    39
 * directory, or it can be a reference to a more complicated object,
jtulach@120
    40
 * such as a query to a database or to a search engine. More
jtulach@120
    41
 * information on the types of URLs and their formats can be found at:
jtulach@120
    42
 * <blockquote>
jtulach@120
    43
 *     <a href="http://www.socs.uts.edu.au/MosaicDocs-old/url-primer.html">
jtulach@120
    44
 *    <i>http://www.socs.uts.edu.au/MosaicDocs-old/url-primer.html</i></a>
jtulach@120
    45
 * </blockquote>
jtulach@120
    46
 * <p>
jtulach@120
    47
 * In general, a URL can be broken into several parts. The previous
jtulach@120
    48
 * example of a URL indicates that the protocol to use is
jtulach@120
    49
 * <code>http</code> (HyperText Transfer Protocol) and that the
jtulach@120
    50
 * information resides on a host machine named
jtulach@120
    51
 * <code>www.socs.uts.edu.au</code>. The information on that host
jtulach@120
    52
 * machine is named <code>/MosaicDocs-old/url-primer.html</code>. The exact
jtulach@120
    53
 * meaning of this name on the host machine is both protocol
jtulach@120
    54
 * dependent and host dependent. The information normally resides in
jtulach@120
    55
 * a file, but it could be generated on the fly. This component of
jtulach@120
    56
 * the URL is called the <i>path</i> component.
jtulach@120
    57
 * <p>
jtulach@120
    58
 * A URL can optionally specify a "port", which is the
jtulach@120
    59
 * port number to which the TCP connection is made on the remote host
jtulach@120
    60
 * machine. If the port is not specified, the default port for
jtulach@120
    61
 * the protocol is used instead. For example, the default port for
jtulach@120
    62
 * <code>http</code> is <code>80</code>. An alternative port could be
jtulach@120
    63
 * specified as:
jtulach@120
    64
 * <blockquote><pre>
jtulach@120
    65
 *     http://www.socs.uts.edu.au:80/MosaicDocs-old/url-primer.html
jtulach@120
    66
 * </pre></blockquote>
jtulach@120
    67
 * <p>
jtulach@120
    68
 * The syntax of <code>URL</code> is defined by  <a
jtulach@120
    69
 * href="http://www.ietf.org/rfc/rfc2396.txt"><i>RFC&nbsp;2396: Uniform
jtulach@120
    70
 * Resource Identifiers (URI): Generic Syntax</i></a>, amended by <a
jtulach@120
    71
 * href="http://www.ietf.org/rfc/rfc2732.txt"><i>RFC&nbsp;2732: Format for
jtulach@120
    72
 * Literal IPv6 Addresses in URLs</i></a>. The Literal IPv6 address format
jtulach@120
    73
 * also supports scope_ids. The syntax and usage of scope_ids is described
jtulach@120
    74
 * <a href="Inet6Address.html#scoped">here</a>.
jtulach@120
    75
 * <p>
jtulach@120
    76
 * A URL may have appended to it a "fragment", also known
jtulach@120
    77
 * as a "ref" or a "reference". The fragment is indicated by the sharp
jtulach@120
    78
 * sign character "#" followed by more characters. For example,
jtulach@120
    79
 * <blockquote><pre>
jtulach@120
    80
 *     http://java.sun.com/index.html#chapter1
jtulach@120
    81
 * </pre></blockquote>
jtulach@120
    82
 * <p>
jtulach@120
    83
 * This fragment is not technically part of the URL. Rather, it
jtulach@120
    84
 * indicates that after the specified resource is retrieved, the
jtulach@120
    85
 * application is specifically interested in that part of the
jtulach@120
    86
 * document that has the tag <code>chapter1</code> attached to it. The
jtulach@120
    87
 * meaning of a tag is resource specific.
jtulach@120
    88
 * <p>
jtulach@120
    89
 * An application can also specify a "relative URL",
jtulach@120
    90
 * which contains only enough information to reach the resource
jtulach@120
    91
 * relative to another URL. Relative URLs are frequently used within
jtulach@120
    92
 * HTML pages. For example, if the contents of the URL:
jtulach@120
    93
 * <blockquote><pre>
jtulach@120
    94
 *     http://java.sun.com/index.html
jtulach@120
    95
 * </pre></blockquote>
jtulach@120
    96
 * contained within it the relative URL:
jtulach@120
    97
 * <blockquote><pre>
jtulach@120
    98
 *     FAQ.html
jtulach@120
    99
 * </pre></blockquote>
jtulach@120
   100
 * it would be a shorthand for:
jtulach@120
   101
 * <blockquote><pre>
jtulach@120
   102
 *     http://java.sun.com/FAQ.html
jtulach@120
   103
 * </pre></blockquote>
jtulach@120
   104
 * <p>
jtulach@120
   105
 * The relative URL need not specify all the components of a URL. If
jtulach@120
   106
 * the protocol, host name, or port number is missing, the value is
jtulach@120
   107
 * inherited from the fully specified URL. The file component must be
jtulach@120
   108
 * specified. The optional fragment is not inherited.
jtulach@120
   109
 * <p>
jtulach@120
   110
 * The URL class does not itself encode or decode any URL components
jtulach@120
   111
 * according to the escaping mechanism defined in RFC2396. It is the
jtulach@120
   112
 * responsibility of the caller to encode any fields, which need to be
jtulach@120
   113
 * escaped prior to calling URL, and also to decode any escaped fields,
jtulach@120
   114
 * that are returned from URL. Furthermore, because URL has no knowledge
jtulach@120
   115
 * of URL escaping, it does not recognise equivalence between the encoded
jtulach@120
   116
 * or decoded form of the same URL. For example, the two URLs:<br>
jtulach@120
   117
 * <pre>    http://foo.com/hello world/ and http://foo.com/hello%20world</pre>
jtulach@120
   118
 * would be considered not equal to each other.
jtulach@120
   119
 * <p>
jtulach@120
   120
 * Note, the {@link java.net.URI} class does perform escaping of its
jtulach@120
   121
 * component fields in certain circumstances. The recommended way
jtulach@120
   122
 * to manage the encoding and decoding of URLs is to use {@link java.net.URI},
jtulach@120
   123
 * and to convert between these two classes using {@link #toURI()} and
jtulach@120
   124
 * {@link URI#toURL()}.
jtulach@120
   125
 * <p>
jtulach@120
   126
 * The {@link URLEncoder} and {@link URLDecoder} classes can also be
jtulach@120
   127
 * used, but only for HTML form encoding, which is not the same
jtulach@120
   128
 * as the encoding scheme defined in RFC2396.
jtulach@120
   129
 *
jtulach@120
   130
 * @author  James Gosling
jtulach@120
   131
 * @since JDK1.0
jtulach@120
   132
 */
jtulach@120
   133
public final class URL implements java.io.Serializable {
jtulach@120
   134
jtulach@120
   135
    static final long serialVersionUID = -7627629688361524110L;
jtulach@120
   136
jtulach@120
   137
    /**
jtulach@120
   138
     * The property which specifies the package prefix list to be scanned
jtulach@120
   139
     * for protocol handlers.  The value of this property (if any) should
jtulach@120
   140
     * be a vertical bar delimited list of package names to search through
jtulach@120
   141
     * for a protocol handler to load.  The policy of this class is that
jtulach@120
   142
     * all protocol handlers will be in a class called <protocolname>.Handler,
jtulach@120
   143
     * and each package in the list is examined in turn for a matching
jtulach@120
   144
     * handler.  If none are found (or the property is not specified), the
jtulach@120
   145
     * default package prefix, sun.net.www.protocol, is used.  The search
jtulach@120
   146
     * proceeds from the first package in the list to the last and stops
jtulach@120
   147
     * when a match is found.
jtulach@120
   148
     */
jtulach@120
   149
    private static final String protocolPathProp = "java.protocol.handler.pkgs";
jtulach@120
   150
jtulach@120
   151
    /**
jtulach@120
   152
     * The protocol to use (ftp, http, nntp, ... etc.) .
jtulach@120
   153
     * @serial
jtulach@120
   154
     */
jtulach@120
   155
    private String protocol;
jtulach@120
   156
jtulach@120
   157
    /**
jtulach@120
   158
     * The host name to connect to.
jtulach@120
   159
     * @serial
jtulach@120
   160
     */
jtulach@120
   161
    private String host;
jtulach@120
   162
jtulach@120
   163
    /**
jtulach@120
   164
     * The protocol port to connect to.
jtulach@120
   165
     * @serial
jtulach@120
   166
     */
jtulach@120
   167
    private int port = -1;
jtulach@120
   168
jtulach@120
   169
    /**
jtulach@120
   170
     * The specified file name on that host. <code>file</code> is
jtulach@120
   171
     * defined as <code>path[?query]</code>
jtulach@120
   172
     * @serial
jtulach@120
   173
     */
jtulach@120
   174
    private String file;
jtulach@120
   175
jtulach@120
   176
    /**
jtulach@120
   177
     * The query part of this URL.
jtulach@120
   178
     */
jtulach@120
   179
    private transient String query;
jtulach@120
   180
jtulach@120
   181
    /**
jtulach@120
   182
     * The authority part of this URL.
jtulach@120
   183
     * @serial
jtulach@120
   184
     */
jtulach@120
   185
    private String authority;
jtulach@120
   186
jtulach@120
   187
    /**
jtulach@120
   188
     * The path part of this URL.
jtulach@120
   189
     */
jtulach@120
   190
    private transient String path;
jtulach@120
   191
jtulach@120
   192
    /**
jtulach@120
   193
     * The userinfo part of this URL.
jtulach@120
   194
     */
jtulach@120
   195
    private transient String userInfo;
jtulach@120
   196
jtulach@120
   197
    /**
jtulach@120
   198
     * # reference.
jtulach@120
   199
     * @serial
jtulach@120
   200
     */
jtulach@120
   201
    private String ref;
jtulach@120
   202
jtulach@120
   203
    /**
jtulach@120
   204
     * The host's IP address, used in equals and hashCode.
jtulach@120
   205
     * Computed on demand. An uninitialized or unknown hostAddress is null.
jtulach@120
   206
     */
jtulach@120
   207
    transient InetAddress hostAddress;
jtulach@120
   208
jtulach@120
   209
    /**
jtulach@120
   210
     * The URLStreamHandler for this URL.
jtulach@120
   211
     */
jtulach@120
   212
    transient URLStreamHandler handler;
jtulach@120
   213
jtulach@120
   214
    /* Our hash code.
jtulach@120
   215
     * @serial
jtulach@120
   216
     */
jtulach@120
   217
    private int hashCode = -1;
jtulach@120
   218
jtulach@120
   219
    /**
jtulach@120
   220
     * Creates a <code>URL</code> object from the specified
jtulach@120
   221
     * <code>protocol</code>, <code>host</code>, <code>port</code>
jtulach@120
   222
     * number, and <code>file</code>.<p>
jtulach@120
   223
     *
jtulach@120
   224
     * <code>host</code> can be expressed as a host name or a literal
jtulach@120
   225
     * IP address. If IPv6 literal address is used, it should be
jtulach@120
   226
     * enclosed in square brackets (<tt>'['</tt> and <tt>']'</tt>), as
jtulach@120
   227
     * specified by <a
jtulach@120
   228
     * href="http://www.ietf.org/rfc/rfc2732.txt">RFC&nbsp;2732</a>;
jtulach@120
   229
     * However, the literal IPv6 address format defined in <a
jtulach@120
   230
     * href="http://www.ietf.org/rfc/rfc2373.txt"><i>RFC&nbsp;2373: IP
jtulach@120
   231
     * Version 6 Addressing Architecture</i></a> is also accepted.<p>
jtulach@120
   232
     *
jtulach@120
   233
     * Specifying a <code>port</code> number of <code>-1</code>
jtulach@120
   234
     * indicates that the URL should use the default port for the
jtulach@120
   235
     * protocol.<p>
jtulach@120
   236
     *
jtulach@120
   237
     * If this is the first URL object being created with the specified
jtulach@120
   238
     * protocol, a <i>stream protocol handler</i> object, an instance of
jtulach@120
   239
     * class <code>URLStreamHandler</code>, is created for that protocol:
jtulach@120
   240
     * <ol>
jtulach@120
   241
     * <li>If the application has previously set up an instance of
jtulach@120
   242
     *     <code>URLStreamHandlerFactory</code> as the stream handler factory,
jtulach@120
   243
     *     then the <code>createURLStreamHandler</code> method of that instance
jtulach@120
   244
     *     is called with the protocol string as an argument to create the
jtulach@120
   245
     *     stream protocol handler.
jtulach@120
   246
     * <li>If no <code>URLStreamHandlerFactory</code> has yet been set up,
jtulach@120
   247
     *     or if the factory's <code>createURLStreamHandler</code> method
jtulach@120
   248
     *     returns <code>null</code>, then the constructor finds the
jtulach@120
   249
     *     value of the system property:
jtulach@120
   250
     *     <blockquote><pre>
jtulach@120
   251
     *         java.protocol.handler.pkgs
jtulach@120
   252
     *     </pre></blockquote>
jtulach@120
   253
     *     If the value of that system property is not <code>null</code>,
jtulach@120
   254
     *     it is interpreted as a list of packages separated by a vertical
jtulach@120
   255
     *     slash character '<code>|</code>'. The constructor tries to load
jtulach@120
   256
     *     the class named:
jtulach@120
   257
     *     <blockquote><pre>
jtulach@120
   258
     *         &lt;<i>package</i>&gt;.&lt;<i>protocol</i>&gt;.Handler
jtulach@120
   259
     *     </pre></blockquote>
jtulach@120
   260
     *     where &lt;<i>package</i>&gt; is replaced by the name of the package
jtulach@120
   261
     *     and &lt;<i>protocol</i>&gt; is replaced by the name of the protocol.
jtulach@120
   262
     *     If this class does not exist, or if the class exists but it is not
jtulach@120
   263
     *     a subclass of <code>URLStreamHandler</code>, then the next package
jtulach@120
   264
     *     in the list is tried.
jtulach@120
   265
     * <li>If the previous step fails to find a protocol handler, then the
jtulach@120
   266
     *     constructor tries to load from a system default package.
jtulach@120
   267
     *     <blockquote><pre>
jtulach@120
   268
     *         &lt;<i>system default package</i>&gt;.&lt;<i>protocol</i>&gt;.Handler
jtulach@120
   269
     *     </pre></blockquote>
jtulach@120
   270
     *     If this class does not exist, or if the class exists but it is not a
jtulach@120
   271
     *     subclass of <code>URLStreamHandler</code>, then a
jtulach@120
   272
     *     <code>MalformedURLException</code> is thrown.
jtulach@120
   273
     * </ol>
jtulach@120
   274
     *
jtulach@120
   275
     * <p>Protocol handlers for the following protocols are guaranteed
jtulach@120
   276
     * to exist on the search path :-
jtulach@120
   277
     * <blockquote><pre>
jtulach@120
   278
     *     http, https, ftp, file, and jar
jtulach@120
   279
     * </pre></blockquote>
jtulach@120
   280
     * Protocol handlers for additional protocols may also be
jtulach@120
   281
     * available.
jtulach@120
   282
     *
jtulach@120
   283
     * <p>No validation of the inputs is performed by this constructor.
jtulach@120
   284
     *
jtulach@120
   285
     * @param      protocol   the name of the protocol to use.
jtulach@120
   286
     * @param      host       the name of the host.
jtulach@120
   287
     * @param      port       the port number on the host.
jtulach@120
   288
     * @param      file       the file on the host
jtulach@120
   289
     * @exception  MalformedURLException  if an unknown protocol is specified.
jtulach@120
   290
     * @see        java.lang.System#getProperty(java.lang.String)
jtulach@120
   291
     * @see        java.net.URL#setURLStreamHandlerFactory(
jtulach@120
   292
     *                  java.net.URLStreamHandlerFactory)
jtulach@120
   293
     * @see        java.net.URLStreamHandler
jtulach@120
   294
     * @see        java.net.URLStreamHandlerFactory#createURLStreamHandler(
jtulach@120
   295
     *                  java.lang.String)
jtulach@120
   296
     */
jtulach@120
   297
    public URL(String protocol, String host, int port, String file)
jtulach@120
   298
        throws MalformedURLException
jtulach@120
   299
    {
jtulach@120
   300
        this(protocol, host, port, file, null);
jtulach@120
   301
    }
jtulach@120
   302
jtulach@120
   303
    /**
jtulach@120
   304
     * Creates a URL from the specified <code>protocol</code>
jtulach@120
   305
     * name, <code>host</code> name, and <code>file</code> name. The
jtulach@120
   306
     * default port for the specified protocol is used.
jtulach@120
   307
     * <p>
jtulach@120
   308
     * This method is equivalent to calling the four-argument
jtulach@120
   309
     * constructor with the arguments being <code>protocol</code>,
jtulach@120
   310
     * <code>host</code>, <code>-1</code>, and <code>file</code>.
jtulach@120
   311
     *
jtulach@120
   312
     * No validation of the inputs is performed by this constructor.
jtulach@120
   313
     *
jtulach@120
   314
     * @param      protocol   the name of the protocol to use.
jtulach@120
   315
     * @param      host       the name of the host.
jtulach@120
   316
     * @param      file       the file on the host.
jtulach@120
   317
     * @exception  MalformedURLException  if an unknown protocol is specified.
jtulach@120
   318
     * @see        java.net.URL#URL(java.lang.String, java.lang.String,
jtulach@120
   319
     *                  int, java.lang.String)
jtulach@120
   320
     */
jtulach@120
   321
    public URL(String protocol, String host, String file)
jtulach@120
   322
            throws MalformedURLException {
jtulach@120
   323
        this(protocol, host, -1, file);
jtulach@120
   324
    }
jtulach@120
   325
jtulach@120
   326
    /**
jtulach@120
   327
     * Creates a <code>URL</code> object from the specified
jtulach@120
   328
     * <code>protocol</code>, <code>host</code>, <code>port</code>
jtulach@120
   329
     * number, <code>file</code>, and <code>handler</code>. Specifying
jtulach@120
   330
     * a <code>port</code> number of <code>-1</code> indicates that
jtulach@120
   331
     * the URL should use the default port for the protocol. Specifying
jtulach@120
   332
     * a <code>handler</code> of <code>null</code> indicates that the URL
jtulach@120
   333
     * should use a default stream handler for the protocol, as outlined
jtulach@120
   334
     * for:
jtulach@120
   335
     *     java.net.URL#URL(java.lang.String, java.lang.String, int,
jtulach@120
   336
     *                      java.lang.String)
jtulach@120
   337
     *
jtulach@120
   338
     * <p>If the handler is not null and there is a security manager,
jtulach@120
   339
     * the security manager's <code>checkPermission</code>
jtulach@120
   340
     * method is called with a
jtulach@120
   341
     * <code>NetPermission("specifyStreamHandler")</code> permission.
jtulach@120
   342
     * This may result in a SecurityException.
jtulach@120
   343
     *
jtulach@120
   344
     * No validation of the inputs is performed by this constructor.
jtulach@120
   345
     *
jtulach@120
   346
     * @param      protocol   the name of the protocol to use.
jtulach@120
   347
     * @param      host       the name of the host.
jtulach@120
   348
     * @param      port       the port number on the host.
jtulach@120
   349
     * @param      file       the file on the host
jtulach@120
   350
     * @param      handler    the stream handler for the URL.
jtulach@120
   351
     * @exception  MalformedURLException  if an unknown protocol is specified.
jtulach@120
   352
     * @exception  SecurityException
jtulach@120
   353
     *        if a security manager exists and its
jtulach@120
   354
     *        <code>checkPermission</code> method doesn't allow
jtulach@120
   355
     *        specifying a stream handler explicitly.
jtulach@120
   356
     * @see        java.lang.System#getProperty(java.lang.String)
jtulach@120
   357
     * @see        java.net.URL#setURLStreamHandlerFactory(
jtulach@120
   358
     *                  java.net.URLStreamHandlerFactory)
jtulach@120
   359
     * @see        java.net.URLStreamHandler
jtulach@120
   360
     * @see        java.net.URLStreamHandlerFactory#createURLStreamHandler(
jtulach@120
   361
     *                  java.lang.String)
jtulach@120
   362
     * @see        SecurityManager#checkPermission
jtulach@120
   363
     * @see        java.net.NetPermission
jtulach@120
   364
     */
jtulach@120
   365
    public URL(String protocol, String host, int port, String file,
jtulach@120
   366
               URLStreamHandler handler) throws MalformedURLException {
jtulach@120
   367
        if (handler != null) {
jtulach@120
   368
            SecurityManager sm = System.getSecurityManager();
jtulach@120
   369
            if (sm != null) {
jtulach@120
   370
                // check for permission to specify a handler
jtulach@120
   371
                checkSpecifyHandler(sm);
jtulach@120
   372
            }
jtulach@120
   373
        }
jtulach@120
   374
jtulach@120
   375
        protocol = protocol.toLowerCase();
jtulach@120
   376
        this.protocol = protocol;
jtulach@120
   377
        if (host != null) {
jtulach@120
   378
jtulach@120
   379
            /**
jtulach@120
   380
             * if host is a literal IPv6 address,
jtulach@120
   381
             * we will make it conform to RFC 2732
jtulach@120
   382
             */
jtulach@120
   383
            if (host.indexOf(':') >= 0 && !host.startsWith("[")) {
jtulach@120
   384
                host = "["+host+"]";
jtulach@120
   385
            }
jtulach@120
   386
            this.host = host;
jtulach@120
   387
jtulach@120
   388
            if (port < -1) {
jtulach@120
   389
                throw new MalformedURLException("Invalid port number :" +
jtulach@120
   390
                                                    port);
jtulach@120
   391
            }
jtulach@120
   392
            this.port = port;
jtulach@120
   393
            authority = (port == -1) ? host : host + ":" + port;
jtulach@120
   394
        }
jtulach@120
   395
jtulach@120
   396
        Parts parts = new Parts(file);
jtulach@120
   397
        path = parts.getPath();
jtulach@120
   398
        query = parts.getQuery();
jtulach@120
   399
jtulach@120
   400
        if (query != null) {
jtulach@120
   401
            this.file = path + "?" + query;
jtulach@120
   402
        } else {
jtulach@120
   403
            this.file = path;
jtulach@120
   404
        }
jtulach@120
   405
        ref = parts.getRef();
jtulach@120
   406
jtulach@120
   407
        // Note: we don't do validation of the URL here. Too risky to change
jtulach@120
   408
        // right now, but worth considering for future reference. -br
jtulach@120
   409
        if (handler == null &&
jtulach@120
   410
            (handler = getURLStreamHandler(protocol)) == null) {
jtulach@120
   411
            throw new MalformedURLException("unknown protocol: " + protocol);
jtulach@120
   412
        }
jtulach@120
   413
        this.handler = handler;
jtulach@120
   414
    }
jtulach@120
   415
jtulach@120
   416
    /**
jtulach@120
   417
     * Creates a <code>URL</code> object from the <code>String</code>
jtulach@120
   418
     * representation.
jtulach@120
   419
     * <p>
jtulach@120
   420
     * This constructor is equivalent to a call to the two-argument
jtulach@120
   421
     * constructor with a <code>null</code> first argument.
jtulach@120
   422
     *
jtulach@120
   423
     * @param      spec   the <code>String</code> to parse as a URL.
jtulach@120
   424
     * @exception  MalformedURLException  if no protocol is specified, or an
jtulach@120
   425
     *               unknown protocol is found, or <tt>spec</tt> is <tt>null</tt>.
jtulach@120
   426
     * @see        java.net.URL#URL(java.net.URL, java.lang.String)
jtulach@120
   427
     */
jtulach@120
   428
    public URL(String spec) throws MalformedURLException {
jtulach@120
   429
        this(null, spec);
jtulach@120
   430
    }
jtulach@120
   431
jtulach@120
   432
    /**
jtulach@120
   433
     * Creates a URL by parsing the given spec within a specified context.
jtulach@120
   434
     *
jtulach@120
   435
     * The new URL is created from the given context URL and the spec
jtulach@120
   436
     * argument as described in
jtulach@120
   437
     * RFC2396 &quot;Uniform Resource Identifiers : Generic * Syntax&quot; :
jtulach@120
   438
     * <blockquote><pre>
jtulach@120
   439
     *          &lt;scheme&gt;://&lt;authority&gt;&lt;path&gt;?&lt;query&gt;#&lt;fragment&gt;
jtulach@120
   440
     * </pre></blockquote>
jtulach@120
   441
     * The reference is parsed into the scheme, authority, path, query and
jtulach@120
   442
     * fragment parts. If the path component is empty and the scheme,
jtulach@120
   443
     * authority, and query components are undefined, then the new URL is a
jtulach@120
   444
     * reference to the current document. Otherwise, the fragment and query
jtulach@120
   445
     * parts present in the spec are used in the new URL.
jtulach@120
   446
     * <p>
jtulach@120
   447
     * If the scheme component is defined in the given spec and does not match
jtulach@120
   448
     * the scheme of the context, then the new URL is created as an absolute
jtulach@120
   449
     * URL based on the spec alone. Otherwise the scheme component is inherited
jtulach@120
   450
     * from the context URL.
jtulach@120
   451
     * <p>
jtulach@120
   452
     * If the authority component is present in the spec then the spec is
jtulach@120
   453
     * treated as absolute and the spec authority and path will replace the
jtulach@120
   454
     * context authority and path. If the authority component is absent in the
jtulach@120
   455
     * spec then the authority of the new URL will be inherited from the
jtulach@120
   456
     * context.
jtulach@120
   457
     * <p>
jtulach@120
   458
     * If the spec's path component begins with a slash character
jtulach@120
   459
     * &quot;/&quot; then the
jtulach@120
   460
     * path is treated as absolute and the spec path replaces the context path.
jtulach@120
   461
     * <p>
jtulach@120
   462
     * Otherwise, the path is treated as a relative path and is appended to the
jtulach@120
   463
     * context path, as described in RFC2396. Also, in this case,
jtulach@120
   464
     * the path is canonicalized through the removal of directory
jtulach@120
   465
     * changes made by occurences of &quot;..&quot; and &quot;.&quot;.
jtulach@120
   466
     * <p>
jtulach@120
   467
     * For a more detailed description of URL parsing, refer to RFC2396.
jtulach@120
   468
     *
jtulach@120
   469
     * @param      context   the context in which to parse the specification.
jtulach@120
   470
     * @param      spec      the <code>String</code> to parse as a URL.
jtulach@120
   471
     * @exception  MalformedURLException  if no protocol is specified, or an
jtulach@120
   472
     *               unknown protocol is found, or <tt>spec</tt> is <tt>null</tt>.
jtulach@120
   473
     * @see        java.net.URL#URL(java.lang.String, java.lang.String,
jtulach@120
   474
     *                  int, java.lang.String)
jtulach@120
   475
     * @see        java.net.URLStreamHandler
jtulach@120
   476
     * @see        java.net.URLStreamHandler#parseURL(java.net.URL,
jtulach@120
   477
     *                  java.lang.String, int, int)
jtulach@120
   478
     */
jtulach@120
   479
    public URL(URL context, String spec) throws MalformedURLException {
jtulach@120
   480
        this(context, spec, null);
jtulach@120
   481
    }
jtulach@120
   482
jtulach@120
   483
    /**
jtulach@120
   484
     * Creates a URL by parsing the given spec with the specified handler
jtulach@120
   485
     * within a specified context. If the handler is null, the parsing
jtulach@120
   486
     * occurs as with the two argument constructor.
jtulach@120
   487
     *
jtulach@120
   488
     * @param      context   the context in which to parse the specification.
jtulach@120
   489
     * @param      spec      the <code>String</code> to parse as a URL.
jtulach@120
   490
     * @param      handler   the stream handler for the URL.
jtulach@120
   491
     * @exception  MalformedURLException  if no protocol is specified, or an
jtulach@120
   492
     *               unknown protocol is found, or <tt>spec</tt> is <tt>null</tt>.
jtulach@120
   493
     * @exception  SecurityException
jtulach@120
   494
     *        if a security manager exists and its
jtulach@120
   495
     *        <code>checkPermission</code> method doesn't allow
jtulach@120
   496
     *        specifying a stream handler.
jtulach@120
   497
     * @see        java.net.URL#URL(java.lang.String, java.lang.String,
jtulach@120
   498
     *                  int, java.lang.String)
jtulach@120
   499
     * @see        java.net.URLStreamHandler
jtulach@120
   500
     * @see        java.net.URLStreamHandler#parseURL(java.net.URL,
jtulach@120
   501
     *                  java.lang.String, int, int)
jtulach@120
   502
     */
jtulach@120
   503
    public URL(URL context, String spec, URLStreamHandler handler)
jtulach@120
   504
        throws MalformedURLException
jtulach@120
   505
    {
jtulach@120
   506
        String original = spec;
jtulach@120
   507
        int i, limit, c;
jtulach@120
   508
        int start = 0;
jtulach@120
   509
        String newProtocol = null;
jtulach@120
   510
        boolean aRef=false;
jtulach@120
   511
        boolean isRelative = false;
jtulach@120
   512
jtulach@120
   513
        // Check for permission to specify a handler
jtulach@120
   514
        if (handler != null) {
jtulach@120
   515
            SecurityManager sm = System.getSecurityManager();
jtulach@120
   516
            if (sm != null) {
jtulach@120
   517
                checkSpecifyHandler(sm);
jtulach@120
   518
            }
jtulach@120
   519
        }
jtulach@120
   520
jtulach@120
   521
        try {
jtulach@120
   522
            limit = spec.length();
jtulach@120
   523
            while ((limit > 0) && (spec.charAt(limit - 1) <= ' ')) {
jtulach@120
   524
                limit--;        //eliminate trailing whitespace
jtulach@120
   525
            }
jtulach@120
   526
            while ((start < limit) && (spec.charAt(start) <= ' ')) {
jtulach@120
   527
                start++;        // eliminate leading whitespace
jtulach@120
   528
            }
jtulach@120
   529
jtulach@120
   530
            if (spec.regionMatches(true, start, "url:", 0, 4)) {
jtulach@120
   531
                start += 4;
jtulach@120
   532
            }
jtulach@120
   533
            if (start < spec.length() && spec.charAt(start) == '#') {
jtulach@120
   534
                /* we're assuming this is a ref relative to the context URL.
jtulach@120
   535
                 * This means protocols cannot start w/ '#', but we must parse
jtulach@120
   536
                 * ref URL's like: "hello:there" w/ a ':' in them.
jtulach@120
   537
                 */
jtulach@120
   538
                aRef=true;
jtulach@120
   539
            }
jtulach@120
   540
            for (i = start ; !aRef && (i < limit) &&
jtulach@120
   541
                     ((c = spec.charAt(i)) != '/') ; i++) {
jtulach@120
   542
                if (c == ':') {
jtulach@120
   543
jtulach@120
   544
                    String s = spec.substring(start, i).toLowerCase();
jtulach@120
   545
                    if (isValidProtocol(s)) {
jtulach@120
   546
                        newProtocol = s;
jtulach@120
   547
                        start = i + 1;
jtulach@120
   548
                    }
jtulach@120
   549
                    break;
jtulach@120
   550
                }
jtulach@120
   551
            }
jtulach@120
   552
jtulach@120
   553
            // Only use our context if the protocols match.
jtulach@120
   554
            protocol = newProtocol;
jtulach@120
   555
            if ((context != null) && ((newProtocol == null) ||
jtulach@120
   556
                            newProtocol.equalsIgnoreCase(context.protocol))) {
jtulach@120
   557
                // inherit the protocol handler from the context
jtulach@120
   558
                // if not specified to the constructor
jtulach@120
   559
                if (handler == null) {
jtulach@120
   560
                    handler = context.handler;
jtulach@120
   561
                }
jtulach@120
   562
jtulach@120
   563
                // If the context is a hierarchical URL scheme and the spec
jtulach@120
   564
                // contains a matching scheme then maintain backwards
jtulach@120
   565
                // compatibility and treat it as if the spec didn't contain
jtulach@120
   566
                // the scheme; see 5.2.3 of RFC2396
jtulach@120
   567
                if (context.path != null && context.path.startsWith("/"))
jtulach@120
   568
                    newProtocol = null;
jtulach@120
   569
jtulach@120
   570
                if (newProtocol == null) {
jtulach@120
   571
                    protocol = context.protocol;
jtulach@120
   572
                    authority = context.authority;
jtulach@120
   573
                    userInfo = context.userInfo;
jtulach@120
   574
                    host = context.host;
jtulach@120
   575
                    port = context.port;
jtulach@120
   576
                    file = context.file;
jtulach@120
   577
                    path = context.path;
jtulach@120
   578
                    isRelative = true;
jtulach@120
   579
                }
jtulach@120
   580
            }
jtulach@120
   581
jtulach@120
   582
            if (protocol == null) {
jtulach@120
   583
                throw new MalformedURLException("no protocol: "+original);
jtulach@120
   584
            }
jtulach@120
   585
jtulach@120
   586
            // Get the protocol handler if not specified or the protocol
jtulach@120
   587
            // of the context could not be used
jtulach@120
   588
            if (handler == null &&
jtulach@120
   589
                (handler = getURLStreamHandler(protocol)) == null) {
jtulach@120
   590
                throw new MalformedURLException("unknown protocol: "+protocol);
jtulach@120
   591
            }
jtulach@120
   592
jtulach@120
   593
            this.handler = handler;
jtulach@120
   594
jtulach@120
   595
            i = spec.indexOf('#', start);
jtulach@120
   596
            if (i >= 0) {
jtulach@120
   597
                ref = spec.substring(i + 1, limit);
jtulach@120
   598
                limit = i;
jtulach@120
   599
            }
jtulach@120
   600
jtulach@120
   601
            /*
jtulach@120
   602
             * Handle special case inheritance of query and fragment
jtulach@120
   603
             * implied by RFC2396 section 5.2.2.
jtulach@120
   604
             */
jtulach@120
   605
            if (isRelative && start == limit) {
jtulach@120
   606
                query = context.query;
jtulach@120
   607
                if (ref == null) {
jtulach@120
   608
                    ref = context.ref;
jtulach@120
   609
                }
jtulach@120
   610
            }
jtulach@120
   611
jtulach@120
   612
            handler.parseURL(this, spec, start, limit);
jtulach@120
   613
jtulach@120
   614
        } catch(MalformedURLException e) {
jtulach@120
   615
            throw e;
jtulach@120
   616
        } catch(Exception e) {
jtulach@120
   617
            MalformedURLException exception = new MalformedURLException(e.getMessage());
jtulach@120
   618
            exception.initCause(e);
jtulach@120
   619
            throw exception;
jtulach@120
   620
        }
jtulach@120
   621
    }
jtulach@120
   622
jtulach@120
   623
    /*
jtulach@120
   624
     * Returns true if specified string is a valid protocol name.
jtulach@120
   625
     */
jtulach@120
   626
    private boolean isValidProtocol(String protocol) {
jtulach@120
   627
        int len = protocol.length();
jtulach@120
   628
        if (len < 1)
jtulach@120
   629
            return false;
jtulach@120
   630
        char c = protocol.charAt(0);
jtulach@120
   631
        if (!Character.isLetter(c))
jtulach@120
   632
            return false;
jtulach@120
   633
        for (int i = 1; i < len; i++) {
jtulach@120
   634
            c = protocol.charAt(i);
jtulach@120
   635
            if (!Character.isLetterOrDigit(c) && c != '.' && c != '+' &&
jtulach@120
   636
                c != '-') {
jtulach@120
   637
                return false;
jtulach@120
   638
            }
jtulach@120
   639
        }
jtulach@120
   640
        return true;
jtulach@120
   641
    }
jtulach@120
   642
jtulach@120
   643
    /*
jtulach@120
   644
     * Checks for permission to specify a stream handler.
jtulach@120
   645
     */
jtulach@120
   646
    private void checkSpecifyHandler(SecurityManager sm) {
jtulach@120
   647
        sm.checkPermission(SecurityConstants.SPECIFY_HANDLER_PERMISSION);
jtulach@120
   648
    }
jtulach@120
   649
jtulach@120
   650
    /**
jtulach@120
   651
     * Sets the fields of the URL. This is not a public method so that
jtulach@120
   652
     * only URLStreamHandlers can modify URL fields. URLs are
jtulach@120
   653
     * otherwise constant.
jtulach@120
   654
     *
jtulach@120
   655
     * @param protocol the name of the protocol to use
jtulach@120
   656
     * @param host the name of the host
jtulach@120
   657
       @param port the port number on the host
jtulach@120
   658
     * @param file the file on the host
jtulach@120
   659
     * @param ref the internal reference in the URL
jtulach@120
   660
     */
jtulach@120
   661
    protected void set(String protocol, String host,
jtulach@120
   662
                       int port, String file, String ref) {
jtulach@120
   663
        synchronized (this) {
jtulach@120
   664
            this.protocol = protocol;
jtulach@120
   665
            this.host = host;
jtulach@120
   666
            authority = port == -1 ? host : host + ":" + port;
jtulach@120
   667
            this.port = port;
jtulach@120
   668
            this.file = file;
jtulach@120
   669
            this.ref = ref;
jtulach@120
   670
            /* This is very important. We must recompute this after the
jtulach@120
   671
             * URL has been changed. */
jtulach@120
   672
            hashCode = -1;
jtulach@120
   673
            hostAddress = null;
jtulach@120
   674
            int q = file.lastIndexOf('?');
jtulach@120
   675
            if (q != -1) {
jtulach@120
   676
                query = file.substring(q+1);
jtulach@120
   677
                path = file.substring(0, q);
jtulach@120
   678
            } else
jtulach@120
   679
                path = file;
jtulach@120
   680
        }
jtulach@120
   681
    }
jtulach@120
   682
jtulach@120
   683
    /**
jtulach@120
   684
     * Sets the specified 8 fields of the URL. This is not a public method so
jtulach@120
   685
     * that only URLStreamHandlers can modify URL fields. URLs are otherwise
jtulach@120
   686
     * constant.
jtulach@120
   687
     *
jtulach@120
   688
     * @param protocol the name of the protocol to use
jtulach@120
   689
     * @param host the name of the host
jtulach@120
   690
     * @param port the port number on the host
jtulach@120
   691
     * @param authority the authority part for the url
jtulach@120
   692
     * @param userInfo the username and password
jtulach@120
   693
     * @param path the file on the host
jtulach@120
   694
     * @param ref the internal reference in the URL
jtulach@120
   695
     * @param query the query part of this URL
jtulach@120
   696
     * @since 1.3
jtulach@120
   697
     */
jtulach@120
   698
    protected void set(String protocol, String host, int port,
jtulach@120
   699
                       String authority, String userInfo, String path,
jtulach@120
   700
                       String query, String ref) {
jtulach@120
   701
        synchronized (this) {
jtulach@120
   702
            this.protocol = protocol;
jtulach@120
   703
            this.host = host;
jtulach@120
   704
            this.port = port;
jtulach@120
   705
            this.file = query == null ? path : path + "?" + query;
jtulach@120
   706
            this.userInfo = userInfo;
jtulach@120
   707
            this.path = path;
jtulach@120
   708
            this.ref = ref;
jtulach@120
   709
            /* This is very important. We must recompute this after the
jtulach@120
   710
             * URL has been changed. */
jtulach@120
   711
            hashCode = -1;
jtulach@120
   712
            hostAddress = null;
jtulach@120
   713
            this.query = query;
jtulach@120
   714
            this.authority = authority;
jtulach@120
   715
        }
jtulach@120
   716
    }
jtulach@120
   717
jtulach@120
   718
    /**
jtulach@120
   719
     * Gets the query part of this <code>URL</code>.
jtulach@120
   720
     *
jtulach@120
   721
     * @return  the query part of this <code>URL</code>,
jtulach@120
   722
     * or <CODE>null</CODE> if one does not exist
jtulach@120
   723
     * @since 1.3
jtulach@120
   724
     */
jtulach@120
   725
    public String getQuery() {
jtulach@120
   726
        return query;
jtulach@120
   727
    }
jtulach@120
   728
jtulach@120
   729
    /**
jtulach@120
   730
     * Gets the path part of this <code>URL</code>.
jtulach@120
   731
     *
jtulach@120
   732
     * @return  the path part of this <code>URL</code>, or an
jtulach@120
   733
     * empty string if one does not exist
jtulach@120
   734
     * @since 1.3
jtulach@120
   735
     */
jtulach@120
   736
    public String getPath() {
jtulach@120
   737
        return path;
jtulach@120
   738
    }
jtulach@120
   739
jtulach@120
   740
    /**
jtulach@120
   741
     * Gets the userInfo part of this <code>URL</code>.
jtulach@120
   742
     *
jtulach@120
   743
     * @return  the userInfo part of this <code>URL</code>, or
jtulach@120
   744
     * <CODE>null</CODE> if one does not exist
jtulach@120
   745
     * @since 1.3
jtulach@120
   746
     */
jtulach@120
   747
    public String getUserInfo() {
jtulach@120
   748
        return userInfo;
jtulach@120
   749
    }
jtulach@120
   750
jtulach@120
   751
    /**
jtulach@120
   752
     * Gets the authority part of this <code>URL</code>.
jtulach@120
   753
     *
jtulach@120
   754
     * @return  the authority part of this <code>URL</code>
jtulach@120
   755
     * @since 1.3
jtulach@120
   756
     */
jtulach@120
   757
    public String getAuthority() {
jtulach@120
   758
        return authority;
jtulach@120
   759
    }
jtulach@120
   760
jtulach@120
   761
    /**
jtulach@120
   762
     * Gets the port number of this <code>URL</code>.
jtulach@120
   763
     *
jtulach@120
   764
     * @return  the port number, or -1 if the port is not set
jtulach@120
   765
     */
jtulach@120
   766
    public int getPort() {
jtulach@120
   767
        return port;
jtulach@120
   768
    }
jtulach@120
   769
jtulach@120
   770
    /**
jtulach@120
   771
     * Gets the default port number of the protocol associated
jtulach@120
   772
     * with this <code>URL</code>. If the URL scheme or the URLStreamHandler
jtulach@120
   773
     * for the URL do not define a default port number,
jtulach@120
   774
     * then -1 is returned.
jtulach@120
   775
     *
jtulach@120
   776
     * @return  the port number
jtulach@120
   777
     * @since 1.4
jtulach@120
   778
     */
jtulach@120
   779
    public int getDefaultPort() {
jtulach@120
   780
        return handler.getDefaultPort();
jtulach@120
   781
    }
jtulach@120
   782
jtulach@120
   783
    /**
jtulach@120
   784
     * Gets the protocol name of this <code>URL</code>.
jtulach@120
   785
     *
jtulach@120
   786
     * @return  the protocol of this <code>URL</code>.
jtulach@120
   787
     */
jtulach@120
   788
    public String getProtocol() {
jtulach@120
   789
        return protocol;
jtulach@120
   790
    }
jtulach@120
   791
jtulach@120
   792
    /**
jtulach@120
   793
     * Gets the host name of this <code>URL</code>, if applicable.
jtulach@120
   794
     * The format of the host conforms to RFC 2732, i.e. for a
jtulach@120
   795
     * literal IPv6 address, this method will return the IPv6 address
jtulach@120
   796
     * enclosed in square brackets (<tt>'['</tt> and <tt>']'</tt>).
jtulach@120
   797
     *
jtulach@120
   798
     * @return  the host name of this <code>URL</code>.
jtulach@120
   799
     */
jtulach@120
   800
    public String getHost() {
jtulach@120
   801
        return host;
jtulach@120
   802
    }
jtulach@120
   803
jtulach@120
   804
    /**
jtulach@120
   805
     * Gets the file name of this <code>URL</code>.
jtulach@120
   806
     * The returned file portion will be
jtulach@120
   807
     * the same as <CODE>getPath()</CODE>, plus the concatenation of
jtulach@120
   808
     * the value of <CODE>getQuery()</CODE>, if any. If there is
jtulach@120
   809
     * no query portion, this method and <CODE>getPath()</CODE> will
jtulach@120
   810
     * return identical results.
jtulach@120
   811
     *
jtulach@120
   812
     * @return  the file name of this <code>URL</code>,
jtulach@120
   813
     * or an empty string if one does not exist
jtulach@120
   814
     */
jtulach@120
   815
    public String getFile() {
jtulach@120
   816
        return file;
jtulach@120
   817
    }
jtulach@120
   818
jtulach@120
   819
    /**
jtulach@120
   820
     * Gets the anchor (also known as the "reference") of this
jtulach@120
   821
     * <code>URL</code>.
jtulach@120
   822
     *
jtulach@120
   823
     * @return  the anchor (also known as the "reference") of this
jtulach@120
   824
     *          <code>URL</code>, or <CODE>null</CODE> if one does not exist
jtulach@120
   825
     */
jtulach@120
   826
    public String getRef() {
jtulach@120
   827
        return ref;
jtulach@120
   828
    }
jtulach@120
   829
jtulach@120
   830
    /**
jtulach@120
   831
     * Compares this URL for equality with another object.<p>
jtulach@120
   832
     *
jtulach@120
   833
     * If the given object is not a URL then this method immediately returns
jtulach@120
   834
     * <code>false</code>.<p>
jtulach@120
   835
     *
jtulach@120
   836
     * Two URL objects are equal if they have the same protocol, reference
jtulach@120
   837
     * equivalent hosts, have the same port number on the host, and the same
jtulach@120
   838
     * file and fragment of the file.<p>
jtulach@120
   839
     *
jtulach@120
   840
     * Two hosts are considered equivalent if both host names can be resolved
jtulach@120
   841
     * into the same IP addresses; else if either host name can't be
jtulach@120
   842
     * resolved, the host names must be equal without regard to case; or both
jtulach@120
   843
     * host names equal to null.<p>
jtulach@120
   844
     *
jtulach@120
   845
     * Since hosts comparison requires name resolution, this operation is a
jtulach@120
   846
     * blocking operation. <p>
jtulach@120
   847
     *
jtulach@120
   848
     * Note: The defined behavior for <code>equals</code> is known to
jtulach@120
   849
     * be inconsistent with virtual hosting in HTTP.
jtulach@120
   850
     *
jtulach@120
   851
     * @param   obj   the URL to compare against.
jtulach@120
   852
     * @return  <code>true</code> if the objects are the same;
jtulach@120
   853
     *          <code>false</code> otherwise.
jtulach@120
   854
     */
jtulach@120
   855
    public boolean equals(Object obj) {
jtulach@120
   856
        if (!(obj instanceof URL))
jtulach@120
   857
            return false;
jtulach@120
   858
        URL u2 = (URL)obj;
jtulach@120
   859
jtulach@120
   860
        return handler.equals(this, u2);
jtulach@120
   861
    }
jtulach@120
   862
jtulach@120
   863
    /**
jtulach@120
   864
     * Creates an integer suitable for hash table indexing.<p>
jtulach@120
   865
     *
jtulach@120
   866
     * The hash code is based upon all the URL components relevant for URL
jtulach@120
   867
     * comparison. As such, this operation is a blocking operation.<p>
jtulach@120
   868
     *
jtulach@120
   869
     * @return  a hash code for this <code>URL</code>.
jtulach@120
   870
     */
jtulach@120
   871
    public synchronized int hashCode() {
jtulach@120
   872
        if (hashCode != -1)
jtulach@120
   873
            return hashCode;
jtulach@120
   874
jtulach@120
   875
        hashCode = handler.hashCode(this);
jtulach@120
   876
        return hashCode;
jtulach@120
   877
    }
jtulach@120
   878
jtulach@120
   879
    /**
jtulach@120
   880
     * Compares two URLs, excluding the fragment component.<p>
jtulach@120
   881
     *
jtulach@120
   882
     * Returns <code>true</code> if this <code>URL</code> and the
jtulach@120
   883
     * <code>other</code> argument are equal without taking the
jtulach@120
   884
     * fragment component into consideration.
jtulach@120
   885
     *
jtulach@120
   886
     * @param   other   the <code>URL</code> to compare against.
jtulach@120
   887
     * @return  <code>true</code> if they reference the same remote object;
jtulach@120
   888
     *          <code>false</code> otherwise.
jtulach@120
   889
     */
jtulach@120
   890
    public boolean sameFile(URL other) {
jtulach@120
   891
        return handler.sameFile(this, other);
jtulach@120
   892
    }
jtulach@120
   893
jtulach@120
   894
    /**
jtulach@120
   895
     * Constructs a string representation of this <code>URL</code>. The
jtulach@120
   896
     * string is created by calling the <code>toExternalForm</code>
jtulach@120
   897
     * method of the stream protocol handler for this object.
jtulach@120
   898
     *
jtulach@120
   899
     * @return  a string representation of this object.
jtulach@120
   900
     * @see     java.net.URL#URL(java.lang.String, java.lang.String, int,
jtulach@120
   901
     *                  java.lang.String)
jtulach@120
   902
     * @see     java.net.URLStreamHandler#toExternalForm(java.net.URL)
jtulach@120
   903
     */
jtulach@120
   904
    public String toString() {
jtulach@120
   905
        return toExternalForm();
jtulach@120
   906
    }
jtulach@120
   907
jtulach@120
   908
    /**
jtulach@120
   909
     * Constructs a string representation of this <code>URL</code>. The
jtulach@120
   910
     * string is created by calling the <code>toExternalForm</code>
jtulach@120
   911
     * method of the stream protocol handler for this object.
jtulach@120
   912
     *
jtulach@120
   913
     * @return  a string representation of this object.
jtulach@120
   914
     * @see     java.net.URL#URL(java.lang.String, java.lang.String,
jtulach@120
   915
     *                  int, java.lang.String)
jtulach@120
   916
     * @see     java.net.URLStreamHandler#toExternalForm(java.net.URL)
jtulach@120
   917
     */
jtulach@120
   918
    public String toExternalForm() {
jtulach@120
   919
        return handler.toExternalForm(this);
jtulach@120
   920
    }
jtulach@120
   921
jtulach@120
   922
    /**
jtulach@120
   923
     * Returns a {@link java.net.URI} equivalent to this URL.
jtulach@120
   924
     * This method functions in the same way as <code>new URI (this.toString())</code>.
jtulach@120
   925
     * <p>Note, any URL instance that complies with RFC 2396 can be converted
jtulach@120
   926
     * to a URI. However, some URLs that are not strictly in compliance
jtulach@120
   927
     * can not be converted to a URI.
jtulach@120
   928
     *
jtulach@120
   929
     * @exception URISyntaxException if this URL is not formatted strictly according to
jtulach@120
   930
     *            to RFC2396 and cannot be converted to a URI.
jtulach@120
   931
     *
jtulach@120
   932
     * @return    a URI instance equivalent to this URL.
jtulach@120
   933
     * @since 1.5
jtulach@120
   934
     */
jtulach@120
   935
    public URI toURI() throws URISyntaxException {
jtulach@120
   936
        return new URI (toString());
jtulach@120
   937
    }
jtulach@120
   938
jtulach@120
   939
    /**
jtulach@120
   940
     * Returns a {@link java.net.URLConnection URLConnection} instance that
jtulach@120
   941
     * represents a connection to the remote object referred to by the
jtulach@120
   942
     * {@code URL}.
jtulach@120
   943
     *
jtulach@120
   944
     * <P>A new instance of {@linkplain java.net.URLConnection URLConnection} is
jtulach@120
   945
     * created every time when invoking the
jtulach@120
   946
     * {@linkplain java.net.URLStreamHandler#openConnection(URL)
jtulach@120
   947
     * URLStreamHandler.openConnection(URL)} method of the protocol handler for
jtulach@120
   948
     * this URL.</P>
jtulach@120
   949
     *
jtulach@120
   950
     * <P>It should be noted that a URLConnection instance does not establish
jtulach@120
   951
     * the actual network connection on creation. This will happen only when
jtulach@120
   952
     * calling {@linkplain java.net.URLConnection#connect() URLConnection.connect()}.</P>
jtulach@120
   953
     *
jtulach@120
   954
     * <P>If for the URL's protocol (such as HTTP or JAR), there
jtulach@120
   955
     * exists a public, specialized URLConnection subclass belonging
jtulach@120
   956
     * to one of the following packages or one of their subpackages:
jtulach@120
   957
     * java.lang, java.io, java.util, java.net, the connection
jtulach@120
   958
     * returned will be of that subclass. For example, for HTTP an
jtulach@120
   959
     * HttpURLConnection will be returned, and for JAR a
jtulach@120
   960
     * JarURLConnection will be returned.</P>
jtulach@120
   961
     *
jtulach@120
   962
     * @return     a {@link java.net.URLConnection URLConnection} linking
jtulach@120
   963
     *             to the URL.
jtulach@120
   964
     * @exception  IOException  if an I/O exception occurs.
jtulach@120
   965
     * @see        java.net.URL#URL(java.lang.String, java.lang.String,
jtulach@120
   966
     *             int, java.lang.String)
jtulach@120
   967
     */
jtulach@120
   968
    public URLConnection openConnection() throws java.io.IOException {
jtulach@120
   969
        return handler.openConnection(this);
jtulach@120
   970
    }
jtulach@120
   971
jtulach@120
   972
    /**
jtulach@120
   973
     * Same as {@link #openConnection()}, except that the connection will be
jtulach@120
   974
     * made through the specified proxy; Protocol handlers that do not
jtulach@120
   975
     * support proxing will ignore the proxy parameter and make a
jtulach@120
   976
     * normal connection.
jtulach@120
   977
     *
jtulach@120
   978
     * Invoking this method preempts the system's default ProxySelector
jtulach@120
   979
     * settings.
jtulach@120
   980
     *
jtulach@120
   981
     * @param      proxy the Proxy through which this connection
jtulach@120
   982
     *             will be made. If direct connection is desired,
jtulach@120
   983
     *             Proxy.NO_PROXY should be specified.
jtulach@120
   984
     * @return     a <code>URLConnection</code> to the URL.
jtulach@120
   985
     * @exception  IOException  if an I/O exception occurs.
jtulach@120
   986
     * @exception  SecurityException if a security manager is present
jtulach@120
   987
     *             and the caller doesn't have permission to connect
jtulach@120
   988
     *             to the proxy.
jtulach@120
   989
     * @exception  IllegalArgumentException will be thrown if proxy is null,
jtulach@120
   990
     *             or proxy has the wrong type
jtulach@120
   991
     * @exception  UnsupportedOperationException if the subclass that
jtulach@120
   992
     *             implements the protocol handler doesn't support
jtulach@120
   993
     *             this method.
jtulach@120
   994
     * @see        java.net.URL#URL(java.lang.String, java.lang.String,
jtulach@120
   995
     *             int, java.lang.String)
jtulach@120
   996
     * @see        java.net.URLConnection
jtulach@120
   997
     * @see        java.net.URLStreamHandler#openConnection(java.net.URL,
jtulach@120
   998
     *             java.net.Proxy)
jtulach@120
   999
     * @since      1.5
jtulach@120
  1000
     */
jtulach@120
  1001
    public URLConnection openConnection(Proxy proxy)
jtulach@120
  1002
        throws java.io.IOException {
jtulach@120
  1003
        if (proxy == null) {
jtulach@120
  1004
            throw new IllegalArgumentException("proxy can not be null");
jtulach@120
  1005
        }
jtulach@120
  1006
jtulach@120
  1007
        // Create a copy of Proxy as a security measure
jtulach@120
  1008
        Proxy p = proxy == Proxy.NO_PROXY ? Proxy.NO_PROXY : sun.net.ApplicationProxy.create(proxy);
jtulach@120
  1009
        SecurityManager sm = System.getSecurityManager();
jtulach@120
  1010
        if (p.type() != Proxy.Type.DIRECT && sm != null) {
jtulach@120
  1011
            InetSocketAddress epoint = (InetSocketAddress) p.address();
jtulach@120
  1012
            if (epoint.isUnresolved())
jtulach@120
  1013
                sm.checkConnect(epoint.getHostName(), epoint.getPort());
jtulach@120
  1014
            else
jtulach@120
  1015
                sm.checkConnect(epoint.getAddress().getHostAddress(),
jtulach@120
  1016
                                epoint.getPort());
jtulach@120
  1017
        }
jtulach@120
  1018
        return handler.openConnection(this, p);
jtulach@120
  1019
    }
jtulach@120
  1020
jtulach@120
  1021
    /**
jtulach@120
  1022
     * Opens a connection to this <code>URL</code> and returns an
jtulach@120
  1023
     * <code>InputStream</code> for reading from that connection. This
jtulach@120
  1024
     * method is a shorthand for:
jtulach@120
  1025
     * <blockquote><pre>
jtulach@120
  1026
     *     openConnection().getInputStream()
jtulach@120
  1027
     * </pre></blockquote>
jtulach@120
  1028
     *
jtulach@120
  1029
     * @return     an input stream for reading from the URL connection.
jtulach@120
  1030
     * @exception  IOException  if an I/O exception occurs.
jtulach@120
  1031
     * @see        java.net.URL#openConnection()
jtulach@120
  1032
     * @see        java.net.URLConnection#getInputStream()
jtulach@120
  1033
     */
jtulach@120
  1034
    public final InputStream openStream() throws java.io.IOException {
jtulach@120
  1035
        return openConnection().getInputStream();
jtulach@120
  1036
    }
jtulach@120
  1037
jtulach@120
  1038
    /**
jtulach@120
  1039
     * Gets the contents of this URL. This method is a shorthand for:
jtulach@120
  1040
     * <blockquote><pre>
jtulach@120
  1041
     *     openConnection().getContent()
jtulach@120
  1042
     * </pre></blockquote>
jtulach@120
  1043
     *
jtulach@120
  1044
     * @return     the contents of this URL.
jtulach@120
  1045
     * @exception  IOException  if an I/O exception occurs.
jtulach@120
  1046
     * @see        java.net.URLConnection#getContent()
jtulach@120
  1047
     */
jtulach@120
  1048
    public final Object getContent() throws java.io.IOException {
jtulach@120
  1049
        return openConnection().getContent();
jtulach@120
  1050
    }
jtulach@120
  1051
jtulach@120
  1052
    /**
jtulach@120
  1053
     * Gets the contents of this URL. This method is a shorthand for:
jtulach@120
  1054
     * <blockquote><pre>
jtulach@120
  1055
     *     openConnection().getContent(Class[])
jtulach@120
  1056
     * </pre></blockquote>
jtulach@120
  1057
     *
jtulach@120
  1058
     * @param classes an array of Java types
jtulach@120
  1059
     * @return     the content object of this URL that is the first match of
jtulach@120
  1060
     *               the types specified in the classes array.
jtulach@120
  1061
     *               null if none of the requested types are supported.
jtulach@120
  1062
     * @exception  IOException  if an I/O exception occurs.
jtulach@120
  1063
     * @see        java.net.URLConnection#getContent(Class[])
jtulach@120
  1064
     * @since 1.3
jtulach@120
  1065
     */
jtulach@120
  1066
    public final Object getContent(Class[] classes)
jtulach@120
  1067
    throws java.io.IOException {
jtulach@120
  1068
        return openConnection().getContent(classes);
jtulach@120
  1069
    }
jtulach@120
  1070
jtulach@120
  1071
    /**
jtulach@120
  1072
     * The URLStreamHandler factory.
jtulach@120
  1073
     */
jtulach@120
  1074
    static URLStreamHandlerFactory factory;
jtulach@120
  1075
jtulach@120
  1076
    /**
jtulach@120
  1077
     * Sets an application's <code>URLStreamHandlerFactory</code>.
jtulach@120
  1078
     * This method can be called at most once in a given Java Virtual
jtulach@120
  1079
     * Machine.
jtulach@120
  1080
     *
jtulach@120
  1081
     *<p> The <code>URLStreamHandlerFactory</code> instance is used to
jtulach@120
  1082
     *construct a stream protocol handler from a protocol name.
jtulach@120
  1083
     *
jtulach@120
  1084
     * <p> If there is a security manager, this method first calls
jtulach@120
  1085
     * the security manager's <code>checkSetFactory</code> method
jtulach@120
  1086
     * to ensure the operation is allowed.
jtulach@120
  1087
     * This could result in a SecurityException.
jtulach@120
  1088
     *
jtulach@120
  1089
     * @param      fac   the desired factory.
jtulach@120
  1090
     * @exception  Error  if the application has already set a factory.
jtulach@120
  1091
     * @exception  SecurityException  if a security manager exists and its
jtulach@120
  1092
     *             <code>checkSetFactory</code> method doesn't allow
jtulach@120
  1093
     *             the operation.
jtulach@120
  1094
     * @see        java.net.URL#URL(java.lang.String, java.lang.String,
jtulach@120
  1095
     *             int, java.lang.String)
jtulach@120
  1096
     * @see        java.net.URLStreamHandlerFactory
jtulach@120
  1097
     * @see        SecurityManager#checkSetFactory
jtulach@120
  1098
     */
jtulach@120
  1099
    public static void setURLStreamHandlerFactory(URLStreamHandlerFactory fac) {
jtulach@120
  1100
        synchronized (streamHandlerLock) {
jtulach@120
  1101
            if (factory != null) {
jtulach@120
  1102
                throw new Error("factory already defined");
jtulach@120
  1103
            }
jtulach@120
  1104
            SecurityManager security = System.getSecurityManager();
jtulach@120
  1105
            if (security != null) {
jtulach@120
  1106
                security.checkSetFactory();
jtulach@120
  1107
            }
jtulach@120
  1108
            handlers.clear();
jtulach@120
  1109
            factory = fac;
jtulach@120
  1110
        }
jtulach@120
  1111
    }
jtulach@120
  1112
jtulach@120
  1113
    /**
jtulach@120
  1114
     * A table of protocol handlers.
jtulach@120
  1115
     */
jtulach@120
  1116
    static Hashtable handlers = new Hashtable();
jtulach@120
  1117
    private static Object streamHandlerLock = new Object();
jtulach@120
  1118
jtulach@120
  1119
    /**
jtulach@120
  1120
     * Returns the Stream Handler.
jtulach@120
  1121
     * @param protocol the protocol to use
jtulach@120
  1122
     */
jtulach@120
  1123
    static URLStreamHandler getURLStreamHandler(String protocol) {
jtulach@120
  1124
jtulach@120
  1125
        URLStreamHandler handler = (URLStreamHandler)handlers.get(protocol);
jtulach@120
  1126
        if (handler == null) {
jtulach@120
  1127
jtulach@120
  1128
            boolean checkedWithFactory = false;
jtulach@120
  1129
jtulach@120
  1130
            // Use the factory (if any)
jtulach@120
  1131
            if (factory != null) {
jtulach@120
  1132
                handler = factory.createURLStreamHandler(protocol);
jtulach@120
  1133
                checkedWithFactory = true;
jtulach@120
  1134
            }
jtulach@120
  1135
jtulach@120
  1136
            // Try java protocol handler
jtulach@120
  1137
            if (handler == null) {
jtulach@120
  1138
                String packagePrefixList = null;
jtulach@120
  1139
jtulach@120
  1140
                packagePrefixList
jtulach@120
  1141
                    = java.security.AccessController.doPrivileged(
jtulach@120
  1142
                    new sun.security.action.GetPropertyAction(
jtulach@120
  1143
                        protocolPathProp,""));
jtulach@120
  1144
                if (packagePrefixList != "") {
jtulach@120
  1145
                    packagePrefixList += "|";
jtulach@120
  1146
                }
jtulach@120
  1147
jtulach@120
  1148
                // REMIND: decide whether to allow the "null" class prefix
jtulach@120
  1149
                // or not.
jtulach@120
  1150
                packagePrefixList += "sun.net.www.protocol";
jtulach@120
  1151
jtulach@120
  1152
                StringTokenizer packagePrefixIter =
jtulach@120
  1153
                    new StringTokenizer(packagePrefixList, "|");
jtulach@120
  1154
jtulach@120
  1155
                while (handler == null &&
jtulach@120
  1156
                       packagePrefixIter.hasMoreTokens()) {
jtulach@120
  1157
jtulach@120
  1158
                    String packagePrefix =
jtulach@120
  1159
                      packagePrefixIter.nextToken().trim();
jtulach@120
  1160
                    try {
jtulach@120
  1161
                        String clsName = packagePrefix + "." + protocol +
jtulach@120
  1162
                          ".Handler";
jtulach@120
  1163
                        Class cls = null;
jtulach@120
  1164
                        try {
jtulach@120
  1165
                            cls = Class.forName(clsName);
jtulach@120
  1166
                        } catch (ClassNotFoundException e) {
jtulach@120
  1167
                            ClassLoader cl = ClassLoader.getSystemClassLoader();
jtulach@120
  1168
                            if (cl != null) {
jtulach@120
  1169
                                cls = cl.loadClass(clsName);
jtulach@120
  1170
                            }
jtulach@120
  1171
                        }
jtulach@120
  1172
                        if (cls != null) {
jtulach@120
  1173
                            handler  =
jtulach@120
  1174
                              (URLStreamHandler)cls.newInstance();
jtulach@120
  1175
                        }
jtulach@120
  1176
                    } catch (Exception e) {
jtulach@120
  1177
                        // any number of exceptions can get thrown here
jtulach@120
  1178
                    }
jtulach@120
  1179
                }
jtulach@120
  1180
            }
jtulach@120
  1181
jtulach@120
  1182
            synchronized (streamHandlerLock) {
jtulach@120
  1183
jtulach@120
  1184
                URLStreamHandler handler2 = null;
jtulach@120
  1185
jtulach@120
  1186
                // Check again with hashtable just in case another
jtulach@120
  1187
                // thread created a handler since we last checked
jtulach@120
  1188
                handler2 = (URLStreamHandler)handlers.get(protocol);
jtulach@120
  1189
jtulach@120
  1190
                if (handler2 != null) {
jtulach@120
  1191
                    return handler2;
jtulach@120
  1192
                }
jtulach@120
  1193
jtulach@120
  1194
                // Check with factory if another thread set a
jtulach@120
  1195
                // factory since our last check
jtulach@120
  1196
                if (!checkedWithFactory && factory != null) {
jtulach@120
  1197
                    handler2 = factory.createURLStreamHandler(protocol);
jtulach@120
  1198
                }
jtulach@120
  1199
jtulach@120
  1200
                if (handler2 != null) {
jtulach@120
  1201
                    // The handler from the factory must be given more
jtulach@120
  1202
                    // importance. Discard the default handler that
jtulach@120
  1203
                    // this thread created.
jtulach@120
  1204
                    handler = handler2;
jtulach@120
  1205
                }
jtulach@120
  1206
jtulach@120
  1207
                // Insert this handler into the hashtable
jtulach@120
  1208
                if (handler != null) {
jtulach@120
  1209
                    handlers.put(protocol, handler);
jtulach@120
  1210
                }
jtulach@120
  1211
jtulach@120
  1212
            }
jtulach@120
  1213
        }
jtulach@120
  1214
jtulach@120
  1215
        return handler;
jtulach@120
  1216
jtulach@120
  1217
    }
jtulach@120
  1218
jtulach@120
  1219
    /**
jtulach@120
  1220
     * WriteObject is called to save the state of the URL to an
jtulach@120
  1221
     * ObjectOutputStream. The handler is not saved since it is
jtulach@120
  1222
     * specific to this system.
jtulach@120
  1223
     *
jtulach@120
  1224
     * @serialData the default write object value. When read back in,
jtulach@120
  1225
     * the reader must ensure that calling getURLStreamHandler with
jtulach@120
  1226
     * the protocol variable returns a valid URLStreamHandler and
jtulach@120
  1227
     * throw an IOException if it does not.
jtulach@120
  1228
     */
jtulach@120
  1229
    private synchronized void writeObject(java.io.ObjectOutputStream s)
jtulach@120
  1230
        throws IOException
jtulach@120
  1231
    {
jtulach@120
  1232
        s.defaultWriteObject(); // write the fields
jtulach@120
  1233
    }
jtulach@120
  1234
jtulach@120
  1235
    /**
jtulach@120
  1236
     * readObject is called to restore the state of the URL from the
jtulach@120
  1237
     * stream.  It reads the components of the URL and finds the local
jtulach@120
  1238
     * stream handler.
jtulach@120
  1239
     */
jtulach@120
  1240
    private synchronized void readObject(java.io.ObjectInputStream s)
jtulach@120
  1241
         throws IOException, ClassNotFoundException
jtulach@120
  1242
    {
jtulach@120
  1243
        s.defaultReadObject();  // read the fields
jtulach@120
  1244
        if ((handler = getURLStreamHandler(protocol)) == null) {
jtulach@120
  1245
            throw new IOException("unknown protocol: " + protocol);
jtulach@120
  1246
        }
jtulach@120
  1247
jtulach@120
  1248
        // Construct authority part
jtulach@120
  1249
        if (authority == null &&
jtulach@120
  1250
            ((host != null && host.length() > 0) || port != -1)) {
jtulach@120
  1251
            if (host == null)
jtulach@120
  1252
                host = "";
jtulach@120
  1253
            authority = (port == -1) ? host : host + ":" + port;
jtulach@120
  1254
jtulach@120
  1255
            // Handle hosts with userInfo in them
jtulach@120
  1256
            int at = host.lastIndexOf('@');
jtulach@120
  1257
            if (at != -1) {
jtulach@120
  1258
                userInfo = host.substring(0, at);
jtulach@120
  1259
                host = host.substring(at+1);
jtulach@120
  1260
            }
jtulach@120
  1261
        } else if (authority != null) {
jtulach@120
  1262
            // Construct user info part
jtulach@120
  1263
            int ind = authority.indexOf('@');
jtulach@120
  1264
            if (ind != -1)
jtulach@120
  1265
                userInfo = authority.substring(0, ind);
jtulach@120
  1266
        }
jtulach@120
  1267
jtulach@120
  1268
        // Construct path and query part
jtulach@120
  1269
        path = null;
jtulach@120
  1270
        query = null;
jtulach@120
  1271
        if (file != null) {
jtulach@120
  1272
            // Fix: only do this if hierarchical?
jtulach@120
  1273
            int q = file.lastIndexOf('?');
jtulach@120
  1274
            if (q != -1) {
jtulach@120
  1275
                query = file.substring(q+1);
jtulach@120
  1276
                path = file.substring(0, q);
jtulach@120
  1277
            } else
jtulach@120
  1278
                path = file;
jtulach@120
  1279
        }
jtulach@120
  1280
    }
jtulach@120
  1281
}
jtulach@120
  1282
jtulach@120
  1283
class Parts {
jtulach@120
  1284
    String path, query, ref;
jtulach@120
  1285
jtulach@120
  1286
    Parts(String file) {
jtulach@120
  1287
        int ind = file.indexOf('#');
jtulach@120
  1288
        ref = ind < 0 ? null: file.substring(ind + 1);
jtulach@120
  1289
        file = ind < 0 ? file: file.substring(0, ind);
jtulach@120
  1290
        int q = file.lastIndexOf('?');
jtulach@120
  1291
        if (q != -1) {
jtulach@120
  1292
            query = file.substring(q+1);
jtulach@120
  1293
            path = file.substring(0, q);
jtulach@120
  1294
        } else {
jtulach@120
  1295
            path = file;
jtulach@120
  1296
        }
jtulach@120
  1297
    }
jtulach@120
  1298
jtulach@120
  1299
    String getPath() {
jtulach@120
  1300
        return path;
jtulach@120
  1301
    }
jtulach@120
  1302
jtulach@120
  1303
    String getQuery() {
jtulach@120
  1304
        return query;
jtulach@120
  1305
    }
jtulach@120
  1306
jtulach@120
  1307
    String getRef() {
jtulach@120
  1308
        return ref;
jtulach@120
  1309
    }
jtulach@120
  1310
}