1/* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18package java.net; 19 20import java.io.IOException; 21import java.io.InputStream; 22import java.io.OutputStream; 23import java.security.AccessController; 24import java.security.PrivilegedAction; 25import java.util.Collections; 26import java.util.Date; 27import java.util.Hashtable; 28import java.util.List; 29import java.util.Map; 30import java.util.StringTokenizer; 31 32import org.apache.harmony.luni.internal.net.www.MimeTable; 33import org.apache.harmony.luni.util.Msg; 34import org.apache.harmony.luni.util.PriviAction; 35 36/** 37 * Concrete implementations of the abstract {@code URLConnection} class provide 38 * a communication link to a URL for exchanging data with a specific protocol 39 * type. A {@code URLConnection} can only be set up after the instantiation but 40 * before connecting to the remote resource. 41 */ 42public abstract class URLConnection { 43 44 /** 45 * The URL which represents the remote target of this {@code URLConnection}. 46 */ 47 protected URL url; 48 49 private String contentType; 50 51 private static boolean defaultAllowUserInteraction; 52 53 private static boolean defaultUseCaches = true; 54 55 ContentHandler defaultHandler = new DefaultContentHandler(); 56 57 private long lastModified = -1; 58 59 /** 60 * The data must be modified more recently than this time in milliseconds 61 * since January 1, 1970, GMT to be transmitted. 62 */ 63 protected long ifModifiedSince; 64 65 /** 66 * Specifies whether the using of caches is enabled or the data has to be 67 * recent for every request. 68 */ 69 protected boolean useCaches = defaultUseCaches; 70 71 /** 72 * Specifies whether this {@code URLConnection} is already connected to the 73 * remote resource. If this field is set to {@code true} the flags for 74 * setting up the connection are not changeable anymore. 75 */ 76 protected boolean connected; 77 78 /** 79 * Specifies whether this {@code URLConnection} allows sending data. 80 */ 81 protected boolean doOutput; 82 83 /** 84 * Specifies whether this {@code URLConnection} allows receiving data. 85 */ 86 protected boolean doInput = true; 87 88 /** 89 * Specifies whether this {@code URLConnection} allows user interaction as 90 * it is needed for authentication purposes. 91 */ 92 protected boolean allowUserInteraction = defaultAllowUserInteraction; 93 94 private static ContentHandlerFactory contentHandlerFactory; 95 96 private int readTimeout = 0; 97 98 private int connectTimeout = 0; 99 100 /** 101 * Cache for storing content handler 102 */ 103 static Hashtable<String, Object> contentHandlers = new Hashtable<String, Object>(); 104 105 /** 106 * A hashtable that maps the filename extension (key) to a MIME-type 107 * (element) 108 */ 109 private static FileNameMap fileNameMap; 110 111 /** 112 * Creates a new {@code URLConnection} instance pointing to the resource 113 * specified by the given URL. 114 * 115 * @param url 116 * the URL which represents the resource this {@code 117 * URLConnection} will point to. 118 */ 119 protected URLConnection(URL url) { 120 this.url = url; 121 } 122 123 /** 124 * Establishes the connection to the earlier configured resource. The 125 * connection can only be set up before this method has been called. 126 * 127 * @throws IOException 128 * if an error occurs while connecting to the resource. 129 */ 130 public abstract void connect() throws IOException; 131 132 /** 133 * Gets the option value which indicates whether user interaction is allowed 134 * on this {@code URLConnection}. 135 * 136 * @return the value of the option {@code allowUserInteraction}. 137 * @see #allowUserInteraction 138 */ 139 public boolean getAllowUserInteraction() { 140 return allowUserInteraction; 141 } 142 143 /** 144 * Gets an object representing the content of the resource this {@code 145 * URLConnection} is connected to. First, it attempts to get the content 146 * type from the method {@code getContentType()} which looks at the response 147 * header field "Content-Type". If none is found it will guess the content 148 * type from the filename extension. If that fails the stream itself will be 149 * used to guess the content type. 150 * 151 * @return the content representing object. 152 * @throws IOException 153 * if an error occurs obtaining the content. 154 */ 155 public Object getContent() throws java.io.IOException { 156 if (!connected) { 157 connect(); 158 } 159 160 if ((contentType = getContentType()) == null) { 161 if ((contentType = guessContentTypeFromName(url.getFile())) == null) { 162 contentType = guessContentTypeFromStream(getInputStream()); 163 } 164 } 165 if (contentType != null) { 166 return getContentHandler(contentType).getContent(this); 167 } 168 return null; 169 } 170 171 /** 172 * Gets an object representing the content of the resource this {@code 173 * URLConnection} is connected to. First, it attempts to get the content 174 * type from the method {@code getContentType()} which looks at the response 175 * header field "Content-Type". If none is found it will guess the content 176 * type from the filename extension. If that fails the stream itself will be 177 * used to guess the content type. The content type must match with one of 178 * the list {@code types}. 179 * 180 * @param types 181 * the list of acceptable content types. 182 * @return the content representing object or {@code null} if the content 183 * type does not match with one of the specified types. 184 * @throws IOException 185 * if an error occurs obtaining the content. 186 */ 187 // Param is not generic in spec 188 @SuppressWarnings("unchecked") 189 public Object getContent(Class[] types) throws IOException { 190 if (!connected) { 191 connect(); 192 } 193 194 if ((contentType = getContentType()) == null) { 195 if ((contentType = guessContentTypeFromName(url.getFile())) == null) { 196 contentType = guessContentTypeFromStream(getInputStream()); 197 } 198 } 199 if (contentType != null) { 200 return getContentHandler(contentType).getContent(this, types); 201 } 202 return null; 203 } 204 205 /** 206 * Gets the content encoding type specified by the response header field 207 * {@code content-encoding} or {@code null} if this field is not set. 208 * 209 * @return the value of the response header field {@code content-encoding}. 210 */ 211 public String getContentEncoding() { 212 return getHeaderField("Content-Encoding"); //$NON-NLS-1$ 213 } 214 215 /** 216 * Returns the specific ContentHandler that will handle the type {@code 217 * contentType}. 218 * 219 * @param type 220 * The type that needs to be handled 221 * @return An instance of the Content Handler 222 */ 223 private ContentHandler getContentHandler(String type) throws IOException { 224 // Replace all non-alphanumeric character by '_' 225 final String typeString = parseTypeString(type.replace('/', '.')); 226 227 // if there's a cached content handler, use it 228 Object cHandler = contentHandlers.get(type); 229 if (cHandler != null) { 230 return (ContentHandler) cHandler; 231 } 232 233 if (contentHandlerFactory != null) { 234 cHandler = contentHandlerFactory.createContentHandler(type); 235 contentHandlers.put(type, cHandler); 236 return (ContentHandler) cHandler; 237 } 238 239 // search through the package list for the right class for the Content 240 // Type 241 String packageList = AccessController 242 .doPrivileged(new PriviAction<String>( 243 "java.content.handler.pkgs")); //$NON-NLS-1$ 244 if (packageList != null) { 245 final StringTokenizer st = new StringTokenizer(packageList, "|"); //$NON-NLS-1$ 246 while (st.countTokens() > 0) { 247 try { 248 Class<?> cl = Class.forName(st.nextToken() + "." //$NON-NLS-1$ 249 + typeString, true, ClassLoader 250 .getSystemClassLoader()); 251 cHandler = cl.newInstance(); 252 } catch (ClassNotFoundException e) { 253 } catch (IllegalAccessException e) { 254 } catch (InstantiationException e) { 255 } 256 } 257 } 258 259 if (cHandler == null) { 260 cHandler = AccessController 261 .doPrivileged(new PrivilegedAction<Object>() { 262 public Object run() { 263 try { 264 // Try looking up AWT image content handlers 265 String className = "org.apache.harmony.awt.www.content." //$NON-NLS-1$ 266 + typeString; 267 return Class.forName(className).newInstance(); 268 } catch (ClassNotFoundException e) { 269 } catch (IllegalAccessException e) { 270 } catch (InstantiationException e) { 271 } 272 return null; 273 } 274 }); 275 } 276 if (cHandler != null) { 277 if (!(cHandler instanceof ContentHandler)) { 278 throw new UnknownServiceException(); 279 } 280 contentHandlers.put(type, cHandler); // if we got the handler, 281 // cache it for next time 282 return (ContentHandler) cHandler; 283 } 284 285 return defaultHandler; 286 } 287 288 /** 289 * Gets the content length in bytes specified by the response header field 290 * {@code content-length} or {@code -1} if this field is not set. 291 * 292 * @return the value of the response header field {@code content-length}. 293 */ 294 public int getContentLength() { 295 return getHeaderFieldInt("Content-Length", -1); //$NON-NLS-1$ 296 } 297 298 /** 299 * Gets the MIME-type of the content specified by the response header field 300 * {@code content-type} or {@code null} if type is unknown. 301 * 302 * @return the value of the response header field {@code content-type}. 303 */ 304 public String getContentType() { 305 return getHeaderField("Content-Type"); //$NON-NLS-1$ 306 } 307 308 /** 309 * Gets the timestamp when this response has been sent as a date in 310 * milliseconds since January 1, 1970 GMT or {@code 0} if this timestamp is 311 * unknown. 312 * 313 * @return the sending timestamp of the current response. 314 */ 315 public long getDate() { 316 return getHeaderFieldDate("Date", 0); //$NON-NLS-1$ 317 } 318 319 /** 320 * Gets the default setting whether this connection allows user interaction. 321 * 322 * @return the value of the default setting {@code 323 * defaultAllowUserInteraction}. 324 * @see #allowUserInteraction 325 */ 326 public static boolean getDefaultAllowUserInteraction() { 327 return defaultAllowUserInteraction; 328 } 329 330 /** 331 * Gets the default value for the specified request {@code field} or {@code 332 * null} if the field could not be found. The current implementation of this 333 * method returns always {@code null}. 334 * 335 * @param field 336 * the request field whose default value shall be returned. 337 * @return the default value for the given field. 338 * @deprecated Use {@link #getRequestProperty} 339 */ 340 @Deprecated 341 public static String getDefaultRequestProperty(String field) { 342 return null; 343 } 344 345 /** 346 * Gets the default setting whether this connection allows using caches. 347 * 348 * @return the value of the default setting {@code defaultUseCaches}. 349 * @see #useCaches 350 */ 351 public boolean getDefaultUseCaches() { 352 return defaultUseCaches; 353 } 354 355 /** 356 * Gets the value of the option {@code doInput} which specifies whether this 357 * connection allows to receive data. 358 * 359 * @return {@code true} if this connection allows input, {@code false} 360 * otherwise. 361 * @see #doInput 362 */ 363 public boolean getDoInput() { 364 return doInput; 365 } 366 367 /** 368 * Gets the value of the option {@code doOutput} which specifies whether 369 * this connection allows to send data. 370 * 371 * @return {@code true} if this connection allows output, {@code false} 372 * otherwise. 373 * @see #doOutput 374 */ 375 public boolean getDoOutput() { 376 return doOutput; 377 } 378 379 /** 380 * Gets the timestamp when this response will be expired in milliseconds 381 * since January 1, 1970 GMT or {@code 0} if this timestamp is unknown. 382 * 383 * @return the value of the response header field {@code expires}. 384 */ 385 public long getExpiration() { 386 return getHeaderFieldDate("Expires", 0); //$NON-NLS-1$ 387 } 388 389 /** 390 * Gets the table which is used by all {@code URLConnection} instances to 391 * determine the MIME-type according to a file extension. 392 * 393 * @return the file name map to determine the MIME-type. 394 */ 395 public static FileNameMap getFileNameMap() { 396 // Must use lazy initialization or there is a bootstrap problem 397 // trying to load the MimeTable resource from a .jar before 398 // JarURLConnection has finished initialization. 399 synchronized (URLConnection.class) { 400 if (fileNameMap == null) { 401 fileNameMap = new MimeTable(); 402 } 403 return fileNameMap; 404 } 405 } 406 407 /** 408 * Gets the header value at the field position {@code pos} or {@code null} 409 * if the header has fewer than {@code pos} fields. The current 410 * implementation of this method returns always {@code null}. 411 * 412 * @param pos 413 * the field position of the response header. 414 * @return the value of the field at position {@code pos}. 415 */ 416 public String getHeaderField(int pos) { 417 return null; 418 } 419 420 /** 421 * Gets an unchangeable map of the response-header fields and values. The 422 * response-header field names are the key values of the map. The map values 423 * are lists of header field values associated with a particular key name. 424 * 425 * @return the response-header representing generic map. 426 * @since 1.4 427 */ 428 public Map<String, List<String>> getHeaderFields() { 429 return Collections.emptyMap(); 430 } 431 432 /** 433 * Gets an unchangeable map of general request properties used by this 434 * connection. The request property names are the key values of the map. The 435 * map values are lists of property values of the corresponding key name. 436 * 437 * @return the request-property representing generic map. 438 * @since 1.4 439 */ 440 public Map<String, List<String>> getRequestProperties() { 441 if (connected) { 442 throw new IllegalStateException(Msg.getString("K0037")); //$NON-NLS-1$ 443 } 444 return Collections.emptyMap(); 445 } 446 447 /** 448 * Adds the given property to the request header. Existing properties with 449 * the same name will not be overwritten by this method. 450 * 451 * @param field 452 * the request property field name to add. 453 * @param newValue 454 * the value of the property which is to add. 455 * @throws IllegalStateException 456 * if the connection has been already established. 457 * @throws NullPointerException 458 * if the property name is {@code null}. 459 * @since 1.4 460 */ 461 public void addRequestProperty(String field, String newValue) { 462 if (connected) { 463 throw new IllegalStateException(Msg.getString("K0037")); //$NON-NLS-1$ 464 } 465 if (field == null) { 466 throw new NullPointerException(Msg.getString("KA007")); //$NON-NLS-1$ 467 } 468 } 469 470 /** 471 * Gets the value of the header field specified by {@code key} or {@code 472 * null} if there is no field with this name. The current implementation of 473 * this method returns always {@code null}. 474 * 475 * @param key 476 * the name of the header field. 477 * @return the value of the header field. 478 */ 479 public String getHeaderField(String key) { 480 return null; 481 } 482 483 /** 484 * Gets the specified header value as a date in milliseconds since January 485 * 1, 1970 GMT. Returns the {@code defaultValue} if no such header field 486 * could be found. 487 * 488 * @param field 489 * the header field name whose value is needed. 490 * @param defaultValue 491 * the default value if no field has been found. 492 * @return the value of the specified header field as a date in 493 * milliseconds. 494 */ 495 @SuppressWarnings("deprecation") 496 public long getHeaderFieldDate(String field, long defaultValue) { 497 String date = getHeaderField(field); 498 if (date == null) { 499 return defaultValue; 500 } 501 try { 502 return Date.parse(date); 503 } catch (Exception e) { 504 return defaultValue; 505 } 506 } 507 508 /** 509 * Gets the specified header value as a number. Returns the {@code 510 * defaultValue} if no such header field could be found or the value could 511 * not be parsed as an {@code Integer}. 512 * 513 * @param field 514 * the header field name whose value is needed. 515 * @param defaultValue 516 * the default value if no field has been found. 517 * @return the value of the specified header field as a number. 518 */ 519 public int getHeaderFieldInt(String field, int defaultValue) { 520 try { 521 return Integer.parseInt(getHeaderField(field)); 522 } catch (NumberFormatException e) { 523 return defaultValue; 524 } 525 } 526 527 /** 528 * Gets the name of the header field at the given position {@code posn} or 529 * {@code null} if there are fewer than {@code posn} fields. The current 530 * implementation of this method returns always {@code null}. 531 * 532 * @param posn 533 * the position of the header field which has to be returned. 534 * @return the header field name at the given position. 535 */ 536 public String getHeaderFieldKey(int posn) { 537 return null; 538 } 539 540 /** 541 * Gets the point of time since when the data must be modified to be 542 * transmitted. Some protocols transmit data only if it has been modified 543 * more recently than a particular time. 544 * 545 * @return the time in milliseconds since January 1, 1970 GMT. 546 * @see #ifModifiedSince 547 */ 548 public long getIfModifiedSince() { 549 return ifModifiedSince; 550 } 551 552 /** 553 * Gets an {@code InputStream} for reading data from the resource pointed by 554 * this {@code URLConnection}. It throws an UnknownServiceException by 555 * default. This method must be overridden by its subclasses. 556 * 557 * @return the InputStream to read data from. 558 * @throws IOException 559 * if no InputStream could be created. 560 */ 561 public InputStream getInputStream() throws IOException { 562 throw new UnknownServiceException(Msg.getString("K004d")); //$NON-NLS-1$ 563 } 564 565 /** 566 * Gets the value of the response header field {@code last-modified} or 567 * {@code 0} if this value is not set. 568 * 569 * @return the value of the {@code last-modified} header field. 570 */ 571 public long getLastModified() { 572 if (lastModified != -1) { 573 return lastModified; 574 } 575 return lastModified = getHeaderFieldDate("Last-Modified", 0); //$NON-NLS-1$ 576 } 577 578 /** 579 * Gets an {@code OutputStream} for writing data to this {@code 580 * URLConnection}. It throws an {@code UnknownServiceException} by default. 581 * This method must be overridden by its subclasses. 582 * 583 * @return the OutputStream to write data. 584 * @throws IOException 585 * if no OutputStream could be created. 586 */ 587 public OutputStream getOutputStream() throws IOException { 588 throw new UnknownServiceException(Msg.getString("K005f")); //$NON-NLS-1$ 589 } 590 591 /** 592 * Gets a {@code Permission} object representing all needed permissions to 593 * open this connection. The returned permission object depends on the state 594 * of the connection and will be {@code null} if no permissions are 595 * necessary. By default, this method returns {@code AllPermission}. 596 * Subclasses should overwrite this method to return an appropriate 597 * permission object. 598 * 599 * @return the permission object representing the needed permissions to open 600 * this connection. 601 * @throws IOException 602 * if an I/O error occurs while creating the permission object. 603 */ 604 public java.security.Permission getPermission() throws IOException { 605 return new java.security.AllPermission(); 606 } 607 608 /** 609 * Gets the value of the request header property specified by {code field} 610 * or {@code null} if there is no field with this name. The current 611 * implementation of this method returns always {@code null}. 612 * 613 * @param field 614 * the name of the request header property. 615 * @return the value of the property. 616 * @throws IllegalStateException 617 * if the connection has been already established. 618 */ 619 public String getRequestProperty(String field) { 620 if (connected) { 621 throw new IllegalStateException(Msg.getString("K0037")); //$NON-NLS-1$ 622 } 623 return null; 624 } 625 626 /** 627 * Gets the URL represented by this {@code URLConnection}. 628 * 629 * @return the URL of this connection. 630 */ 631 public URL getURL() { 632 return url; 633 } 634 635 /** 636 * Gets the value of the flag which specifies whether this {@code 637 * URLConnection} allows to use caches. 638 * 639 * @return {@code true} if using caches is allowed, {@code false} otherwise. 640 */ 641 public boolean getUseCaches() { 642 return useCaches; 643 } 644 645 /** 646 * Determines the MIME-type of the given resource {@code url} by resolving 647 * the filename extension with the internal FileNameMap. Any fragment 648 * identifier is removed before processing. 649 * 650 * @param url 651 * the URL with the filename to get the MIME type. 652 * @return the guessed content type or {@code null} if the type could not be 653 * determined. 654 */ 655 public static String guessContentTypeFromName(String url) { 656 return getFileNameMap().getContentTypeFor(url); 657 } 658 659 /** 660 * Determines the MIME-type of the resource represented by the input stream 661 * {@code is} by reading its first few characters. 662 * 663 * @param is 664 * the resource representing input stream to determine the 665 * content type. 666 * @return the guessed content type or {@code null} if the type could not be 667 * determined. 668 * @throws IOException 669 * if an I/O error occurs while reading from the input stream. 670 */ 671 @SuppressWarnings("nls") 672 public static String guessContentTypeFromStream(InputStream is) 673 throws IOException { 674 675 if (!is.markSupported()) { 676 return null; 677 } 678 // Look ahead up to 64 bytes for the longest encoded header 679 is.mark(64); 680 byte[] bytes = new byte[64]; 681 int length = is.read(bytes); 682 is.reset(); 683 684 // Check for Unicode BOM encoding indicators 685 String encoding = "ASCII"; 686 int start = 0; 687 if (length > 1) { 688 if ((bytes[0] == (byte) 0xFF) && (bytes[1] == (byte) 0xFE)) { 689 encoding = "UTF-16LE"; 690 start = 2; 691 length -= length & 1; 692 } 693 if ((bytes[0] == (byte) 0xFE) && (bytes[1] == (byte) 0xFF)) { 694 encoding = "UTF-16BE"; 695 start = 2; 696 length -= length & 1; 697 } 698 if (length > 2) { 699 if ((bytes[0] == (byte) 0xEF) && (bytes[1] == (byte) 0xBB) 700 && (bytes[2] == (byte) 0xBF)) { 701 encoding = "UTF-8"; 702 start = 3; 703 } 704 if (length > 3) { 705 if ((bytes[0] == (byte) 0x00) && (bytes[1] == (byte) 0x00) 706 && (bytes[2] == (byte) 0xFE) 707 && (bytes[3] == (byte) 0xFF)) { 708 encoding = "UTF-32BE"; 709 start = 4; 710 length -= length & 3; 711 } 712 if ((bytes[0] == (byte) 0xFF) && (bytes[1] == (byte) 0xFE) 713 && (bytes[2] == (byte) 0x00) 714 && (bytes[3] == (byte) 0x00)) { 715 encoding = "UTF-32LE"; 716 start = 4; 717 length -= length & 3; 718 } 719 } 720 } 721 } 722 723 String header = new String(bytes, start, length - start, encoding); 724 725 // Check binary types 726 if (header.startsWith("PK")) { 727 return "application/zip"; 728 } 729 if (header.startsWith("GI")) { 730 return "image/gif"; 731 } 732 733 // Check text types 734 String textHeader = header.trim().toUpperCase(); 735 if (textHeader.startsWith("<!DOCTYPE HTML") || 736 textHeader.startsWith("<HTML") || 737 textHeader.startsWith("<HEAD") || 738 textHeader.startsWith("<BODY") || 739 textHeader.startsWith("<HEAD")) { 740 return "text/html"; 741 } 742 743 if (textHeader.startsWith("<?XML")) { 744 return "application/xml"; 745 } 746 747 // Give up 748 return null; 749 } 750 751 /** 752 * Performs any necessary string parsing on the input string such as 753 * converting non-alphanumeric character into underscore. 754 * 755 * @param typeString 756 * the parsed string 757 * @return the string to be parsed 758 */ 759 private String parseTypeString(String typeString) { 760 StringBuilder typeStringBuffer = new StringBuilder(typeString); 761 for (int i = 0; i < typeStringBuffer.length(); i++) { 762 // if non-alphanumeric, replace it with '_' 763 char c = typeStringBuffer.charAt(i); 764 if (!(Character.isLetter(c) || Character.isDigit(c) || c == '.')) { 765 typeStringBuffer.setCharAt(i, '_'); 766 } 767 } 768 return typeStringBuffer.toString(); 769 } 770 771 /** 772 * Sets the flag indicating whether this connection allows user interaction 773 * or not. This method can only be called prior to the connection 774 * establishment. 775 * 776 * @param newValue 777 * the value of the flag to be set. 778 * @throws IllegalStateException 779 * if this method attempts to change the flag after the 780 * connection has been established. 781 * @see #allowUserInteraction 782 */ 783 public void setAllowUserInteraction(boolean newValue) { 784 if (connected) { 785 throw new IllegalStateException(Msg.getString("K0037")); //$NON-NLS-1$ 786 } 787 this.allowUserInteraction = newValue; 788 } 789 790 /** 791 * Sets the internally used content handler factory. The content factory can 792 * only be set if it is allowed by the security manager and only once during 793 * the lifetime of the application. 794 * 795 * @param contentFactory 796 * the content factory to be set. 797 * @throws Error 798 * if the security manager does not allow to set the content 799 * factory or it has been already set earlier ago. 800 */ 801 public static synchronized void setContentHandlerFactory( 802 ContentHandlerFactory contentFactory) { 803 if (contentHandlerFactory != null) { 804 throw new Error(Msg.getString("K004e")); //$NON-NLS-1$ 805 } 806 SecurityManager sManager = System.getSecurityManager(); 807 if (sManager != null) { 808 sManager.checkSetFactory(); 809 } 810 contentHandlerFactory = contentFactory; 811 } 812 813 /** 814 * Sets the default value for the flag indicating whether this connection 815 * allows user interaction or not. Existing {@code URLConnection}s are 816 * unaffected. 817 * 818 * @param allows 819 * the default value of the flag to be used for new connections. 820 * @see #defaultAllowUserInteraction 821 * @see #allowUserInteraction 822 */ 823 public static void setDefaultAllowUserInteraction(boolean allows) { 824 defaultAllowUserInteraction = allows; 825 } 826 827 /** 828 * Sets the default value of the specified request header field. This value 829 * will be used for the specific field of every newly created connection. 830 * The current implementation of this method does nothing. 831 * 832 * @param field 833 * the request header field to be set. 834 * @param value 835 * the default value to be used. 836 * @deprecated Use {@link #setRequestProperty} of an existing {@code 837 * URLConnection} instance. 838 */ 839 @Deprecated 840 public static void setDefaultRequestProperty(String field, String value) { 841 } 842 843 /** 844 * Sets the default value for the flag indicating whether this connection 845 * allows to use caches. Existing {@code URLConnection}s are unaffected. 846 * 847 * @param newValue 848 * the default value of the flag to be used for new connections. 849 * @see #defaultUseCaches 850 * @see #useCaches 851 */ 852 public void setDefaultUseCaches(boolean newValue) { 853 // BEGIN android-removed 854 // Setting the default doesn't concern the current connection. 855 // if (connected) { 856 // throw new IllegalAccessError(Msg.getString("K0037")); //$NON-NLS-1$ 857 // } 858 // END android-removed 859 defaultUseCaches = newValue; 860 } 861 862 /** 863 * Sets the flag indicating whether this {@code URLConnection} allows input. 864 * It cannot be set after the connection is established. 865 * 866 * @param newValue 867 * the new value for the flag to be set. 868 * @throws IllegalAccessError 869 * if this method attempts to change the value after the 870 * connection has been already established. 871 * @see #doInput 872 */ 873 public void setDoInput(boolean newValue) { 874 if (connected) { 875 throw new IllegalStateException(Msg.getString("K0037")); //$NON-NLS-1$ 876 } 877 this.doInput = newValue; 878 } 879 880 /** 881 * Sets the flag indicating whether this {@code URLConnection} allows 882 * output. It cannot be set after the connection is established. 883 * 884 * @param newValue 885 * the new value for the flag to be set. 886 * @throws IllegalAccessError 887 * if this method attempts to change the value after the 888 * connection has been already established. 889 * @see #doOutput 890 */ 891 public void setDoOutput(boolean newValue) { 892 if (connected) { 893 throw new IllegalStateException(Msg.getString("K0037")); //$NON-NLS-1$ 894 } 895 this.doOutput = newValue; 896 } 897 898 /** 899 * Sets the internal map which is used by all {@code URLConnection} 900 * instances to determine the MIME-type according to a filename extension. 901 * 902 * @param map 903 * the MIME table to be set. 904 */ 905 public static void setFileNameMap(FileNameMap map) { 906 SecurityManager manager = System.getSecurityManager(); 907 if (manager != null) { 908 manager.checkSetFactory(); 909 } 910 synchronized (URLConnection.class) { 911 fileNameMap = map; 912 } 913 } 914 915 /** 916 * Sets the point of time since when the data must be modified to be 917 * transmitted. Some protocols transmit data only if it has been modified 918 * more recently than a particular time. The data will be transmitted 919 * regardless of its timestamp if this option is set to {@code 0}. 920 * 921 * @param newValue 922 * the time in milliseconds since January 1, 1970 GMT. 923 * @throws IllegalStateException 924 * if this {@code URLConnection} has already been connected. 925 * @see #ifModifiedSince 926 */ 927 public void setIfModifiedSince(long newValue) { 928 if (connected) { 929 throw new IllegalStateException(Msg.getString("K0037")); //$NON-NLS-1$ 930 } 931 this.ifModifiedSince = newValue; 932 } 933 934 /** 935 * Sets the value of the specified request header field. The value will only 936 * be used by the current {@code URLConnection} instance. This method can 937 * only be called before the connection is established. 938 * 939 * @param field 940 * the request header field to be set. 941 * @param newValue 942 * the new value of the specified property. 943 * @throws IllegalStateException 944 * if the connection has been already established. 945 * @throws NullPointerException 946 * if the parameter {@code field} is {@code null}. 947 */ 948 public void setRequestProperty(String field, String newValue) { 949 if (connected) { 950 throw new IllegalStateException(Msg.getString("K0037")); //$NON-NLS-1$ 951 } 952 if (field == null) { 953 throw new NullPointerException(Msg.getString("KA007")); //$NON-NLS-1$ 954 } 955 } 956 957 /** 958 * Sets the flag indicating whether this connection allows to use caches or 959 * not. This method can only be called prior to the connection 960 * establishment. 961 * 962 * @param newValue 963 * the value of the flag to be set. 964 * @throws IllegalStateException 965 * if this method attempts to change the flag after the 966 * connection has been established. 967 * @see #useCaches 968 */ 969 public void setUseCaches(boolean newValue) { 970 if (connected) { 971 throw new IllegalStateException(Msg.getString("K0037")); //$NON-NLS-1$ 972 } 973 this.useCaches = newValue; 974 } 975 976 /** 977 * Sets the timeout value in milliseconds for establishing the connection to 978 * the resource pointed by this {@code URLConnection} instance. A {@code 979 * SocketTimeoutException} is thrown if the connection could not be 980 * established in this time. Default is {@code 0} which stands for an 981 * infinite timeout. 982 * 983 * @param timeout 984 * the connecting timeout in milliseconds. 985 * @throws IllegalArgumentException 986 * if the parameter {@code timeout} is less than zero. 987 */ 988 public void setConnectTimeout(int timeout) { 989 if (0 > timeout) { 990 throw new IllegalArgumentException(Msg.getString("K0036")); //$NON-NLS-1$ 991 } 992 this.connectTimeout = timeout; 993 } 994 995 /** 996 * Gets the configured connecting timeout. 997 * 998 * @return the connecting timeout value in milliseconds. 999 */ 1000 public int getConnectTimeout() { 1001 return connectTimeout; 1002 } 1003 1004 /** 1005 * Sets the timeout value in milliseconds for reading from the input stream 1006 * of an established connection to the resource. A {@code 1007 * SocketTimeoutException} is thrown if the connection could not be 1008 * established in this time. Default is {@code 0} which stands for an 1009 * infinite timeout. 1010 * 1011 * @param timeout 1012 * the reading timeout in milliseconds. 1013 * @throws IllegalArgumentException 1014 * if the parameter {@code timeout} is less than zero. 1015 */ 1016 public void setReadTimeout(int timeout) { 1017 if (0 > timeout) { 1018 throw new IllegalArgumentException(Msg.getString("K0036")); //$NON-NLS-1$ 1019 } 1020 this.readTimeout = timeout; 1021 } 1022 1023 /** 1024 * Gets the configured timeout for reading from the input stream of an 1025 * established connection to the resource. 1026 * 1027 * @return the reading timeout value in milliseconds. 1028 */ 1029 public int getReadTimeout() { 1030 return readTimeout; 1031 } 1032 1033 /** 1034 * Returns the string representation containing the name of this class and 1035 * the URL. 1036 * 1037 * @return the string representation of this {@code URLConnection} instance. 1038 */ 1039 @Override 1040 public String toString() { 1041 return getClass().getName() + ":" + url.toString(); //$NON-NLS-1$ 1042 } 1043 1044 static class DefaultContentHandler extends java.net.ContentHandler { 1045 1046 /** 1047 * @param u 1048 * the URL connection 1049 * 1050 * @see java.net.ContentHandler#getContent(java.net.URLConnection) 1051 */ 1052 @Override 1053 public Object getContent(URLConnection u) throws IOException { 1054 return u.getInputStream(); 1055 } 1056 } 1057} 1058