1 |
/* URL.java -- Uniform Resource Locator Class |
/* URL.java -- Uniform Resource Locator Class |
2 |
Copyright (C) 1998, 1999, 2002 Free Software Foundation, Inc. |
Copyright (C) 1998, 1999, 2000, 2002 Free Software Foundation, Inc. |
3 |
|
|
4 |
This file is part of GNU Classpath. |
This file is part of GNU Classpath. |
5 |
|
|
43 |
import java.io.Serializable; |
import java.io.Serializable; |
44 |
import java.io.ObjectInputStream; |
import java.io.ObjectInputStream; |
45 |
import java.io.ObjectOutputStream; |
import java.io.ObjectOutputStream; |
|
import java.util.StringTokenizer; |
|
46 |
import java.util.Hashtable; |
import java.util.Hashtable; |
47 |
|
import java.util.StringTokenizer; |
48 |
|
|
49 |
|
|
50 |
|
/* |
51 |
|
* Written using on-line Java Platform 1.2 API Specification, as well |
52 |
|
* as "The Java Class Libraries", 2nd edition (Addison-Wesley, 1998). |
53 |
|
* Status: Believed complete and correct. |
54 |
|
*/ |
55 |
|
|
56 |
/** |
/** |
57 |
* This final class represents an Internet Uniform Resource Locator (URL). |
* This final class represents an Internet Uniform Resource Locator (URL). |
112 |
* done, then the above information is superseded and the behavior of this |
* done, then the above information is superseded and the behavior of this |
113 |
* class in loading protocol handlers is dependent on that factory. |
* class in loading protocol handlers is dependent on that factory. |
114 |
* |
* |
|
* @version 0.5 |
|
|
* |
|
115 |
* @author Aaron M. Renn (arenn@urbanophile.com) |
* @author Aaron M. Renn (arenn@urbanophile.com) |
116 |
|
* @author Warren Levy <warrenl@cygnus.com> |
117 |
* |
* |
118 |
* @see URLStreamHandler |
* @see URLStreamHandler |
119 |
*/ |
*/ |
120 |
public final class URL implements Serializable |
public final class URL implements Serializable |
121 |
{ |
{ |
122 |
|
/** |
123 |
|
* The name of the protocol for this URL. |
124 |
|
* The protocol is always stored in lower case. |
125 |
|
*/ |
126 |
|
private String protocol; |
127 |
|
|
128 |
/*************************************************************************/ |
/** |
129 |
|
* The "authority" portion of the URL. |
130 |
|
*/ |
131 |
|
private String authority; |
132 |
|
|
133 |
/* |
/** |
134 |
* Class Variables |
* The hostname or IP address of this protocol. |
135 |
*/ |
* This includes a possible user. For example <code>joe@some.host.net</code>. |
136 |
|
*/ |
137 |
|
private String host; |
138 |
|
|
139 |
private static final long serialVersionUID = -7627629688361524110L; |
/** |
140 |
|
* The port number of this protocol or -1 if the port number used is |
141 |
|
* the default for this protocol. |
142 |
|
*/ |
143 |
|
private int port = -1; // Initialize for constructor using context. |
144 |
|
|
145 |
/** |
/** |
146 |
* If an application installs in own protocol handler factory, this is |
* The "file" portion of the URL. It is defined as <code>path[?query]</code>. |
147 |
* where we keep track of it. |
*/ |
148 |
*/ |
private String file; |
149 |
private static URLStreamHandlerFactory factory; |
|
150 |
|
/** |
151 |
|
* The anchor portion of the URL. |
152 |
|
*/ |
153 |
|
private String ref; |
154 |
|
|
155 |
|
/** |
156 |
|
* This is the hashCode for this URL |
157 |
|
*/ |
158 |
|
private int hashCode = 0; |
159 |
|
|
160 |
|
/** |
161 |
|
* The protocol handler in use for this URL |
162 |
|
*/ |
163 |
|
transient private URLStreamHandler handler; |
164 |
|
|
165 |
|
/** |
166 |
|
* This a table where we cache protocol handlers to avoid the overhead |
167 |
|
* of looking them up each time. |
168 |
|
*/ |
169 |
|
private static Hashtable handlers = new Hashtable(); |
170 |
|
|
171 |
|
/** |
172 |
|
* If an application installs its own protocol handler factory, this is |
173 |
|
* where we keep track of it. |
174 |
|
*/ |
175 |
|
private static URLStreamHandlerFactory factory; |
176 |
|
|
177 |
|
private static final long serialVersionUID = -7627629688361524110L; |
178 |
|
|
179 |
/** |
/** |
180 |
* This a table where we cache protocol handlers to avoid the overhead |
* This a table where we cache protocol handlers to avoid the overhead |
188 |
private static boolean cache_handlers; |
private static boolean cache_handlers; |
189 |
|
|
190 |
/** |
/** |
191 |
* The search path of packages to search for protocol handlers in |
* The search path of packages to search for protocol handlers in. |
192 |
*/ |
*/ |
193 |
private static String ph_search_path; |
private static String ph_search_path; |
194 |
|
|
209 |
ph_search_path = "gnu.java.net.protocol"; |
ph_search_path = "gnu.java.net.protocol"; |
210 |
} |
} |
211 |
|
|
|
/*************************************************************************/ |
|
|
|
|
|
/* |
|
|
* Instance Variables |
|
|
*/ |
|
|
|
|
|
/** |
|
|
* The name of the protocol for this URL |
|
|
*/ |
|
|
private String protocol; |
|
|
|
|
|
/** |
|
|
* The hostname or IP address of this protocol |
|
|
*/ |
|
|
private String host; |
|
|
|
|
|
/** |
|
|
* The port number of this protocol or -1 if the port number used is |
|
|
* the default for this protocol. |
|
|
*/ |
|
|
private int port = -1; |
|
|
|
|
|
/** |
|
|
* The "file" portion of the URL |
|
|
*/ |
|
|
private String file; |
|
|
|
|
|
/** |
|
|
* The "authority" portion of the URL |
|
|
*/ |
|
|
private String authority; |
|
|
|
|
|
/** |
|
|
* The anchor portion of the URL |
|
|
*/ |
|
|
private String ref; |
|
|
|
|
|
private transient String userInfo; |
|
|
|
|
|
/** |
|
|
* The protocol handler in use for this URL |
|
|
*/ |
|
|
private transient URLStreamHandler ph; |
|
|
|
|
|
/** |
|
|
* This is the hashCode for this URL |
|
|
*/ |
|
|
private int hashCode; |
|
|
|
|
|
/*************************************************************************/ |
|
|
|
|
|
/* |
|
|
* Static Methods |
|
|
*/ |
|
|
|
|
|
/** |
|
|
* Sets the URLStreamHandlerFactory for this class. This factory is |
|
|
* responsible for returning the appropriate protocol handler for |
|
|
* a given URL. |
|
|
* |
|
|
* @param fac The URLStreamHandlerFactory class to use |
|
|
* |
|
|
* @exception Error If the factory is alread set. |
|
|
*/ |
|
|
public static synchronized void |
|
|
setURLStreamHandlerFactory(URLStreamHandlerFactory fac) |
|
|
{ |
|
|
if (factory == null) |
|
|
factory = fac; |
|
|
else |
|
|
throw new Error("URLStreamHandlerFactory alread set"); |
|
|
} |
|
|
|
|
|
/*************************************************************************/ |
|
|
|
|
212 |
/** |
/** |
213 |
* This internal method is used in two different constructors to load |
* This internal method is used in two different constructors to load |
214 |
* a protocol handler for this URL. |
* a protocol handler for this URL. |
215 |
* |
* |
216 |
* @param The protocol to load a handler for |
* @param The protocol to load a handler for |
217 |
* |
* |
218 |
* @return A URLStreamHandler for this protocol |
* @return A URLStreamHandler for this protocol, or null when not found. |
|
* |
|
|
* @exception MalformedURLException If the protocol can't be loaded. |
|
219 |
*/ |
*/ |
220 |
private static URLStreamHandler |
private static synchronized URLStreamHandler |
221 |
getProtocolHandler(String protocol) throws MalformedURLException |
getURLStreamHandler(String protocol) |
222 |
{ |
{ |
223 |
URLStreamHandler ph; |
URLStreamHandler ph; |
224 |
|
|
242 |
{ |
{ |
243 |
ph = factory.createURLStreamHandler(protocol); |
ph = factory.createURLStreamHandler(protocol); |
244 |
if (ph == null) |
if (ph == null) |
245 |
throw new MalformedURLException(protocol); |
return null; |
246 |
|
|
247 |
if (cache_handlers) |
if (cache_handlers) |
248 |
ph_cache.put(protocol, ph.getClass()); |
ph_cache.put(protocol, ph.getClass()); |
274 |
} |
} |
275 |
|
|
276 |
// Still here, which is bad |
// Still here, which is bad |
277 |
throw new MalformedURLException(protocol); |
return null; |
278 |
} |
} |
279 |
|
|
|
/*************************************************************************/ |
|
|
|
|
|
/* |
|
|
* Constructors |
|
|
*/ |
|
280 |
|
|
281 |
/** |
/** |
282 |
* Constructs a URL and loads a protocol handler for the values passed as |
* Constructs a URL and loads a protocol handler for the values passed as |
283 |
* arguments. |
* arguments. |
284 |
* |
* |
285 |
* @param protocol The protocol for this URL ("http", "ftp", etc) |
* @param protocol The protocol for this URL ("http", "ftp", etc) |
286 |
* @param host The hostname or IP address to connect to |
* @param host The hostname or IP address to connect to |
287 |
* @param port The port number to use, or -1 to use the protocol's default port |
* @param port The port number to use, or -1 to use the protocol's |
288 |
* @param file The "file" portion of the URL. |
* default port |
289 |
* |
* @param file The "file" portion of the URL. |
290 |
* @exception MalformedURLException If a protocol handler cannot be loaded |
* |
291 |
*/ |
* @exception MalformedURLException If a protocol handler cannot be loaded or |
292 |
public |
* a parse error occurs. |
293 |
URL(String protocol, String host, int port, String file) |
*/ |
294 |
|
public URL(String protocol, String host, int port, String file) |
295 |
throws MalformedURLException |
throws MalformedURLException |
296 |
{ |
{ |
297 |
this(protocol, host, port, file, null); |
this(protocol, host, port, file, null); |
298 |
} |
} |
|
|
|
|
/*************************************************************************/ |
|
|
|
|
|
/** |
|
|
* Constructs a URL and loads a protocol handler for the values passed in |
|
|
* as arugments. Uses the default port for the protocol. |
|
|
* |
|
|
* @param protocol The protocol for this URL ("http", "ftp", etc) |
|
|
* @param host The hostname or IP address for this URL |
|
|
* @param file The "file" portion of this URL. |
|
|
* |
|
|
* @exception MalformedURLException If a protocol handler cannot be loaded |
|
|
*/ |
|
|
public |
|
|
URL(String protocol, String host, String file) throws MalformedURLException |
|
|
{ |
|
|
this(protocol, host, -1, file, null); |
|
|
} |
|
|
|
|
|
/*************************************************************************/ |
|
|
|
|
|
/** |
|
|
* This method initializes a new instance of <code>URL</code> with the |
|
|
* specified protocol, host, port, and file. Additionally, this method |
|
|
* allows the caller to specify a protocol handler to use instead of |
|
|
* the default. If this handler is specified, the caller must have |
|
|
* the "specifyStreamHandler" permission (see <code>NetPermission</code>) |
|
|
* or a <code>SecurityException</code> will be thrown. |
|
|
* |
|
|
* @param protocol The protocol for this URL ("http", "ftp", etc) |
|
|
* @param host The hostname or IP address to connect to |
|
|
* @param port The port number to use, or -1 to use the protocol's default port |
|
|
* @param file The "file" portion of the URL. |
|
|
* @param ph The protocol handler to use with this URL. |
|
|
* |
|
|
* @exception MalformedURLException If no protocol handler can be loaded |
|
|
* for the specified protocol. |
|
|
* @exception SecurityException If the <code>SecurityManager</code> exists |
|
|
* and does not allow the caller to specify its own protocol handler. |
|
|
*/ |
|
|
public |
|
|
URL(String protocol, String host, int port, String file, |
|
|
URLStreamHandler ph) throws MalformedURLException, SecurityException |
|
|
{ |
|
|
this.protocol = protocol.toLowerCase(); |
|
|
this.host = host; |
|
|
this.port = port; |
|
|
this.file = file; |
|
|
|
|
|
if (ph != null) |
|
|
{ |
|
|
SecurityManager sm = System.getSecurityManager(); |
|
|
if (sm != null) |
|
|
sm.checkPermission(new NetPermission("specifyStreamHandler")); |
|
299 |
|
|
300 |
this.ph = ph; |
/** |
301 |
} |
* Constructs a URL and loads a protocol handler for the values passed in |
302 |
else |
* as arugments. Uses the default port for the protocol. |
303 |
{ |
* |
304 |
this.ph = getProtocolHandler(protocol); |
* @param protocol The protocol for this URL ("http", "ftp", etc) |
305 |
} |
* @param host The hostname or IP address for this URL |
306 |
|
* @param file The "file" portion of this URL. |
307 |
hashCode = toString().hashCode(); |
* |
308 |
} |
* @exception MalformedURLException If a protocol handler cannot be loaded or |
309 |
|
* a parse error occurs. |
310 |
|
*/ |
311 |
|
public URL(String protocol, String host, String file) |
312 |
|
throws MalformedURLException |
313 |
|
{ |
314 |
|
this(protocol, host, -1, file, null); |
315 |
|
} |
316 |
|
|
|
/*************************************************************************/ |
|
317 |
|
|
318 |
/** |
/** |
319 |
* This method parses a String representation of a URL within the |
* This method initializes a new instance of <code>URL</code> with the |
320 |
* context of an existing URL. Principally this means that any fields |
* specified protocol, host, port, and file. Additionally, this method |
321 |
* not present the URL are inheritied from the context URL. This allows |
* allows the caller to specify a protocol handler to use instead of |
322 |
* relative URL's to be easily constructed (***true?***). If the |
* the default. If this handler is specified, the caller must have |
323 |
* context argument is null, then a complete URL must be specified in the |
* the "specifyStreamHandler" permission (see <code>NetPermission</code>) |
324 |
* URL string. If the protocol parsed out of the URL is different |
* or a <code>SecurityException</code> will be thrown. |
325 |
* from the context URL's protocol, then then URL String is also |
* |
326 |
* expected to be a complete URL. |
* @param protocol The protocol for this URL ("http", "ftp", etc) |
327 |
* |
* @param host The hostname or IP address to connect to |
328 |
* @param context The context URL |
* @param port The port number to use, or -1 to use the protocol's default |
329 |
* @param url A String representing this URL |
* port |
330 |
* |
* @param file The "file" portion of the URL. |
331 |
* @exception MalformedURLException If a protocol handler cannot be found |
* @param handler The protocol handler to use with this URL. |
332 |
* for the URL cannot be parsed |
* |
333 |
*/ |
* @exception MalformedURLException If no protocol handler can be loaded |
334 |
public |
* for the specified protocol. |
335 |
URL(URL context, String url) throws MalformedURLException |
* @exception SecurityException If the <code>SecurityManager</code> exists |
336 |
{ |
* and does not allow the caller to specify its own protocol handler. |
337 |
this(context, url, null); |
* |
338 |
} |
* @since 1.2 |
339 |
|
*/ |
340 |
|
public URL(String protocol, String host, int port, String file, |
341 |
|
URLStreamHandler handler) throws MalformedURLException |
342 |
|
{ |
343 |
|
if (protocol == null) |
344 |
|
throw new MalformedURLException("null protocol"); |
345 |
|
this.protocol = protocol.toLowerCase(); |
346 |
|
|
347 |
/*************************************************************************/ |
if (handler != null) |
348 |
|
{ |
349 |
|
SecurityManager s = System.getSecurityManager(); |
350 |
|
if (s != null) |
351 |
|
s.checkPermission (new NetPermission ("specifyStreamHandler")); |
352 |
|
|
353 |
/** |
this.handler = handler; |
354 |
* This method parses a String representation of a URL within the |
} |
355 |
* context of an existing URL. Principally this means that any fields |
else |
356 |
* not present the URL are inheritied from the context URL. This allows |
this.handler = getURLStreamHandler(protocol); |
|
* relative URL's to be easily constructed (***true?***). If the |
|
|
* context argument is null, then a complete URL must be specified in the |
|
|
* URL string. If the protocol parsed out of the URL is different |
|
|
* from the context URL's protocol, then then URL String is also |
|
|
* expected to be a complete URL. |
|
|
* |
|
|
* Additionally, this method allows the caller to specify a protocol handler to |
|
|
* use instead of the default. If this handler is specified, the caller must |
|
|
* have the "specifyStreamHandler" permission (see <code>NetPermission</code>) |
|
|
* or a <code>SecurityException</code> will be thrown. |
|
|
* |
|
|
* @param context The context URL |
|
|
* @param url A String representing this URL |
|
|
* @param ph The protocol handler for this URL |
|
|
* |
|
|
* @exception MalformedURLException If a protocol handler cannot be found or the URL cannot be parsed |
|
|
* @exception SecurityException If the <code>SecurityManager</code> exists |
|
|
* and does not allow the caller to specify its own protocol handler. |
|
|
*/ |
|
|
public |
|
|
URL(URL context, String url, URLStreamHandler ph) throws MalformedURLException |
|
|
{ |
|
|
int end, start = -1; |
|
357 |
|
|
358 |
int colon_index = url.indexOf(":"); |
if (this.handler == null) |
359 |
int slash_index = url.indexOf("/"); |
throw new MalformedURLException ( |
360 |
|
"Protocol handler not found: " + protocol); |
361 |
|
|
362 |
|
this.host = host; |
363 |
|
this.port = port; |
364 |
|
this.authority = null; |
365 |
|
|
366 |
// Find a protocol name in the string if there is one |
int hashAt = file.indexOf('#'); |
367 |
if (colon_index != -1) |
if (hashAt < 0) |
|
if ((slash_index == -1) ||((slash_index != -1) && |
|
|
(colon_index < slash_index))) |
|
368 |
{ |
{ |
369 |
protocol = url.substring(0, colon_index); |
this.file = file; |
370 |
start = colon_index + 1; // Used for parsing later |
this.ref = null; |
371 |
} |
} |
372 |
|
else |
|
// Handle defaulting of protocol from context. If no protocol and no |
|
|
// context, then no URL. |
|
|
if (protocol == null) |
|
|
if (context == null) |
|
|
throw new MalformedURLException(url); |
|
|
else |
|
|
protocol = context.getProtocol(); |
|
|
|
|
|
protocol = protocol.toLowerCase(); |
|
|
|
|
|
// Default in items as necessary |
|
|
if (context != null) |
|
|
if (context.getProtocol().toLowerCase().equals(protocol)) |
|
373 |
{ |
{ |
374 |
host = context.getHost(); |
this.file = file.substring(0, hashAt); |
375 |
port = context.getPort(); |
this.ref = file.substring(hashAt + 1); |
|
file = context.getFile(); |
|
|
if (file == null) |
|
|
file = ""; |
|
376 |
} |
} |
377 |
|
hashCode = hashCode(); // Used for serialization. |
378 |
|
} |
379 |
|
|
380 |
// Get the protocol handler and parse the rest of the URL string. |
/** |
381 |
if (ph != null) |
* Initializes a URL from a complete string specification such as |
382 |
{ |
* "http://www.urbanophile.com/arenn/". First the protocol name is parsed |
383 |
SecurityManager sm = System.getSecurityManager(); |
* out of the string. Then a handler is located for that protocol and |
384 |
if (sm != null) |
* the parseURL() method of that protocol handler is used to parse the |
385 |
sm.checkPermission(new NetPermission("specifyStreamHandler")); |
* remaining fields. |
386 |
|
* |
387 |
this.ph = ph; |
* @param spec The complete String representation of a URL |
388 |
} |
* |
389 |
else |
* @exception MalformedURLException If a protocol handler cannot be found |
390 |
{ |
* or the URL cannot be parsed |
391 |
this.ph = getProtocolHandler(protocol); |
*/ |
392 |
} |
public URL(String spec) throws MalformedURLException |
393 |
|
{ |
394 |
if (start == -1) |
this((URL) null, spec, (URLStreamHandler) null); |
395 |
start = 0; |
} |
396 |
|
|
397 |
// We are supposed to stop parsing at the "#" char and treat everything |
/* |
398 |
// after that as an anchor. |
* This method parses a String representation of a URL within the |
399 |
end = url.indexOf("#"); |
* context of an existing URL. Principally this means that any |
400 |
if (end == -1) |
* fields not present the URL are inheritied from the context URL. |
401 |
end = url.length(); |
* This allows relative URL's to be easily constructed. If the |
402 |
|
* context argument is null, then a complete URL must be specified |
403 |
// Ok, parseURL will not work here right now. Instead, we just |
* in the URL string. If the protocol parsed out of the URL is |
404 |
// do a hack by treating the spec URL as a file that should be |
* different from the context URL's protocol, then then URL String |
405 |
// appended to the context. Only if the context is null do we try |
* is also expected to be a complete URL. |
406 |
// to parse. |
* |
407 |
|
* @param context The context on which to parse the specification |
408 |
this.ph.parseURL(this, url, start, end); |
* @param spec The string to parse an URL |
409 |
|
* |
410 |
hashCode = toString().hashCode(); |
* @exception MalformedURLException If a protocol handler cannot be found |
411 |
} |
* for the URL cannot be parsed |
412 |
|
*/ |
413 |
/*************************************************************************/ |
public URL(URL context, String spec) throws MalformedURLException |
414 |
|
{ |
415 |
/** |
this(context, spec, (URLStreamHandler) null); |
416 |
* Initializes a URL from a complete string specification such as |
} |
|
* "http://www.urbanophile.com/arenn/". First the protocol name is parsed |
|
|
* out of the string. Then a handler is located for that protocol and |
|
|
* the parseURL() method of that protocol handler is used to parse the |
|
|
* remaining fields. |
|
|
* |
|
|
* @param url The complete String representation of a URL |
|
|
* |
|
|
* @exception MalformedURLException If a protocol handler cannot be found or the URL cannot be parsed |
|
|
*/ |
|
|
public |
|
|
URL(String url) throws MalformedURLException |
|
|
{ |
|
|
this(null, url); |
|
|
} |
|
|
|
|
|
/*************************************************************************/ |
|
|
|
|
|
/* |
|
|
* Instance Methods |
|
|
*/ |
|
|
|
|
|
/** |
|
|
* This protected method is used by protocol handlers to set the values |
|
|
* of the fields in this URL. This might be done in the parseURL method |
|
|
* of that class. |
|
|
* |
|
|
* @param protocol The protocol name for this URL |
|
|
* @param host The hostname or IP address for this URL |
|
|
* @param port The port number of this URL |
|
|
* @param file The "file" portion of this URL. |
|
|
* @param ref The anchor portion of this URL. |
|
|
*/ |
|
|
protected synchronized void |
|
|
set(String protocol, String host, int port, String file, String ref) |
|
|
{ |
|
|
//*** Should we ignore null'd fields? Assume not for now. |
|
|
|
|
|
this.protocol = protocol; |
|
|
this.host = host; |
|
|
this.port = port; |
|
|
this.file = file; |
|
|
this.ref = ref; |
|
|
} |
|
|
|
|
|
/*************************************************************************/ |
|
|
|
|
|
/** |
|
|
* Returns the protocol name of this URL |
|
|
* |
|
|
* @return The protocol |
|
|
*/ |
|
|
public String |
|
|
getProtocol() |
|
|
{ |
|
|
return(protocol); |
|
|
} |
|
|
|
|
|
/*************************************************************************/ |
|
|
|
|
|
/** |
|
|
* Returns the hostname or IP address for this protocol |
|
|
* |
|
|
* @return The hostname |
|
|
*/ |
|
|
public String |
|
|
getHost() |
|
|
{ |
|
|
return(host); |
|
|
} |
|
|
|
|
|
/*************************************************************************/ |
|
|
|
|
|
/** |
|
|
* Returns the port number of this URL or -1 if the default port number is |
|
|
* being used |
|
|
* |
|
|
* @return The port number |
|
|
*/ |
|
|
public int |
|
|
getPort() |
|
|
{ |
|
|
return(port); |
|
|
} |
|
|
|
|
|
/*************************************************************************/ |
|
417 |
|
|
418 |
/** |
/** |
419 |
* Returns the "file" portion of this URL |
* Creates an URL from given arguments |
420 |
* |
* This method parses a String representation of a URL within the |
421 |
* @return The file portion |
* context of an existing URL. Principally this means that any fields |
422 |
*/ |
* not present the URL are inheritied from the context URL. This allows |
423 |
public String |
* relative URL's to be easily constructed. If the context argument is |
424 |
getFile() |
* null, then a complete URL must be specified in the URL string. |
425 |
{ |
* If the protocol parsed out of the URL is different |
426 |
return(file); |
* from the context URL's protocol, then then URL String is also |
427 |
} |
* expected to be a complete URL. |
428 |
|
* <p> |
429 |
|
* Additionally, this method allows the caller to specify a protocol handler |
430 |
|
* to use instead of the default. If this handler is specified, the caller |
431 |
|
* must have the "specifyStreamHandler" permission |
432 |
|
* (see <code>NetPermission</code>) or a <code>SecurityException</code> |
433 |
|
* will be thrown. |
434 |
|
* |
435 |
|
* @param context The context in which to parse the specification |
436 |
|
* @param spec The string to parse as an URL |
437 |
|
* @param handler The stream handler for the URL |
438 |
|
* |
439 |
|
* @exception MalformedURLException If a protocol handler cannot be found |
440 |
|
* or the URL cannot be parsed |
441 |
|
* @exception SecurityException If the <code>SecurityManager</code> exists |
442 |
|
* and does not allow the caller to specify its own protocol handler. |
443 |
|
* |
444 |
|
* @since 1.2 |
445 |
|
*/ |
446 |
|
public URL(URL context, String spec, URLStreamHandler handler) |
447 |
|
throws MalformedURLException |
448 |
|
{ |
449 |
|
/* A protocol is defined by the doc as the substring before a ':' |
450 |
|
* as long as the ':' occurs before any '/'. |
451 |
|
* |
452 |
|
* If context is null, then spec must be an absolute URL. |
453 |
|
* |
454 |
|
* The relative URL need not specify all the components of a URL. |
455 |
|
* If the protocol, host name, or port number is missing, the value |
456 |
|
* is inherited from the context. A bare file component is appended |
457 |
|
* to the context's file. The optional anchor is not inherited. |
458 |
|
*/ |
459 |
|
|
460 |
|
// If this is an absolute URL, then ignore context completely. |
461 |
|
// An absolute URL must have chars prior to "://" but cannot have a colon |
462 |
|
// right after the "://". The second colon is for an optional port value |
463 |
|
// and implies that the host from the context is used if available. |
464 |
|
int colon; |
465 |
|
if ((colon = spec.indexOf("://", 1)) > 0 && |
466 |
|
! spec.regionMatches(colon, "://:", 0, 4)) |
467 |
|
context = null; |
468 |
|
|
469 |
|
int slash; |
470 |
|
if ((colon = spec.indexOf(':')) > 0 && |
471 |
|
(colon < (slash = spec.indexOf('/')) || slash < 0)) |
472 |
|
{ |
473 |
|
// Protocol specified in spec string. |
474 |
|
protocol = spec.substring(0, colon).toLowerCase(); |
475 |
|
if (context != null && context.protocol.equals(protocol)) |
476 |
|
{ |
477 |
|
// The 1.2 doc specifically says these are copied to the new URL. |
478 |
|
host = context.host; |
479 |
|
port = context.port; |
480 |
|
file = context.file; |
481 |
|
authority = context.authority; |
482 |
|
} |
483 |
|
} |
484 |
|
else if (context != null) |
485 |
|
{ |
486 |
|
// Protocol NOT specified in spec string. |
487 |
|
// Use context fields (except ref) as a foundation for relative URLs. |
488 |
|
colon = -1; |
489 |
|
protocol = context.protocol; |
490 |
|
host = context.host; |
491 |
|
port = context.port; |
492 |
|
file = context.file; |
493 |
|
authority = context.authority; |
494 |
|
} |
495 |
|
else // Protocol NOT specified in spec. and no context available. |
496 |
|
throw new |
497 |
|
MalformedURLException("Absolute URL required with null context"); |
498 |
|
|
499 |
/*************************************************************************/ |
if (handler != null) |
500 |
|
{ |
501 |
|
SecurityManager s = System.getSecurityManager (); |
502 |
|
if (s != null) |
503 |
|
s.checkPermission (new NetPermission ("specifyStreamHandler")); |
504 |
|
|
505 |
/** |
this.handler = handler; |
506 |
* Returns the ref (sometimes called the "reference") portion of the |
} |
507 |
* URL |
else |
508 |
* |
this.handler = getURLStreamHandler(protocol); |
|
* @return The ref |
|
|
*/ |
|
|
public String |
|
|
getRef() |
|
|
{ |
|
|
return(ref); |
|
|
} |
|
509 |
|
|
510 |
/*************************************************************************/ |
if (this.handler == null) |
511 |
|
throw new MalformedURLException("Protocol handler not found: " |
512 |
|
+ protocol); |
513 |
|
|
514 |
|
// JDK 1.2 doc for parseURL specifically states that any '#' ref |
515 |
|
// is to be excluded by passing the 'limit' as the indexOf the '#' |
516 |
|
// if one exists, otherwise pass the end of the string. |
517 |
|
int hashAt = spec.indexOf('#', colon + 1); |
518 |
|
this.handler.parseURL(this, spec, colon + 1, |
519 |
|
hashAt < 0 ? spec.length() : hashAt); |
520 |
|
if (hashAt >= 0) |
521 |
|
ref = spec.substring(hashAt + 1); |
522 |
|
|
523 |
/** |
hashCode = hashCode(); // Used for serialization. |
524 |
* Test another URL for equality with this one. This will be true only if |
} |
|
* the argument is non-null and all of the fields in the URL's match |
|
|
* exactly (ie, protocol, host, port, file, and ref). Overrides |
|
|
* Object.equals(). |
|
|
* |
|
|
* @param url The URL to compare with |
|
|
* |
|
|
* @return true if the URL is equal, false otherwise |
|
|
*/ |
|
|
public boolean |
|
|
equals(Object url) |
|
|
{ |
|
|
// Is it null? |
|
|
if (url == null) |
|
|
return(false); |
|
|
|
|
|
// Is it a URL? |
|
|
if (!(url instanceof URL)) |
|
|
return(false); |
|
|
|
|
|
URL u = (URL)url; |
|
|
|
|
|
// Check everything but the ref |
|
|
if (!sameFile(u)) |
|
|
return(false); |
|
|
|
|
|
// Do the ref's match |
|
|
String s = u.getRef(); |
|
|
if (s != null) |
|
|
if (!s.equals(getRef())) |
|
|
return(false); |
|
|
else if (getRef() != null) |
|
|
return(false); |
|
525 |
|
|
526 |
// Still here so everything must be ok |
/** |
527 |
return(true); |
* Test another URL for equality with this one. This will be true only if |
528 |
} |
* the argument is non-null and all of the fields in the URL's match |
529 |
|
* exactly (ie, protocol, host, port, file, and ref). Overrides |
530 |
|
* Object.equals(), implemented by calling the equals method of the handler. |
531 |
|
* |
532 |
|
* @param url The URL to compare with |
533 |
|
* |
534 |
|
* @return true if the URL is equal, false otherwise |
535 |
|
*/ |
536 |
|
public boolean equals(Object obj) |
537 |
|
{ |
538 |
|
if (obj == null || ! (obj instanceof URL)) |
539 |
|
return false; |
540 |
|
|
541 |
/*************************************************************************/ |
URL uObj = (URL) obj; |
542 |
|
|
543 |
/** |
return handler.equals (this, uObj); |
544 |
* Tests whether or not another URL refers to the same "file" as this one. |
} |
|
* This will be true if and only if the passed object is not null, is a |
|
|
* URL, and matches all fields but the ref (ie, protocol, host, port, |
|
|
* and file); |
|
|
* |
|
|
* @param url The URL object to test with |
|
|
* |
|
|
* @return true if URL matches this URL's file, false otherwise |
|
|
*/ |
|
|
public boolean |
|
|
sameFile(URL url) |
|
|
{ |
|
|
if (url == null) |
|
|
return(false); |
|
545 |
|
|
546 |
// Do the protocol's match? |
/** |
547 |
String s = url.getProtocol(); |
* Returns the contents of this URL as an object by first opening a |
548 |
if (s != null) |
* connection, then calling the getContent() method against the connection |
549 |
{ |
* |
550 |
if (!s.equals(getProtocol())) |
* @return A content object for this URL |
551 |
return(false); |
* @exception IOException If opening the connection or getting the |
552 |
} |
* content fails. |
553 |
else if (getProtocol() != null) |
* |
554 |
return(false); |
* @since 1.3 |
555 |
|
*/ |
556 |
|
public final Object getContent() throws IOException |
557 |
|
{ |
558 |
|
return openConnection().getContent(); |
559 |
|
} |
560 |
|
|
561 |
// Do the hostname's match? |
/** |
562 |
s = url.getHost(); |
* Gets the contents of this URL |
563 |
if (s != null) |
* |
564 |
{ |
* @exception IOException If an error occurs |
565 |
if (!s.equals(getHost())) |
*/ |
566 |
return(false); |
public final Object getContent (Class[] classes) throws IOException |
567 |
} |
{ |
568 |
else if (getHost() != null) |
// FIXME: implement this |
569 |
return(false); |
return getContent(); |
570 |
|
} |
571 |
|
|
572 |
// Do the port's match? |
/** |
573 |
if (url.getPort() != getPort()) |
* Returns the file portion of the URL. |
574 |
return(false); |
* Defined as <code>path[?query]</code>. |
575 |
|
* Returns the empty string if there is no file portion. |
576 |
// Do the file's match? |
*/ |
577 |
s = url.getFile(); |
public String getFile() |
578 |
if (s != null) |
{ |
579 |
{ |
return file == null ? "" : file; |
580 |
if (!s.equals(getFile())) |
} |
|
return(false); |
|
|
} |
|
|
else if (getFile() != null) |
|
|
return(false); |
|
581 |
|
|
582 |
// We're still here, so everything must be ok! |
/** |
583 |
return(true); |
* Returns the path of the URL. This is the part of the file before any '?' |
584 |
} |
* character. |
585 |
|
* |
586 |
|
* @since 1.3 |
587 |
|
*/ |
588 |
|
public String getPath() |
589 |
|
{ |
590 |
|
int quest = file.indexOf('?'); |
591 |
|
return quest < 0 ? file : file.substring(0, quest); |
592 |
|
} |
593 |
|
|
594 |
/*************************************************************************/ |
/** |
595 |
|
* Returns the authority of the URL |
596 |
|
* |
597 |
|
* @since 1.3 |
598 |
|
*/ |
599 |
|
public String getAuthority() |
600 |
|
{ |
601 |
|
return authority; |
602 |
|
} |
603 |
|
|
604 |
/* |
/** |
605 |
* This is the implementation of the Comparable interface for URL's. It |
* Returns the host of the URL |
606 |
* will return a negative int, 0, or a positive int depending on whether |
*/ |
607 |
* a URL is less than, equal to, or greater than this URL respectively. |
public String getHost() |
608 |
* This is done by returning the compareTo result on this string |
{ |
609 |
* representations of these URL's. |
int at = (host == null) ? -1 : host.indexOf('@'); |
610 |
* |
return at < 0 ? host : host.substring(at + 1, host.length()); |
611 |
* @param url The URL to compare against |
} |
|
* |
|
|
* @return An int indicating whether a URL is less than, equal to, or greater than this URL |
|
|
* |
|
|
public int |
|
|
compareTo(Object url) |
|
|
{ |
|
|
return(toExternalForm().compareTo(((URL)url).toExternalForm())); |
|
|
} |
|
|
*/ |
|
612 |
|
|
613 |
/*************************************************************************/ |
/** |
614 |
|
* Returns the port number of this URL or -1 if the default port number is |
615 |
|
* being used. |
616 |
|
* |
617 |
|
* @return The port number |
618 |
|
* |
619 |
|
* @see #getDefaultPort() |
620 |
|
*/ |
621 |
|
public int getPort() |
622 |
|
{ |
623 |
|
return port; |
624 |
|
} |
625 |
|
|
626 |
/** |
/** |
627 |
* Returns a String representing this URL. The String returned is |
* Returns the default port of the URL. If the StreamHandler for the URL |
628 |
* created by calling the protocol handler's toExternalForm() method. |
* protocol does not define a default port it returns -1. |
629 |
* |
*/ |
630 |
* @return A string for this URL |
public int getDefaultPort() |
631 |
*/ |
{ |
632 |
public String |
return handler.getDefaultPort(); |
633 |
toExternalForm() |
} |
|
{ |
|
|
return(ph.toExternalForm(this)); |
|
|
} |
|
634 |
|
|
635 |
/*************************************************************************/ |
/** |
636 |
|
* Returns the protocol of the URL |
637 |
|
*/ |
638 |
|
public String getProtocol() |
639 |
|
{ |
640 |
|
return protocol; |
641 |
|
} |
642 |
|
|
643 |
/** |
/** |
644 |
* Returns a String representing this URL. Identical to toExternalForm(). |
* Returns the ref (sometimes called the "# reference" or "anchor") portion |
645 |
* The value returned is created by the protocol handler's |
* of the URL. |
646 |
* toExternalForm method. Overrides Object.toString() |
* |
647 |
* |
* @return The ref |
648 |
* @return A string for this URL |
*/ |
649 |
*/ |
public String getRef() |
650 |
public String |
{ |
651 |
toString() |
return ref; |
652 |
{ |
} |
|
return(toExternalForm()); |
|
|
} |
|
653 |
|
|
654 |
/*************************************************************************/ |
/** |
655 |
|
* Returns the user information of the URL. This is the part of the host |
656 |
|
* name before the '@'. |
657 |
|
* |
658 |
|
* @return the user at a particular host or null when no user defined. |
659 |
|
*/ |
660 |
|
public String getUserInfo () |
661 |
|
{ |
662 |
|
int at = host.indexOf('@'); |
663 |
|
return at < 0 ? null : host.substring(0, at); |
664 |
|
} |
665 |
|
|
666 |
/** |
/** |
667 |
* Returns a URLConnection for this object created by calling the |
* Returns the query of the URL. This is the part of the file before the |
668 |
* openConnection() method of the protocol handler |
* '?'. |
669 |
* |
* |
670 |
* @return A URLConnection for this URL |
* @ return the query part of the file, or null when there is no query part. |
671 |
* |
*/ |
672 |
* @exception IOException If an error occurs |
public String getQuery () |
673 |
*/ |
{ |
674 |
public synchronized URLConnection |
int quest = file.indexOf('?'); |
675 |
openConnection() throws IOException |
return quest < 0 ? null : file.substring(quest + 1, file.length()); |
676 |
{ |
} |
|
return(ph.openConnection(this)); |
|
|
} |
|
677 |
|
|
678 |
/*************************************************************************/ |
/** |
679 |
|
* Returns a hashcode computed by the URLStreamHandler of this URL |
680 |
|
*/ |
681 |
|
public int hashCode() |
682 |
|
{ |
683 |
|
if (hashCode != 0) |
684 |
|
return hashCode; // Use cached value if available. |
685 |
|
else |
686 |
|
return handler.hashCode (this); |
687 |
|
} |
688 |
|
|
689 |
/** |
/** |
690 |
* This method returns an InputStream for this URL by first opening the |
* Returns a URLConnection object that represents a connection to the remote |
691 |
* connection, then calling the getInputStream() method against the |
* object referred to by the URL. The URLConnection is created by calling the |
692 |
* connection. |
* openConnection() method of the protocol handler |
693 |
* |
* |
694 |
* @return An InputStream for this URL |
* @return A URLConnection for this URL |
695 |
* |
* @exception IOException If an error occurs |
696 |
* @exception IOException If an error occurs |
*/ |
697 |
*/ |
public URLConnection openConnection() throws IOException |
698 |
public final synchronized InputStream |
{ |
699 |
openStream() throws IOException |
return handler.openConnection(this); |
700 |
{ |
} |
|
return(openConnection().getInputStream()); |
|
|
} |
|
701 |
|
|
702 |
/*************************************************************************/ |
/** |
703 |
|
* Opens a connection to this URL and returns an InputStream for reading |
704 |
|
* from that connection |
705 |
|
* |
706 |
|
* @exception IOException If an error occurs |
707 |
|
*/ |
708 |
|
public final InputStream openStream() throws IOException |
709 |
|
{ |
710 |
|
return openConnection().getInputStream(); |
711 |
|
} |
712 |
|
|
713 |
/** |
/** |
714 |
* Returns the contents of this URL as an object by first opening a |
* Tests whether or not another URL refers to the same "file" as this one. |
715 |
* connection, then calling the getContent() method against the connection |
* This will be true if and only if the passed object is not null, is a |
716 |
* |
* URL, and matches all fields but the ref (ie, protocol, host, port, |
717 |
* @return A content object for this URL |
* and file); |
718 |
* |
* |
719 |
* @exception IOException If an error occurs |
* @param url The URL object to test with |
720 |
*/ |
* |
721 |
public final synchronized Object |
* @return true if URL matches this URL's file, false otherwise |
722 |
getContent() throws IOException |
*/ |
723 |
{ |
public boolean sameFile(URL other) |
724 |
return(openConnection().getContent()); |
{ |
725 |
} |
return handler.sameFile(this, other); |
726 |
|
} |
727 |
|
|
728 |
/*************************************************************************/ |
/** |
729 |
|
* Sets the specified fields of the URL. This is not a public method so |
730 |
|
* that only URLStreamHandlers can modify URL fields. This might be called |
731 |
|
* by the <code>parseURL()</code> method in that class. URLs are otherwise |
732 |
|
* constant. |
733 |
|
* |
734 |
|
* @param protocol The protocol name for this URL |
735 |
|
* @param host The hostname or IP address for this URL |
736 |
|
* @param port The port number of this URL |
737 |
|
* @param file The "file" portion of this URL. |
738 |
|
* @param ref The anchor portion of this URL. |
739 |
|
*/ |
740 |
|
protected void set(String protocol, String host, int port, String file, |
741 |
|
String ref) |
742 |
|
{ |
743 |
|
// TBD: Theoretically, a poorly written StreamHandler could pass an |
744 |
|
// invalid protocol. It will cause the handler to be set to null |
745 |
|
// thus overriding a valid handler. Callers of this method should |
746 |
|
// be aware of this. |
747 |
|
this.handler = getURLStreamHandler(protocol); |
748 |
|
this.protocol = protocol.toLowerCase(); |
749 |
|
this.authority = null; |
750 |
|
this.port = port; |
751 |
|
this.host = host; |
752 |
|
this.file = file; |
753 |
|
this.ref = ref; |
754 |
|
hashCode = hashCode(); // Used for serialization. |
755 |
|
} |
756 |
|
|
757 |
/** |
/** |
758 |
* This method returns a hash value for this object. |
* Sets the specified fields of the URL. This is not a public method so |
759 |
* |
* that only URLStreamHandlers can modify URL fields. URLs are otherwise |
760 |
* @return a hash value for this object. |
* constant. |
761 |
*/ |
* |
762 |
public int |
* @since 1.3 |
763 |
hashCode() |
*/ |
764 |
{ |
protected void set(String protocol, String host, int port, |
765 |
return(hashCode); |
String authority, String userInfo, |
766 |
} |
String path, String query, String ref) |
767 |
|
{ |
768 |
|
// TBD: Theoretically, a poorly written StreamHandler could pass an |
769 |
|
// invalid protocol. It will cause the handler to be set to null |
770 |
|
// thus overriding a valid handler. Callers of this method should |
771 |
|
// be aware of this. |
772 |
|
this.handler = getURLStreamHandler(protocol); |
773 |
|
this.protocol = protocol.toLowerCase(); |
774 |
|
if (userInfo == null) |
775 |
|
this.host = host; |
776 |
|
else |
777 |
|
this.host = userInfo + "@" + host; |
778 |
|
this.port = port; |
779 |
|
if (query == null) |
780 |
|
this.file = path; |
781 |
|
else |
782 |
|
this.file = path + "?" + query; |
783 |
|
this.ref = ref; |
784 |
|
hashCode = hashCode(); // Used for serialization. |
785 |
|
} |
786 |
|
|
787 |
//According to Java API Documentation "Serialized form" |
/** |
788 |
private synchronized void writeObject(ObjectOutputStream stream) |
* Sets the URLStreamHandlerFactory for this class. This factory is |
789 |
throws IOException |
* responsible for returning the appropriate protocol handler for |
790 |
{ |
* a given URL. |
791 |
stream.defaultWriteObject(); // write the fields |
* |
792 |
} |
* @param fac The URLStreamHandlerFactory class to use |
793 |
|
* |
794 |
|
* @exception Error If the factory is alread set. |
795 |
|
* @exception SecurityException If a security manager exists and its |
796 |
|
* checkSetFactory method doesn't allow the operation |
797 |
|
*/ |
798 |
|
public static synchronized void |
799 |
|
setURLStreamHandlerFactory(URLStreamHandlerFactory fac) |
800 |
|
{ |
801 |
|
if (factory != null) |
802 |
|
throw new Error("URLStreamHandlerFactory already set"); |
803 |
|
|
804 |
|
// Throw an exception if an extant security mgr precludes |
805 |
|
// setting the factory. |
806 |
|
SecurityManager s = System.getSecurityManager(); |
807 |
|
if (s != null) |
808 |
|
s.checkSetFactory(); |
809 |
|
factory = fac; |
810 |
|
} |
811 |
|
|
812 |
private synchronized void readObject(ObjectInputStream stream) |
/** |
813 |
throws IOException, ClassNotFoundException |
* Returns a String representing this URL. The String returned is |
814 |
{ |
* created by calling the protocol handler's toExternalForm() method. |
815 |
stream.defaultReadObject(); // read the fields |
* |
816 |
ph = getProtocolHandler(protocol); |
* @return A string for this URL |
817 |
if (ph == null) |
*/ |
818 |
throw new IOException("Can't handle protocol: " + protocol); |
public String toExternalForm() |
819 |
} |
{ |
820 |
|
// Identical to toString(). |
821 |
|
return handler.toExternalForm(this); |
822 |
|
} |
823 |
|
|
824 |
/** |
/** |
825 |
* Return the path portion of this URL |
* Returns a String representing this URL. Identical to toExternalForm(). |
826 |
* |
* The value returned is created by the protocol handler's |
827 |
* @since 1.3 |
* toExternalForm method. Overrides Object.toString() |
828 |
*/ |
* |
829 |
public String getPath() |
* @return A string for this URL |
830 |
{ |
*/ |
831 |
return file; |
public String toString() |
832 |
|
{ |
833 |
|
// Identical to toExternalForm(). |
834 |
|
return handler.toExternalForm(this); |
835 |
|
} |
836 |
|
|
837 |
|
private void readObject(ObjectInputStream ois) |
838 |
|
throws IOException, ClassNotFoundException |
839 |
|
{ |
840 |
|
ois.defaultReadObject(); |
841 |
|
this.handler = getURLStreamHandler(protocol); |
842 |
|
if (this.handler == null) |
843 |
|
throw new IOException("Handler for protocol " + protocol + " not found"); |
844 |
|
} |
845 |
|
|
846 |
|
private void writeObject(ObjectOutputStream oos) throws IOException |
847 |
|
{ |
848 |
|
oos.defaultWriteObject(); |
849 |
|
} |
850 |
} |
} |
|
|
|
|
|
|
|
} // class URL |
|
|
|
|