GNU Classpath (0.20) | |
Frames | No Frames |
1: /* URLConnection.java -- Abstract superclass for reading from URL's 2: Copyright (C) 1998, 2002, 2003, 2004 Free Software Foundation, Inc. 3: 4: This file is part of GNU Classpath. 5: 6: GNU Classpath is free software; you can redistribute it and/or modify 7: it under the terms of the GNU General Public License as published by 8: the Free Software Foundation; either version 2, or (at your option) 9: any later version. 10: 11: GNU Classpath is distributed in the hope that it will be useful, but 12: WITHOUT ANY WARRANTY; without even the implied warranty of 13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14: General Public License for more details. 15: 16: You should have received a copy of the GNU General Public License 17: along with GNU Classpath; see the file COPYING. If not, write to the 18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 19: 02110-1301 USA. 20: 21: Linking this library statically or dynamically with other modules is 22: making a combined work based on this library. Thus, the terms and 23: conditions of the GNU General Public License cover the whole 24: combination. 25: 26: As a special exception, the copyright holders of this library give you 27: permission to link this library with independent modules to produce an 28: executable, regardless of the license terms of these independent 29: modules, and to copy and distribute the resulting executable under 30: terms of your choice, provided that you also meet, for each linked 31: independent module, the terms and conditions of the license of that 32: module. An independent module is a module which is not derived from 33: or based on this library. If you modify this library, you may extend 34: this exception to your version of the library, but you are not 35: obligated to do so. If you do not wish to do so, delete this 36: exception statement from your version. */ 37: 38: 39: package java.net; 40: 41: import java.io.IOException; 42: import java.io.InputStream; 43: import java.io.OutputStream; 44: import java.security.AllPermission; 45: import java.security.Permission; 46: import java.text.ParsePosition; 47: import java.text.SimpleDateFormat; 48: import java.util.Collections; 49: import java.util.Date; 50: import java.util.Locale; 51: import java.util.Map; 52: 53: /** 54: * Written using on-line Java Platform 1.2 API Specification, as well 55: * as "The Java Class Libraries", 2nd edition (Addison-Wesley, 1998). 56: * Status: One guessContentTypeFrom... methods not implemented. 57: * getContent method assumes content type from response; see comment there. 58: */ 59: /** 60: * This class models a connection that retrieves the information pointed 61: * to by a URL object. This is typically a connection to a remote node 62: * on the network, but could be a simple disk read. 63: * <p> 64: * A URLConnection object is normally created by calling the openConnection() 65: * method of a URL object. This method is somewhat misnamed because it does 66: * not actually open the connection. Instead, it return an unconnected 67: * instance of this object. The caller then has the opportunity to set 68: * various connection options prior to calling the actual connect() method. 69: * <p> 70: * After the connection has been opened, there are a number of methods in 71: * this class that access various attributes of the data, typically 72: * represented by headers sent in advance of the actual data itself. 73: * <p> 74: * Also of note are the getInputStream and getContent() methods which allow 75: * the caller to retrieve the actual data from the connection. Note that 76: * for some types of connections, writing is also allowed. The setDoOutput() 77: * method must be called prior to connecing in order to enable this, then 78: * the getOutputStream method called after the connection in order to 79: * obtain a stream to write the output to. 80: * <p> 81: * The getContent() method is of particular note. This method returns an 82: * Object that encapsulates the data returned. There is no way do determine 83: * the type of object that will be returned in advance. This is determined 84: * by the actual content handlers as described in the description of that 85: * method. 86: * 87: * @author Aaron M. Renn (arenn@urbanophile.com) 88: * @author Warren Levy (warrenl@cygnus.com) 89: */ 90: public abstract class URLConnection 91: { 92: /** 93: * This is an object that maps filenames to MIME types. The interface 94: * to do this is implemented by this class, so just create an empty 95: * instance and store it here. 96: */ 97: private static FileNameMap fileNameMap; 98: 99: /** 100: * This is the ContentHandlerFactory set by the caller, if any 101: */ 102: private static ContentHandlerFactory factory; 103: 104: /** 105: * This is the default value that will be used to determine whether or 106: * not user interaction should be allowed. 107: */ 108: private static boolean defaultAllowUserInteraction; 109: 110: /** 111: * This is the default flag indicating whether or not to use caches to 112: * store the data returned from a server 113: */ 114: private static boolean defaultUseCaches = true; 115: 116: /** 117: * This variable determines whether or not interaction is allowed with 118: * the user. For example, to prompt for a username and password. 119: */ 120: protected boolean allowUserInteraction; 121: 122: /** 123: * Indicates whether or not a connection has been established to the 124: * destination specified in the URL 125: */ 126: protected boolean connected; 127: 128: /** 129: * Indicates whether or not input can be read from this URL 130: */ 131: protected boolean doInput = true; 132: 133: /** 134: * Indicates whether or not output can be sent to this URL 135: */ 136: protected boolean doOutput; 137: 138: /** 139: * If this flag is set, the protocol is allowed to cache data whenever 140: * it can (caching is not guaranteed). If it is not set, the protocol 141: * must a get a fresh copy of the data. 142: * <p> 143: * This field is set by the setUseCaches method and returned by the 144: * getUseCaches method. 145: * 146: * Its default value is that determined by the last invocation of 147: * setDefaultUseCaches 148: */ 149: protected boolean useCaches; 150: 151: /** 152: * If this value is non-zero, then the connection will only attempt to 153: * fetch the document pointed to by the URL if the document has been 154: * modified more recently than the date set in this variable. That date 155: * should be specified as the number of seconds since 1/1/1970 GMT. 156: */ 157: protected long ifModifiedSince; 158: 159: /** 160: * This is the URL associated with this connection 161: */ 162: protected URL url; 163: private static SimpleDateFormat[] dateFormats; 164: private static boolean dateformats_initialized; 165: 166: /* Cached ParsePosition, used when parsing dates. */ 167: private ParsePosition position; 168: 169: /** 170: * Creates a URL connection to a given URL. A real connection is not made. 171: * Use #connect to do this. 172: * 173: * @param url The Object to create the URL connection to 174: * 175: * @see URLConnection#connect() 176: */ 177: protected URLConnection(URL url) 178: { 179: // Set up all our instance variables 180: this.url = url; 181: allowUserInteraction = defaultAllowUserInteraction; 182: useCaches = defaultUseCaches; 183: } 184: 185: /** 186: * Establishes the actual connection to the URL associated with this 187: * connection object 188: * 189: * @exception IOException if an error occurs 190: */ 191: public abstract void connect() throws IOException; 192: 193: /** 194: * Returns the URL object associated with this connection 195: * 196: * @return The URL for this connection. 197: */ 198: public URL getURL() 199: { 200: return url; 201: } 202: 203: /** 204: * Returns the value of the content-length header field or -1 if the value 205: * is not known or not present. 206: * 207: * @return The content-length field 208: */ 209: public int getContentLength() 210: { 211: return getHeaderFieldInt("content-length", -1); 212: } 213: 214: /** 215: * Returns the the content-type of the data pointed to by the URL. This 216: * method first tries looking for a content-type header. If that is not 217: * present, it attempts to use the file name to determine the content's 218: * MIME type. If that is unsuccessful, the method returns null. The caller 219: * may then still attempt to determine the MIME type by a call to 220: * guessContentTypeFromStream() 221: * 222: * @return The content MIME type 223: */ 224: public String getContentType() 225: { 226: return getHeaderField("content-type"); 227: } 228: 229: /** 230: * Returns the value of the content-encoding field or null if it is not 231: * known or not present. 232: * 233: * @return The content-encoding field 234: */ 235: public String getContentEncoding() 236: { 237: return getHeaderField("content-encoding"); 238: } 239: 240: /** 241: * Returns the value of the expires header or 0 if not known or present. 242: * If populated, the return value is number of seconds since midnight 243: * on 1/1/1970 GMT. 244: * 245: * @return The expiration time. 246: */ 247: public long getExpiration() 248: { 249: return getHeaderFieldDate("expires", 0L); 250: } 251: 252: /** 253: * Returns the date of the document pointed to by the URL as reported in 254: * the date field of the header or 0 if the value is not present or not 255: * known. If populated, the return value is number of seconds since 256: * midnight on 1/1/1970 GMT. 257: * 258: * @return The document date 259: */ 260: public long getDate() 261: { 262: return getHeaderFieldDate("date", 0L); 263: } 264: 265: /** 266: * Returns the value of the last-modified header field or 0 if not known known 267: * or not present. If populated, the return value is the number of seconds 268: * since midnight on 1/1/1970. 269: * 270: * @return The last modified time 271: */ 272: public long getLastModified() 273: { 274: return getHeaderFieldDate("last-modified", 0L); 275: } 276: 277: /** 278: * Return a String representing the header value at the specified index. 279: * This allows the caller to walk the list of header fields. The analogous 280: * getHeaderFieldKey(int) method allows access to the corresponding key 281: * for this header field 282: * 283: * @param index The index into the header field list to retrieve the value for 284: * 285: * @return The header value or null if index is past the end of the headers 286: */ 287: public String getHeaderField(int index) 288: { 289: // Subclasses for specific protocols override this. 290: return null; 291: } 292: 293: /** 294: * Returns a String representing the value of the header field having 295: * the named key. Returns null if the header field does not exist. 296: * 297: * @param name The key of the header field 298: * 299: * @return The value of the header field as a String 300: */ 301: public String getHeaderField(String name) 302: { 303: // Subclasses for specific protocols override this. 304: return null; 305: } 306: 307: /** 308: * Returns a map of all sent header fields 309: * 310: * @return all header fields 311: * 312: * @since 1.4 313: */ 314: public Map getHeaderFields() 315: { 316: // Subclasses for specific protocols override this. 317: return Collections.EMPTY_MAP; 318: } 319: 320: /** 321: * Returns the value of the named header field as an int. If the field 322: * is not present or cannot be parsed as an integer, the default value 323: * will be returned. 324: * 325: * @param name The header field key to lookup 326: * @param defaultValue The defaule value if the header field is not found 327: * or can't be parsed. 328: * 329: * @return The value of the header field or the default value if the field 330: * is missing or malformed 331: */ 332: public int getHeaderFieldInt(String name, int defaultValue) 333: { 334: String value = getHeaderField(name); 335: 336: if (value == null) 337: return defaultValue; 338: 339: try 340: { 341: return Integer.parseInt(value); 342: } 343: catch (NumberFormatException e) 344: { 345: return defaultValue; 346: } 347: } 348: 349: /** 350: * Returns the value of the named header field as a date. This date will 351: * be the number of seconds since midnight 1/1/1970 GMT or the default 352: * value if the field is not present or cannot be converted to a date. 353: * 354: * @param name The name of the header field 355: * @param defaultValue The default date if the header field is not found 356: * or can't be converted. 357: * 358: * @return Returns the date value of the header filed or the default value 359: * if the field is missing or malformed 360: */ 361: public long getHeaderFieldDate(String name, long defaultValue) 362: { 363: if (! dateformats_initialized) 364: initializeDateFormats(); 365: 366: if (position == null) 367: position = new ParsePosition(0); 368: 369: long result = defaultValue; 370: String str = getHeaderField(name); 371: 372: if (str != null) 373: { 374: for (int i = 0; i < dateFormats.length; i++) 375: { 376: SimpleDateFormat df = dateFormats[i]; 377: position.setIndex(0); 378: position.setErrorIndex(0); 379: Date date = df.parse(str, position); 380: if (date != null) 381: return date.getTime(); 382: } 383: } 384: 385: return result; 386: } 387: 388: /** 389: * Returns a String representing the header key at the specified index. 390: * This allows the caller to walk the list of header fields. The analogous 391: * getHeaderField(int) method allows access to the corresponding value for 392: * this tag. 393: * 394: * @param index The index into the header field list to retrieve the key for. 395: * 396: * @return The header field key or null if index is past the end 397: * of the headers. 398: */ 399: public String getHeaderFieldKey(int index) 400: { 401: // Subclasses for specific protocols override this. 402: return null; 403: } 404: 405: /** 406: * This method returns the content of the document pointed to by the 407: * URL as an Object. The type of object depends on the MIME type of 408: * the object and particular content hander loaded. Most text type 409: * content handlers will return a subclass of 410: * <code>InputStream</code>. Images usually return a class that 411: * implements <code>ImageProducer</code>. There is not guarantee 412: * what type of object will be returned, however. 413: * 414: * <p>This class first determines the MIME type of the content, then 415: * creates a ContentHandler object to process the input. If the 416: * <code>ContentHandlerFactory</code> is set, then that object is 417: * called to load a content handler, otherwise a class called 418: * gnu.java.net.content.<content_type> is tried. If this 419: * handler does not exist, the method will simple return the 420: * <code>InputStream</code> returned by 421: * <code>getInputStream()</code>. Note that the default 422: * implementation of <code>getInputStream()</code> throws a 423: * <code>UnknownServiceException</code> so subclasses are encouraged 424: * to override this method.</p> 425: * 426: * @return the content 427: * 428: * @exception IOException If an error with the connection occurs. 429: * @exception UnknownServiceException If the protocol does not support the 430: * content type at all. 431: */ 432: public Object getContent() throws IOException 433: { 434: if (!connected) 435: connect(); 436: 437: // FIXME: Doc indicates that other criteria should be applied as 438: // heuristics to determine the true content type, e.g. see 439: // guessContentTypeFromName() and guessContentTypeFromStream methods 440: // as well as FileNameMap class & fileNameMap field & get/set methods. 441: String type = getContentType(); 442: ContentHandler ch = getContentHandler(type); 443: 444: if (ch != null) 445: return ch.getContent(this); 446: 447: return getInputStream(); 448: } 449: 450: /** 451: * Retrieves the content of this URLConnection 452: * 453: * @param classes The allowed classes for the content 454: * 455: * @return the content 456: * 457: * @exception IOException If an error occurs 458: * @exception UnknownServiceException If the protocol does not support the 459: * content type 460: */ 461: public Object getContent(Class[] classes) throws IOException 462: { 463: // FIXME: implement this 464: return getContent(); 465: } 466: 467: /** 468: * This method returns a <code>Permission</code> object representing the 469: * permissions required to access this URL. This method returns 470: * <code>java.security.AllPermission</code> by default. Subclasses should 471: * override it to return a more specific permission. For example, an 472: * HTTP URL should return an instance of <code>SocketPermission</code> 473: * for the appropriate host and port. 474: * <p> 475: * Note that because of items such as HTTP redirects, the permission 476: * object returned might be different before and after connecting. 477: * 478: * @return A Permission object 479: * 480: * @exception IOException If the computation of the permission requires 481: * network or file I/O and an exception occurs while computing it 482: */ 483: public Permission getPermission() throws IOException 484: { 485: // Subclasses may override this. 486: return new AllPermission(); 487: } 488: 489: /** 490: * Returns an InputStream for this connection. As this default 491: * implementation returns null, subclasses should override this method 492: * 493: * @return An InputStream for this connection 494: * 495: * @exception IOException If an error occurs 496: * @exception UnknownServiceException If the protocol does not support input 497: */ 498: public InputStream getInputStream() throws IOException 499: { 500: // Subclasses for specific protocols override this. 501: throw new UnknownServiceException("Protocol " + url.getProtocol() 502: + " does not support input."); 503: } 504: 505: /** 506: * Returns an OutputStream for this connection. As this default 507: * implementation returns null, subclasses should override this method 508: * 509: * @return An OutputStream for this connection 510: * 511: * @exception IOException If an error occurs 512: * @exception UnknownServiceException If the protocol does not support output 513: */ 514: public OutputStream getOutputStream() throws IOException 515: { 516: // Subclasses for specific protocols override this. 517: throw new UnknownServiceException("Protocol " + url.getProtocol() 518: + " does not support output."); 519: } 520: 521: /** 522: * The methods prints the value of this object as a String by calling the 523: * toString() method of its associated URL. Overrides Object.toString() 524: * 525: * @return A String representation of this object 526: */ 527: public String toString() 528: { 529: return this.getClass().getName() + ":" + url.toString(); 530: } 531: 532: /** 533: * Sets the value of a flag indicating whether or not input is going 534: * to be done for this connection. This default to true unless the 535: * doOutput flag is set to false, in which case this defaults to false. 536: * 537: * @param input <code>true</code> if input is to be done, 538: * <code>false</code> otherwise 539: * 540: * @exception IllegalStateException If already connected 541: */ 542: public void setDoInput(boolean input) 543: { 544: if (connected) 545: throw new IllegalStateException("Already connected"); 546: 547: doInput = input; 548: } 549: 550: /** 551: * Returns the value of a flag indicating whether or not input is going 552: * to be done for this connection. This default to true unless the 553: * doOutput flag is set to false, in which case this defaults to false. 554: * 555: * @return true if input is to be done, false otherwise 556: */ 557: public boolean getDoInput() 558: { 559: return doInput; 560: } 561: 562: /** 563: * Sets a boolean flag indicating whether or not output will be done 564: * on this connection. The default value is false, so this method can 565: * be used to override the default 566: * 567: * @param output ture if output is to be done, false otherwise 568: * 569: * @exception IllegalStateException If already connected 570: */ 571: public void setDoOutput(boolean output) 572: { 573: if (connected) 574: throw new IllegalStateException("Already connected"); 575: 576: doOutput = output; 577: } 578: 579: /** 580: * Returns a boolean flag indicating whether or not output will be done 581: * on this connection. This defaults to false. 582: * 583: * @return true if output is to be done, false otherwise 584: */ 585: public boolean getDoOutput() 586: { 587: return doOutput; 588: } 589: 590: /** 591: * Sets a boolean flag indicating whether or not user interaction is 592: * allowed for this connection. (For example, in order to prompt for 593: * username and password info. 594: * 595: * @param allow true if user interaction should be allowed, false otherwise. 596: * 597: * @exception IllegalStateException If already connected 598: */ 599: public void setAllowUserInteraction(boolean allow) 600: { 601: allowUserInteraction = allow; 602: } 603: 604: /** 605: * Returns a boolean flag indicating whether or not user interaction is 606: * allowed for this connection. (For example, in order to prompt for 607: * username and password info. 608: * 609: * @return true if user interaction is allowed, false otherwise 610: */ 611: public boolean getAllowUserInteraction() 612: { 613: return allowUserInteraction; 614: } 615: 616: /** 617: * Sets the default flag for whether or not interaction with a user 618: * is allowed. This will be used for all connections unless overridden 619: * 620: * @param allow true to allow user interaction, false otherwise 621: */ 622: public static void setDefaultAllowUserInteraction(boolean allow) 623: { 624: defaultAllowUserInteraction = allow; 625: } 626: 627: /** 628: * Returns the default flag for whether or not interaction with a user 629: * is allowed. This will be used for all connections unless overridden 630: * 631: * @return true if user interaction is allowed, false otherwise 632: */ 633: public static boolean getDefaultAllowUserInteraction() 634: { 635: return defaultAllowUserInteraction; 636: } 637: 638: /** 639: * Sets a boolean flag indicating whether or not caching will be used 640: * (if possible) to store data downloaded via the connection. 641: * 642: * @param usecaches The new value 643: * 644: * @exception IllegalStateException If already connected 645: */ 646: public void setUseCaches(boolean usecaches) 647: { 648: if (connected) 649: throw new IllegalStateException("Already connected"); 650: 651: useCaches = usecaches; 652: } 653: 654: /** 655: * Returns a boolean flag indicating whether or not caching will be used 656: * (if possible) to store data downloaded via the connection. 657: * 658: * @return true if caching should be used if possible, false otherwise 659: */ 660: public boolean getUseCaches() 661: { 662: return useCaches; 663: } 664: 665: /** 666: * Sets the ifModified since instance variable. If this value is non 667: * zero and the underlying protocol supports it, the actual document will 668: * not be fetched unless it has been modified since this time. The value 669: * passed should be 0 if this feature is to be disabled or the time expressed 670: * as the number of seconds since midnight 1/1/1970 GMT otherwise. 671: * 672: * @param ifmodifiedsince The new value in milliseconds 673: * since January 1, 1970 GMT 674: * 675: * @exception IllegalStateException If already connected 676: */ 677: public void setIfModifiedSince(long ifmodifiedsince) 678: { 679: if (connected) 680: throw new IllegalStateException("Already connected"); 681: 682: ifModifiedSince = ifmodifiedsince; 683: } 684: 685: /** 686: * Returns the ifModified since instance variable. If this value is non 687: * zero and the underlying protocol supports it, the actual document will 688: * not be fetched unless it has been modified since this time. The value 689: * returned will be 0 if this feature is disabled or the time expressed 690: * as the number of seconds since midnight 1/1/1970 GMT otherwise 691: * 692: * @return The ifModifiedSince value 693: */ 694: public long getIfModifiedSince() 695: { 696: return ifModifiedSince; 697: } 698: 699: /** 700: * Returns the default value used to determine whether or not caching 701: * of documents will be done when possible. 702: * 703: * @return true if caches will be used, false otherwise 704: */ 705: public boolean getDefaultUseCaches() 706: { 707: return defaultUseCaches; 708: } 709: 710: /** 711: * Sets the default value used to determine whether or not caching 712: * of documents will be done when possible. 713: * 714: * @param use true to use caches if possible by default, false otherwise 715: */ 716: public void setDefaultUseCaches(boolean use) 717: { 718: defaultUseCaches = use; 719: } 720: 721: /** 722: * Sets the value of the named request property 723: * 724: * @param key The name of the property 725: * @param value The value of the property 726: * 727: * @exception IllegalStateException If already connected 728: * @exception NullPointerException If key is null 729: * 730: * @see URLConnection#getRequestProperty(String key) 731: * @see URLConnection#addRequestProperty(String key, String value) 732: * 733: * @since 1.4 734: */ 735: public void setRequestProperty(String key, String value) 736: { 737: if (connected) 738: throw new IllegalStateException("Already connected"); 739: 740: if (key == null) 741: throw new NullPointerException("key is null"); 742: 743: // Do nothing unless overridden by subclasses that support setting 744: // header fields in the request. 745: } 746: 747: /** 748: * Adds a new request property by a key/value pair. 749: * This method does not overwrite existing properties with the same key. 750: * 751: * @param key Key of the property to add 752: * @param value Value of the Property to add 753: * 754: * @exception IllegalStateException If already connected 755: * @exception NullPointerException If key is null 756: * 757: * @see URLConnection#getRequestProperty(String key) 758: * @see URLConnection#setRequestProperty(String key, String value) 759: * 760: * @since 1.4 761: */ 762: public void addRequestProperty(String key, String value) 763: { 764: if (connected) 765: throw new IllegalStateException("Already connected"); 766: 767: if (key == null) 768: throw new NullPointerException("key is null"); 769: 770: // Do nothing unless overridden by subclasses that support adding 771: // header fields in the request. 772: } 773: 774: /** 775: * Returns the value of the named request property. 776: * 777: * @param key The name of the property 778: * 779: * @return Value of the property 780: * 781: * @exception IllegalStateException If already connected 782: * 783: * @see URLConnection#setRequestProperty(String key, String value) 784: * @see URLConnection#addRequestProperty(String key, String value) 785: */ 786: public String getRequestProperty(String key) 787: { 788: if (connected) 789: throw new IllegalStateException("Already connected"); 790: 791: // Overridden by subclasses that support reading header fields from the 792: // request. 793: return null; 794: } 795: 796: /** 797: * Returns an unmodifiable Map containing the request properties. 798: * 799: * @return The map of properties 800: * 801: * @exception IllegalStateException If already connected 802: * 803: * @since 1.4 804: */ 805: public Map getRequestProperties() 806: { 807: if (connected) 808: throw new IllegalStateException("Already connected"); 809: 810: // Overridden by subclasses that support reading header fields from the 811: // request. 812: return Collections.EMPTY_MAP; 813: } 814: 815: /** 816: * Sets the default value of a request property. This will be used 817: * for all connections unless the value of the property is manually 818: * overridden. 819: * 820: * @param key The request property name the default is being set for 821: * @param value The value to set the default to 822: * 823: * @deprecated 1.3 The method setRequestProperty should be used instead. 824: * This method does nothing now. 825: * 826: * @see URLConnection#setRequestProperty(String key, String value) 827: */ 828: public static void setDefaultRequestProperty(String key, String value) 829: { 830: // This method does nothing since JDK 1.3. 831: } 832: 833: /** 834: * Returns the default value of a request property. This will be used 835: * for all connections unless the value of the property is manually 836: * overridden. 837: * 838: * @param key The request property to return the default value of 839: * 840: * @return The value of the default property or null if not available 841: * 842: * @deprecated 1.3 The method getRequestProperty should be used instead. 843: * This method does nothing now. 844: * 845: * @see URLConnection#getRequestProperty(String key) 846: */ 847: public static String getDefaultRequestProperty(String key) 848: { 849: // This method does nothing since JDK 1.3. 850: return null; 851: } 852: 853: /** 854: * Sets the ContentHandlerFactory for an application. This can be called 855: * once and only once. If it is called again, then an Error is thrown. 856: * Unlike for other set factory methods, this one does not do a security 857: * check prior to setting the factory. 858: * 859: * @param factory The ContentHandlerFactory for this application 860: * 861: * @exception Error If the factory has already been defined 862: * @exception SecurityException If a security manager exists and its 863: * checkSetFactory method doesn't allow the operation 864: */ 865: public static synchronized void setContentHandlerFactory(ContentHandlerFactory factory) 866: { 867: if (URLConnection.factory != null) 868: throw new Error("ContentHandlerFactory already set"); 869: 870: // Throw an exception if an extant security mgr precludes 871: // setting the factory. 872: SecurityManager s = System.getSecurityManager(); 873: if (s != null) 874: s.checkSetFactory(); 875: 876: URLConnection.factory = factory; 877: } 878: 879: /** 880: * Returns the MIME type of a file based on the name of the file. This 881: * works by searching for the file's extension in a list of file extensions 882: * and returning the MIME type associated with it. If no type is found, 883: * then a MIME type of "application/octet-stream" will be returned. 884: * 885: * @param filename The filename to determine the MIME type for 886: * 887: * @return The MIME type String 888: * 889: * @specnote public since JDK 1.4 890: */ 891: public static String guessContentTypeFromName(String filename) 892: { 893: return getFileNameMap().getContentTypeFor(filename.toLowerCase()); 894: } 895: 896: /** 897: * Returns the MIME type of a stream based on the first few characters 898: * at the beginning of the stream. This routine can be used to determine 899: * the MIME type if a server is believed to be returning an incorrect 900: * MIME type. This method returns "application/octet-stream" if it 901: * cannot determine the MIME type. 902: * <p> 903: * NOTE: Overriding MIME types sent from the server can be obnoxious 904: * to user's. See Internet Exploder 4 if you don't believe me. 905: * 906: * @param is The InputStream to determine the MIME type from 907: * 908: * @return The MIME type 909: * 910: * @exception IOException If an error occurs 911: */ 912: public static String guessContentTypeFromStream(InputStream is) 913: throws IOException 914: { 915: return "application/octet-stream"; 916: } 917: 918: /** 919: * This method returns the <code>FileNameMap</code> object being used 920: * to decode MIME types by file extension. 921: * 922: * @return The <code>FileNameMap</code>. 923: * 924: * @since 1.2 925: */ 926: public static synchronized FileNameMap getFileNameMap() 927: { 928: // Delayed initialization. 929: if (fileNameMap == null) 930: fileNameMap = new MimeTypeMapper(); 931: 932: return fileNameMap; 933: } 934: 935: /** 936: * This method sets the <code>FileNameMap</code> object being used 937: * to decode MIME types by file extension. 938: * 939: * @param map The <code>FileNameMap</code>. 940: * 941: * @exception SecurityException If a security manager exists and its 942: * checkSetFactory method doesn't allow the operation 943: * 944: * @since 1.2 945: */ 946: public static synchronized void setFileNameMap(FileNameMap map) 947: { 948: // Throw an exception if an extant security manager precludes 949: // setting the factory. 950: SecurityManager s = System.getSecurityManager(); 951: if (s != null) 952: s.checkSetFactory(); 953: 954: fileNameMap = map; 955: } 956: 957: private ContentHandler getContentHandler(String contentType) 958: { 959: // No content type so just handle it as the default. 960: if (contentType == null || contentType.equals("")) 961: return null; 962: 963: ContentHandler handler = null; 964: 965: // If a non-default factory has been set, use it. 966: if (factory != null) 967: handler = factory.createContentHandler(contentType); 968: 969: // Then try our default class. 970: try 971: { 972: String typeClass = contentType.replace('/', '.'); 973: 974: // Deal with "Content-Type: text/html; charset=ISO-8859-1". 975: int parameterBegin = typeClass.indexOf(';'); 976: if (parameterBegin >= 1) 977: typeClass = typeClass.substring(0, parameterBegin); 978: 979: Class cls = Class.forName("gnu.java.net.content." + typeClass); 980: Object obj = cls.newInstance(); 981: 982: if (obj instanceof ContentHandler) 983: { 984: handler = (ContentHandler) obj; 985: return handler; 986: } 987: } 988: catch (ClassNotFoundException e) 989: { 990: // Ignore. 991: } 992: catch (InstantiationException e) 993: { 994: // Ignore. 995: } 996: catch (IllegalAccessException e) 997: { 998: // Ignore. 999: } 1000: 1001: return handler; 1002: } 1003: 1004: // We don't put these in a static initializer, because it creates problems 1005: // with initializer co-dependency: SimpleDateFormat's constructors eventually 1006: // depend on URLConnection (via the java.text.*Symbols classes). 1007: private static synchronized void initializeDateFormats() 1008: { 1009: if (dateformats_initialized) 1010: return; 1011: 1012: Locale locale = new Locale("En", "Us", "Unix"); 1013: dateFormats = new SimpleDateFormat[3]; 1014: dateFormats[0] = 1015: new SimpleDateFormat("EEE, dd MMM yyyy hh:mm:ss 'GMT'", locale); 1016: dateFormats[1] = 1017: new SimpleDateFormat("EEEE, dd-MMM-yy hh:mm:ss 'GMT'", locale); 1018: dateFormats[2] = new SimpleDateFormat("EEE MMM d hh:mm:ss yyyy", locale); 1019: dateformats_initialized = true; 1020: } 1021: }
GNU Classpath (0.20) |