source: trunk/gcc/libjava/java/net/URLConnection.java

Last change on this file was 1392, checked in by bird, 21 years ago

This commit was generated by cvs2svn to compensate for changes in r1391,
which included commits to RCS files with non-trunk default branches.

  • Property cvs2svn:cvs-rev set to 1.1.1.2
  • Property svn:eol-style set to native
  • Property svn:executable set to *
File size: 20.4 KB
Line 
1// URLConnection.java - Superclass of all communications links between
2// an application and a URL.
3
4/* Copyright (C) 1999, 2000 Free Software Foundation
5
6 This file is part of libgcj.
7
8This software is copyrighted work licensed under the terms of the
9Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
10details. */
11
12package java.net;
13
14import java.io.*;
15import java.text.ParsePosition;
16import java.text.SimpleDateFormat;
17import java.util.Date;
18import java.util.Locale;
19import java.util.Hashtable;
20import java.util.Map;
21import java.util.StringTokenizer;
22import java.security.Permission;
23import java.security.AllPermission;
24import gnu.gcj.io.MimeTypes;
25
26/**
27 * @author Warren Levy <warrenl@cygnus.com>
28 * @date March 5, 1999.
29 */
30
31/**
32 * Written using on-line Java Platform 1.2 API Specification, as well
33 * as "The Java Class Libraries", 2nd edition (Addison-Wesley, 1998).
34 * Status: One guessContentTypeFrom... methods not implemented.
35 * getContent method assumes content type from response; see comment there.
36 */
37
38public abstract class URLConnection
39{
40 protected URL url;
41 protected boolean doInput = true;
42 protected boolean doOutput = false;
43 protected boolean allowUserInteraction;
44 protected boolean useCaches;
45 protected long ifModifiedSince = 0L;
46 protected boolean connected = false;
47 private static boolean defaultAllowUserInteraction = false;
48 private static boolean defaultUseCaches = true;
49 private static FileNameMap fileNameMap; // Set by the URLConnection subclass.
50 private static ContentHandlerFactory factory;
51 private static ContentHandler contentHandler;
52 private static Hashtable handlers = new Hashtable();
53 private static Locale locale;
54 private static SimpleDateFormat dateFormat1, dateFormat2, dateFormat3;
55 private static boolean dateformats_initialized = false;
56
57 /**
58 * Creates a URL connection to a given URL. A real connection is not made.
59 * Use #connect to do this.
60 *
61 * @param url The Object to create the URL connection to
62 *
63 * @see URLConnection:connect
64 */
65 protected URLConnection(URL url)
66 {
67 this.url = url;
68 allowUserInteraction = defaultAllowUserInteraction;
69 useCaches = defaultUseCaches;
70 }
71
72 /**
73 * Creates a real connection to the object references by the URL given
74 * to the constructor
75 *
76 * @exception IOException If an error occurs
77 */
78 public abstract void connect() throws IOException;
79
80 /**
81 * Returns ths URL to the object.
82 */
83 public URL getURL()
84 {
85 return url;
86 }
87
88 /**
89 * Returns the value of the content-length header field
90 */
91 public int getContentLength()
92 {
93 return getHeaderFieldInt("content-length", -1);
94 }
95
96 /**
97 * Returns the value of the content-type header field
98 */
99 public String getContentType()
100 {
101 return getHeaderField("content-type");
102 }
103
104 /**
105 * Returns the value of the content-encoding header field
106 */
107 public String getContentEncoding()
108 {
109 return getHeaderField("content-encoding");
110 }
111
112 /**
113 * Returns the value of the expires header field
114 */
115 public long getExpiration()
116 {
117 return getHeaderFieldDate("expiration", 0L);
118 }
119
120 /**
121 * Returns the value of the date header field
122 */
123 public long getDate()
124 {
125 return getHeaderFieldDate("date", 0L);
126 }
127
128 /**
129 * Returns the value of the last-modified header field
130 */
131 public long getLastModified()
132 {
133 return getHeaderFieldDate("last-modified", 0L);
134 }
135
136 /**
137 * Returns the value of the n-th header field
138 *
139 * @param num The number of the header field
140 */
141 public String getHeaderField(int num)
142 {
143 // Subclasses for specific protocols override this.
144 return null;
145 }
146
147 /**
148 * Returns the value of the header filed specified by name
149 *
150 * @param name The name of the header field
151 */
152 public String getHeaderField(String name)
153 {
154 // Subclasses for specific protocols override this.
155 return null;
156 }
157
158 /**
159 * Returns a map of all sent header fields
160 *
161 * @since 1.4
162 */
163 public Map getHeaderFields()
164 {
165 // Subclasses for specific protocols override this.
166 return null;
167 }
168
169 /**
170 * Returns the value of the header filed name as int.
171 *
172 * @param name The name of the header field
173 * @param val The default value
174 *
175 * @return Returns the value of the header filed or the default value
176 * if the field is missing or malformed
177 */
178 public int getHeaderFieldInt(String name, int val)
179 {
180 String str = getHeaderField(name);
181 try
182 {
183 if (str != null)
184 val = Integer.parseInt(str);
185 }
186 catch (NumberFormatException e)
187 {
188 ; // Do nothing; val is the default.
189 }
190 return val;
191 }
192
193 /**
194 * Returns the value of a header field parsed as date. The result is then
195 * number of milliseconds since January 1st, 1970 GMT.
196 *
197 * @param name The name of the header field
198 * @param val The dafault date
199 *
200 * @return Returns the date value of the header filed or the default value
201 * if the field is missing or malformed
202 */
203 public long getHeaderFieldDate(String name, long val)
204 {
205 if (! dateformats_initialized)
206 initializeDateFormats();
207 String str = getHeaderField(name);
208 if (str != null)
209 {
210 Date date;
211 if ((date = dateFormat1.parse(str, new ParsePosition(0))) != null)
212 val = date.getTime();
213 else if ((date = dateFormat2.parse(str, new ParsePosition(0))) != null)
214 val = date.getTime();
215 else if ((date = dateFormat3.parse(str, new ParsePosition(0))) != null)
216 val = date.getTime();
217 }
218 return val;
219 }
220
221 /**
222 * Returns the key of the n-th header field
223 *
224 * @param num The number of the header field
225 */
226 public String getHeaderFieldKey(int num)
227 {
228 // Subclasses for specific protocols override this.
229 return null;
230 }
231
232 /**
233 * Retrieves the content of this URLConnection
234 *
235 * @exception IOException If an error occurs
236 * @exception UnknownServiceException If the protocol does not support the
237 * content type
238 */
239 public Object getContent() throws IOException
240 {
241 // FIXME: Doc indicates that other criteria should be applied as
242 // heuristics to determine the true content type, e.g. see
243 // guessContentTypeFromName() and guessContentTypeFromStream methods
244 // as well as FileNameMap class & fileNameMap field & get/set methods.
245 String cType = getContentType();
246 contentHandler = setContentHandler(cType);
247 if (contentHandler == null)
248 return getInputStream();
249
250 return contentHandler.getContent(this);
251 }
252
253 /**
254 * Retrieves the content of this URLConnection
255 *
256 * @exception IOException If an error occurs
257 * @exception UnknownServiceException If the protocol does not support the
258 * content type
259 */
260 public Object getContent(Class[] classes) throws IOException
261 {
262 // FIXME: implement this
263 return getContent ();
264 }
265
266 /**
267 * Returns a permission object representing the permission necessary to make
268 * the connection represented by this object. This method returns null if no
269 * permission is required to make the connection.
270 *
271 * @exception IOException If the computation of the permission requires
272 * network or file I/O and an exception occurs while computing it
273 */
274 public Permission getPermission() throws IOException
275 {
276 // Subclasses may override this.
277 return new java.security.AllPermission();
278 }
279
280 /**
281 * Returns the input stream of the URL connection
282 *
283 * @exception IOException If an error occurs
284 * @exception UnknownServiceException If the protocol does not support input
285 */
286 public InputStream getInputStream() throws IOException
287 {
288 // Subclasses for specific protocols override this.
289 throw new UnknownServiceException("Protocol " + url.getProtocol() +
290 " does not support input.");
291 }
292
293 /**
294 * Returns the output stream of the URL connection
295 *
296 * @exception IOException If an error occurs
297 * @exception UnknownServiceException If the protocol does not support output
298 */
299 public OutputStream getOutputStream() throws IOException
300 {
301 // Subclasses for specific protocols override this.
302 throw new UnknownServiceException("Protocol " + url.getProtocol() +
303 " does not support output.");
304 }
305
306 /**
307 * Returns a string representation of the URL connection object
308 */
309 public String toString()
310 {
311 return this.getClass().getName() + ":" + url.toString();
312 }
313
314 /**
315 * Sets tha value of the doInput field.
316 *
317 * @param doinput The new value of the doInput field
318 *
319 * @exception IllegalStateException If already connected
320 */
321 public void setDoInput(boolean doinput)
322 {
323 if (connected)
324 throw new IllegalStateException ("Already connected");
325
326 doInput = doinput;
327 }
328
329 /**
330 * Returns the current value of the doInput field
331 */
332 public boolean getDoInput()
333 {
334 return doInput;
335 }
336
337 /**
338 * Sets the value of the doOutput field
339 *
340 * @param dooutput The new value of the doOutput field
341 *
342 * @exception IllegalStateException If already connected
343 */
344 public void setDoOutput(boolean dooutput)
345 {
346 if (connected)
347 throw new IllegalStateException ("Already connected");
348
349 doOutput = dooutput;
350 }
351
352 /**
353 * Returns the current value of the doOutput field
354 */
355 public boolean getDoOutput()
356 {
357 return doOutput;
358 }
359
360 /**
361 * Sets a new value to the allowUserInteraction field
362 *
363 * @param allowed The new value
364 *
365 * @exception IllegalStateException If already connected
366 */
367 public void setAllowUserInteraction(boolean allowed)
368 {
369 if (connected)
370 throw new IllegalStateException ("Already connected");
371
372 allowUserInteraction = allowed;
373 }
374
375 /**
376 * Returns the current value of the allowUserInteraction field
377 */
378 public boolean getAllowUserInteraction()
379 {
380 return allowUserInteraction;
381 }
382
383 /**
384 * Sets the default value if the allowUserInteraction field
385 *
386 * @param allowed The new default value
387 */
388 public static void setDefaultAllowUserInteraction(boolean allowed)
389 {
390 defaultAllowUserInteraction = allowed;
391 }
392
393 /**
394 * Returns the default value of the allowUserInteraction field
395 */
396 public static boolean getDefaultAllowUserInteraction()
397 {
398 return defaultAllowUserInteraction;
399 }
400
401 /**
402 * Sets a new value to the useCaches field
403 *
404 * @param usecaches The new value
405 *
406 * @exception IllegalStateException If already connected
407 */
408 public void setUseCaches(boolean usecaches)
409 {
410 if (connected)
411 throw new IllegalStateException ("Already connected");
412
413 useCaches = usecaches;
414 }
415
416 /**
417 * The current value of the useCaches field
418 */
419 public boolean getUseCaches()
420 {
421 return useCaches;
422 }
423
424 /**
425 * Sets the value of the ifModifiedSince field
426 *
427 * @param ifmodifiedsince The new value in milliseconds
428 * since January 1, 1970 GMT
429 *
430 * @exception IllegalStateException If already connected
431 */
432 public void setIfModifiedSince(long ifmodifiedsince)
433 {
434 if (connected)
435 throw new IllegalStateException ("Already connected");
436
437 ifModifiedSince = ifmodifiedsince;
438 }
439
440 /**
441 * Returns the current value of the ifModifiedSince field
442 */
443 public long getIfModifiedSince()
444 {
445 return ifModifiedSince;
446 }
447
448 /**
449 * Returns the default value of the useCaches field
450 */
451 public boolean getDefaultUseCaches()
452 {
453 return defaultUseCaches;
454 }
455
456 /**
457 * Sets the default value of the useCaches field
458 *
459 * @param defaultusecaches The new default value
460 */
461 public void setDefaultUseCaches(boolean defaultusecaches)
462 {
463 defaultUseCaches = defaultusecaches;
464 }
465
466 /**
467 * Sets a property specified by key to value.
468 *
469 * @param key Key of the property to set
470 * @param value Value of the Property to set
471 *
472 * @exception IllegalStateException If already connected
473 * @exception NullPointerException If key is null
474 *
475 * @see URLConnection:getRequestProperty(String key)
476 * @see URLConnection:addRequestProperty(String key, String value)
477 */
478 public void setRequestProperty(String key, String value)
479 {
480 if (connected)
481 throw new IllegalStateException ("Already connected");
482
483 // Do nothing unless overridden by subclasses that support setting
484 // header fields in the request.
485 }
486
487 /**
488 * Sets a property specified by key to value. If the property key already
489 * is assigned to a value it does nothing.
490 *
491 * @param key Key of the property to add
492 * @param value Value of the Property to add
493 *
494 * @exception IllegalStateException If already connected
495 * @exception NullPointerException If key is null
496 *
497 * @see URLConnection:getRequestProperty(String key)
498 * @see URLConnection:setRequestProperty(String key, String value)
499 *
500 * @since 1.4
501 */
502 public void addRequestProperty(String key, String value)
503 {
504 if (connected)
505 throw new IllegalStateException ("Already connected");
506
507 if (getRequestProperty (key) == null)
508 {
509 setRequestProperty (key, value);
510 }
511 }
512
513 /**
514 * Returns a property value specified by key.
515 *
516 * @param key Key of the property to return
517 *
518 * @exception IllegalStateException If already connected
519 *
520 * @see URLConnection:setRequestProperty(String key, String value)
521 * @see URLConnection:addRequestProperty(String key, String value)
522 *
523 * @return Value of the property.
524 */
525 public String getRequestProperty(String key)
526 {
527 if (connected)
528 throw new IllegalStateException ("Already connected");
529
530 // Overridden by subclasses that support reading header fields from the
531 // request.
532 return null;
533 }
534
535 /**
536 * Returns a map that contains all properties of the request
537 *
538 * @exception IllegalStateException If already connected
539 *
540 * @return The map of properties
541 */
542 public Map getRequestProperties()
543 {
544 // Overridden by subclasses that support reading header fields from the
545 // request.
546 return null;
547 }
548
549 /**
550 * Defines a default request property
551 *
552 * @param key The key of the property
553 * @param value The value of the property
554 *
555 * @deprecated 1.3 The method setRequestProperty should be used instead
556 *
557 * @see URLConnection:setRequestProperty
558 */
559 public static void setDefaultRequestProperty(String key, String value)
560 {
561 // Do nothing unless overridden by subclasses that support setting
562 // default request properties.
563 }
564
565 /**
566 * Returns the value of a default request property
567 *
568 * @param key The key of the default property
569 *
570 * @return The value of the default property or null if not available
571 *
572 * @deprecated 1.3 The method getRequestProperty should be used instead
573 *
574 * @see URLConnection:getRequestProperty
575 */
576 public static String getDefaultRequestProperty(String key)
577 {
578 // Overridden by subclasses that support default request properties.
579 return null;
580 }
581
582 /**
583 * Sets a ContentHandlerFactory
584 *
585 * @param fac The ContentHandlerFactory
586 *
587 * @exception Error If the factory has already been defined
588 * @exception SecurityException If a security manager exists and its
589 * checkSetFactory method doesn't allow the operation
590 */
591 public static void setContentHandlerFactory(ContentHandlerFactory fac)
592 {
593 if (factory != null)
594 throw new Error("ContentHandlerFactory already set");
595
596 // Throw an exception if an extant security mgr precludes
597 // setting the factory.
598 SecurityManager s = System.getSecurityManager();
599 if (s != null)
600 s.checkSetFactory();
601 factory = fac;
602 }
603
604 /**
605 * Tries to determine the content type of an object, based on the
606 * specified file name
607 *
608 * @param fname The filename to guess the content type from
609 *
610 * @specnote public since JDK 1.4
611 */
612 public static String guessContentTypeFromName(String fname)
613 {
614 int dot = fname.lastIndexOf (".");
615
616 if (dot != -1)
617 {
618 if (dot == fname.length())
619 return ("application/octet-stream");
620 else
621 fname = fname.substring (dot + 1);
622 }
623
624 String type = MimeTypes.getMimeTypeFromExtension (fname);
625
626 if (type == null)
627 return("application/octet-stream");
628
629 return(type);
630 }
631
632 /**
633 * Tries to guess the content type of an object, based on the characters
634 * at the beginning of then input stream
635 *
636 * @param is The input stream to guess from
637 *
638 * @exception IOException If an error occurs
639 */
640 public static String guessContentTypeFromStream(InputStream is)
641 throws IOException
642 {
643 is.mark(1024);
644 // FIXME: Implement this. Use system mimetype informations (like "file").
645 is.reset();
646 return null;
647 }
648
649 /**
650 * Returns a filename map (a mimetable)
651 *
652 * @since 1.2
653 */
654 public static FileNameMap getFileNameMap()
655 {
656 return fileNameMap;
657 }
658
659 /**
660 * Sets a FileNameMap
661 *
662 * @param map The new FileNameMap
663 *
664 * @exception SecurityException If a security manager exists and its
665 * checkSetFactory method doesn't allow the operation
666 *
667 * @since 1.2
668 */
669 public static void setFileNameMap(FileNameMap map)
670 {
671 // Throw an exception if an extant security mgr precludes
672 // setting the factory.
673 SecurityManager s = System.getSecurityManager();
674 if (s != null)
675 s.checkSetFactory();
676
677 fileNameMap = map;
678 }
679
680 private ContentHandler setContentHandler(String contentType)
681 {
682 ContentHandler handler;
683
684 // No content type so just handle it as the default.
685 if (contentType == null || contentType == "")
686 return null;
687
688 // See if a handler has been cached for this content type.
689 // For efficiency, if a content type has been searched for but not
690 // found, it will be in the hash table but as the contentType String
691 // instead of a ContentHandler.
692 if ((handler = (ContentHandler) handlers.get(contentType)) != null)
693 if (handler instanceof ContentHandler)
694 return handler;
695 else
696 return null;
697
698 // If a non-default factory has been set, use it to find the content type.
699 if (factory != null)
700 handler = factory.createContentHandler(contentType);
701
702 // Non-default factory may have returned null or a factory wasn't set.
703 // Use the default search algorithm to find a handler for this content type.
704 if (handler == null)
705 {
706 // Get the list of packages to check and append our default handler
707 // to it, along with the JDK specified default as a last resort.
708 // Except in very unusual environments the JDK specified one shouldn't
709 // ever be needed (or available).
710 String propVal = System.getProperty("java.content.handler.pkgs");
711 propVal = (propVal == null) ? "" : (propVal + "|");
712 propVal = propVal + "gnu.gcj.content|sun.net.www.content";
713
714 // Replace the '/' character in the content type with '.' and
715 // all other non-alphabetic, non-numeric characters with '_'.
716 StringTokenizer pkgPrefix = new StringTokenizer(propVal, "|");
717 char[] cArray = contentType.toCharArray();
718 for (int i = 0; i < cArray.length; i++)
719 {
720 if (cArray[i] == '/')
721 cArray[i] = '.';
722 else if (! ((cArray[i] >= 'A' && cArray[i] <= 'Z') ||
723 (cArray[i] >= 'a' && cArray[i] <= 'z') ||
724 (cArray[i] >= '0' && cArray[i] <= '9')))
725 cArray[i] = '_';
726 }
727 String contentClass = new String(cArray);
728
729 // See if a class of this content type exists in any of the packages.
730 do
731 {
732 String facName = pkgPrefix.nextToken() + "." + contentClass;
733 try
734 {
735 handler =
736 (ContentHandler) Class.forName(facName).newInstance();
737 }
738 catch (Exception e)
739 {
740 // Can't instantiate; handler still null, go on to next element.
741 }
742 } while ((handler == null ||
743 ! (handler instanceof ContentHandler)) &&
744 pkgPrefix.hasMoreTokens());
745 }
746
747 // Update the hashtable with the new content handler.
748 if (handler != null && handler instanceof ContentHandler)
749 {
750 handlers.put(contentType, handler);
751 return handler;
752 }
753
754 // For efficiency on subsequent searches, put a dummy entry in the hash
755 // table for content types that don't have a non-default ContentHandler.
756 handlers.put(contentType, contentType);
757 return null;
758 }
759
760 // We don't put these in a static initializer, because it creates problems
761 // with initializer co-dependency: SimpleDateFormat's constructors eventually
762 // depend on URLConnection (via the java.text.*Symbols classes).
763 private synchronized void initializeDateFormats()
764 {
765 if (dateformats_initialized)
766 return;
767 locale = new Locale("En", "Us", "Unix");
768 dateFormat1 = new SimpleDateFormat("EEE, dd MMM yyyy hh:mm:ss 'GMT'",
769 locale);
770 dateFormat2 = new SimpleDateFormat("EEEE, dd-MMM-yy hh:mm:ss 'GMT'",
771 locale);
772 dateFormat3 = new SimpleDateFormat("EEE MMM d hh:mm:ss yyyy", locale);
773 dateformats_initialized = true;
774 }
775}
Note: See TracBrowser for help on using the repository browser.