source: trunk/src/gcc/libjava/java/net/URL.java@ 819

Last change on this file since 819 was 2, checked in by bird, 23 years ago

Initial revision

  • Property cvs2svn:cvs-rev set to 1.1
  • Property svn:eol-style set to native
  • Property svn:executable set to *
File size: 12.0 KB
Line 
1// URL.java - A Uniform Resource Locator.
2
3/* Copyright (C) 1999, 2000, 2002 Free Software Foundation
4
5 This file is part of libgcj.
6
7This software is copyrighted work licensed under the terms of the
8Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
9details. */
10
11package java.net;
12
13import java.io.*;
14import java.util.Hashtable;
15import java.util.StringTokenizer;
16
17/**
18 * @author Warren Levy <[email protected]>
19 * @date March 4, 1999.
20 */
21
22/**
23 * Written using on-line Java Platform 1.2 API Specification, as well
24 * as "The Java Class Libraries", 2nd edition (Addison-Wesley, 1998).
25 * Status: Believed complete and correct.
26 */
27
28public final class URL implements Serializable
29{
30 private String protocol;
31 private String host;
32 private int port = -1; // Initialize for constructor using context.
33 private String file;
34 private String ref;
35 private int hashCode = 0;
36 transient private URLStreamHandler handler;
37 private static Hashtable handlers = new Hashtable();
38 private static URLStreamHandlerFactory factory;
39
40 private static final long serialVersionUID = -7627629688361524110L;
41
42 public URL(String protocol, String host, int port, String file)
43 throws MalformedURLException
44 {
45 this(protocol, host, port, file, null);
46 }
47
48 public URL(String protocol, String host, String file)
49 throws MalformedURLException
50 {
51 this(protocol, host, -1, file, null);
52 }
53
54 // JDK1.2
55 public URL(String protocol, String host, int port, String file,
56 URLStreamHandler handler) throws MalformedURLException
57 {
58 if (protocol == null)
59 throw new MalformedURLException("null protocol");
60 this.protocol = protocol;
61
62 if (handler != null)
63 {
64 // TODO12: Need SecurityManager.checkPermission and
65 // TODO12: java.net.NetPermission from JDK 1.2 to be implemented.
66 // Throw an exception if an extant security mgr precludes
67 // specifying a StreamHandler.
68 //
69 // SecurityManager s = System.getSecurityManager();
70 // if (s != null)
71 // s.checkPermission(NetPermission("specifyStreamHandler"));
72
73 this.handler = handler;
74 }
75 else
76 this.handler = setURLStreamHandler(protocol);
77
78 if (this.handler == null)
79 throw new MalformedURLException("Protocol handler not found: " + protocol);
80
81 this.host = host;
82
83 this.port = port;
84
85 int hashAt = file.indexOf('#');
86 if (hashAt < 0)
87 {
88 this.file = file;
89 this.ref = null;
90 }
91 else
92 {
93 this.file = file.substring(0, hashAt);
94 this.ref = file.substring(hashAt + 1);
95 }
96 hashCode = hashCode(); // Used for serialization.
97 }
98
99 public URL(String spec) throws MalformedURLException
100 {
101 this((URL) null, spec, (URLStreamHandler) null);
102 }
103
104 public URL(URL context, String spec) throws MalformedURLException
105 {
106 this(context, spec, (URLStreamHandler) null);
107 }
108
109 // JDK1.2
110 public URL(URL context, String spec, URLStreamHandler handler)
111 throws MalformedURLException
112 {
113 /* A protocol is defined by the doc as the substring before a ':'
114 * as long as the ':' occurs before any '/'.
115 *
116 * If context is null, then spec must be an absolute URL.
117 *
118 * The relative URL need not specify all the components of a URL.
119 * If the protocol, host name, or port number is missing, the value
120 * is inherited from the context. A bare file component is appended
121 * to the context's file. The optional anchor is not inherited.
122 */
123
124 // If this is an absolute URL, then ignore context completely.
125 // An absolute URL must have chars prior to "://" but cannot have a colon
126 // right after the "://". The second colon is for an optional port value
127 // and implies that the host from the context is used if available.
128 int colon;
129 if ((colon = spec.indexOf("://", 1)) > 0 &&
130 ! spec.regionMatches(colon, "://:", 0, 4))
131 context = null;
132
133 int slash;
134 if ((colon = spec.indexOf(':')) > 0 &&
135 (colon < (slash = spec.indexOf('/')) || slash < 0))
136 {
137 // Protocol specified in spec string.
138 protocol = spec.substring(0, colon);
139 if (context != null && context.protocol.equals(protocol))
140 {
141 // The 1.2 doc specifically says these are copied to the new URL.
142 host = context.host;
143 port = context.port;
144 file = context.file;
145 }
146 }
147 else if (context != null)
148 {
149 // Protocol NOT specified in spec string.
150 // Use context fields (except ref) as a foundation for relative URLs.
151 colon = -1;
152 protocol = context.protocol;
153 host = context.host;
154 port = context.port;
155 file = context.file;
156 }
157 else // Protocol NOT specified in spec. and no context available.
158 throw new
159 MalformedURLException("Absolute URL required with null context");
160
161 if (handler != null)
162 {
163 // TODO12: Need SecurityManager.checkPermission and
164 // TODO12: java.net.NetPermission from JDK 1.2 to be implemented.
165 // Throw an exception if an extant security mgr precludes
166 // specifying a StreamHandler.
167 //
168 // SecurityManager s = System.getSecurityManager();
169 // if (s != null)
170 // s.checkPermission(NetPermission("specifyStreamHandler"));
171
172 this.handler = handler;
173 }
174 else
175 this.handler = setURLStreamHandler(protocol);
176
177 if (this.handler == null)
178 throw new MalformedURLException("Protocol handler not found: " + protocol);
179
180 // JDK 1.2 doc for parseURL specifically states that any '#' ref
181 // is to be excluded by passing the 'limit' as the indexOf the '#'
182 // if one exists, otherwise pass the end of the string.
183 int hashAt = spec.indexOf('#', colon + 1);
184 this.handler.parseURL(this, spec, colon + 1,
185 hashAt < 0 ? spec.length() : hashAt);
186 if (hashAt >= 0)
187 ref = spec.substring(hashAt + 1);
188
189 hashCode = hashCode(); // Used for serialization.
190 }
191
192 public boolean equals(Object obj)
193 {
194 if (obj == null || ! (obj instanceof URL))
195 return false;
196
197 URL uObj = (URL) obj;
198
199 // This comparison is very conservative. It assumes that any
200 // field can be null.
201 return (port == uObj.port
202 && ((protocol == null && uObj.protocol == null)
203 || (protocol != null && protocol.equals(uObj.protocol)))
204 && ((host == null && uObj.host == null)
205 || (host != null && host.equals(uObj.host)))
206 && ((file == null && uObj.file == null)
207 || (file != null && file.equals(uObj.file)))
208 && ((ref == null && uObj.ref == null)
209 || (ref != null && ref.equals(uObj.ref))));
210 }
211
212 public final Object getContent() throws IOException
213 {
214 return openConnection().getContent();
215 }
216
217 public String getFile()
218 {
219 return file;
220 }
221
222 public String getPath()
223 {
224 int quest = file.indexOf('?');
225 return quest < 0 ? file : file.substring(0, quest);
226 }
227
228 public String getHost()
229 {
230 return host;
231 }
232
233 public int getPort()
234 {
235 return port;
236 }
237
238 public String getProtocol()
239 {
240 return protocol;
241 }
242
243 public String getRef()
244 {
245 return ref;
246 }
247
248 public int hashCode()
249 {
250 // JCL book says this is computed using (only) the hashcodes of the
251 // protocol, host and file fields. Empirical evidence indicates this
252 // is probably XOR in JDK 1.1. In JDK 1.2 it seems to be a sum including
253 // the port.
254 //
255 // JDK 1.2 online doc infers that host could be null because it
256 // explicitly states that file cannot be null but is silent on host.
257 // A simple example with protocol "http" (hashcode 3213448), host null,
258 // file "/" (hashcode 47) produced a hashcode (3213494) which appeared
259 // to be the sum of the two hashcodes plus the port. Another example
260 // using "/index.html" for file bore this out; as well as "#" for file
261 // (which was reduced to "" with a hashcode of zero). A "" host also
262 // causes the port number and the two hashcodes to be summed.
263
264 if (hashCode != 0)
265 return hashCode; // Use cached value if available.
266 else
267 return (protocol.hashCode() + ((host == null) ? 0 : host.hashCode()) +
268 port + file.hashCode());
269 }
270
271 public URLConnection openConnection() throws IOException
272 {
273 return handler.openConnection(this);
274 }
275
276 public final InputStream openStream() throws IOException
277 {
278 return openConnection().getInputStream();
279 }
280
281 public boolean sameFile(URL other)
282 {
283 return handler.sameFile(this, other);
284 }
285
286 protected void set(String protocol, String host, int port, String file,
287 String ref)
288 {
289 // TBD: Theoretically, a poorly written StreamHandler could pass an
290 // invalid protocol. It will cause the handler to be set to null
291 // thus overriding a valid handler. Callers of this method should
292 // be aware of this.
293 this.handler = setURLStreamHandler(protocol);
294 this.protocol = protocol;
295 this.port = port;
296 this.host = host;
297 this.file = file;
298 this.ref = ref;
299 hashCode = hashCode(); // Used for serialization.
300 }
301
302 public static synchronized void
303 setURLStreamHandlerFactory(URLStreamHandlerFactory fac)
304 {
305 if (factory != null)
306 throw new Error("URLStreamHandlerFactory already set");
307
308 // Throw an exception if an extant security mgr precludes
309 // setting the factory.
310 SecurityManager s = System.getSecurityManager();
311 if (s != null)
312 s.checkSetFactory();
313 factory = fac;
314 }
315
316 public String toExternalForm()
317 {
318 // Identical to toString().
319 return handler.toExternalForm(this);
320 }
321
322 public String toString()
323 {
324 // Identical to toExternalForm().
325 return handler.toExternalForm(this);
326 }
327
328 private URLStreamHandler setURLStreamHandler(String protocol)
329 {
330 URLStreamHandler handler;
331
332 // See if a handler has been cached for this protocol.
333 if ((handler = (URLStreamHandler) handlers.get(protocol)) != null)
334 return handler;
335
336 // If a non-default factory has been set, use it to find the protocol.
337 if (factory != null)
338 handler = factory.createURLStreamHandler(protocol);
339 else if (protocol.equals ("core"))
340 {
341 handler = new gnu.gcj.protocol.core.Handler ();
342 }
343 else if (protocol.equals ("file"))
344 {
345 // This is an interesting case. It's tempting to think that we
346 // could call Class.forName ("gnu.gcj.protocol.file.Handler") to
347 // get the appropriate class. Unfortunately, if we do that the
348 // program will never terminate, because setURLStreamHandler is
349 // eventually called by Class.forName.
350 //
351 // Treating "file" as a special case is the minimum that will
352 // fix this problem. If other protocols are required in a
353 // statically linked application they will need to be handled in
354 // the same way as "file".
355 handler = new gnu.gcj.protocol.file.Handler ();
356 }
357
358 // Non-default factory may have returned null or a factory wasn't set.
359 // Use the default search algorithm to find a handler for this protocol.
360 if (handler == null)
361 {
362 // Get the list of packages to check and append our default handler
363 // to it, along with the JDK specified default as a last resort.
364 // Except in very unusual environments the JDK specified one shouldn't
365 // ever be needed (or available).
366 String propVal = System.getProperty("java.protocol.handler.pkgs");
367 propVal = (propVal == null) ? "" : (propVal + "|");
368 propVal = propVal + "gnu.gcj.protocol|sun.net.www.protocol";
369
370 StringTokenizer pkgPrefix = new StringTokenizer(propVal, "|");
371 do
372 {
373 String facName = pkgPrefix.nextToken() + "." + protocol +
374 ".Handler";
375 try
376 {
377 handler =
378 (URLStreamHandler) Class.forName(facName).newInstance();
379 }
380 catch (Exception e)
381 {
382 // Can't instantiate; handler still null, go on to next element.
383 }
384 } while ((handler == null ||
385 ! (handler instanceof URLStreamHandler)) &&
386 pkgPrefix.hasMoreTokens());
387 }
388
389 // Update the hashtable with the new protocol handler.
390 if (handler != null)
391 if (handler instanceof URLStreamHandler)
392 handlers.put(protocol, handler);
393 else
394 handler = null;
395
396 return handler;
397 }
398
399 private void readObject(ObjectInputStream ois)
400 throws IOException, ClassNotFoundException
401 {
402 ois.defaultReadObject();
403 this.handler = setURLStreamHandler(protocol);
404 if (this.handler == null)
405 throw new IOException("Handler for protocol " + protocol + " not found");
406 }
407
408 private void writeObject(ObjectOutputStream oos) throws IOException
409 {
410 oos.defaultWriteObject();
411 }
412}
Note: See TracBrowser for help on using the repository browser.