blob: 894fde5903381a622680b417cd047003a134ff41 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package java.net;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.Collections;
import java.util.Date;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
import org.apache.harmony.luni.internal.net.www.MimeTable;
import org.apache.harmony.luni.util.Msg;
import org.apache.harmony.luni.util.PriviAction;
/**
* Concrete implementations of the abstract {@code URLConnection} class provide
* a communication link to a URL for exchanging data with a specific protocol
* type. A {@code URLConnection} can only be set up after the instantiation but
* before connecting to the remote resource.
*/
public abstract class URLConnection {
/**
* The URL which represents the remote target of this {@code URLConnection}.
*/
protected URL url;
private String contentType;
private static boolean defaultAllowUserInteraction;
private static boolean defaultUseCaches = true;
ContentHandler defaultHandler = new DefaultContentHandler();
private long lastModified = -1;
/**
* The data must be modified more recently than this time in milliseconds
* since January 1, 1970, GMT to be transmitted.
*/
protected long ifModifiedSince;
/**
* Specifies whether the using of caches is enabled or the data has to be
* recent for every request.
*/
protected boolean useCaches = defaultUseCaches;
/**
* Specifies whether this {@code URLConnection} is already connected to the
* remote resource. If this field is set to {@code true} the flags for
* setting up the connection are not changeable anymore.
*/
protected boolean connected;
/**
* Specifies whether this {@code URLConnection} allows sending data.
*/
protected boolean doOutput;
/**
* Specifies whether this {@code URLConnection} allows receiving data.
*/
protected boolean doInput = true;
/**
* Specifies whether this {@code URLConnection} allows user interaction as
* it is needed for authentication purposes.
*/
protected boolean allowUserInteraction = defaultAllowUserInteraction;
private static ContentHandlerFactory contentHandlerFactory;
private int readTimeout = 0;
private int connectTimeout = 0;
/**
* Cache for storing content handler
*/
static Hashtable<String, Object> contentHandlers = new Hashtable<String, Object>();
/**
* A hashtable that maps the filename extension (key) to a MIME-type
* (element)
*/
private static FileNameMap fileNameMap;
/**
* Creates a new {@code URLConnection} instance pointing to the resource
* specified by the given URL.
*
* @param url
* the URL which represents the resource this {@code
* URLConnection} will point to.
*/
protected URLConnection(URL url) {
this.url = url;
}
/**
* Establishes the connection to the earlier configured resource. The
* connection can only be set up before this method has been called.
*
* @throws IOException
* if an error occurs while connecting to the resource.
*/
public abstract void connect() throws IOException;
/**
* Gets the option value which indicates whether user interaction is allowed
* on this {@code URLConnection}.
*
* @return the value of the option {@code allowUserInteraction}.
* @see #allowUserInteraction
*/
public boolean getAllowUserInteraction() {
return allowUserInteraction;
}
/**
* Gets an object representing the content of the resource this {@code
* URLConnection} is connected to. First, it attempts to get the content
* type from the method {@code getContentType()} which looks at the response
* header field "Content-Type". If none is found it will guess the content
* type from the filename extension. If that fails the stream itself will be
* used to guess the content type.
*
* @return the content representing object.
* @throws IOException
* if an error occurs obtaining the content.
*/
public Object getContent() throws java.io.IOException {
if (!connected) {
connect();
}
if ((contentType = getContentType()) == null) {
if ((contentType = guessContentTypeFromName(url.getFile())) == null) {
contentType = guessContentTypeFromStream(getInputStream());
}
}
if (contentType != null) {
return getContentHandler(contentType).getContent(this);
}
return null;
}
/**
* Gets an object representing the content of the resource this {@code
* URLConnection} is connected to. First, it attempts to get the content
* type from the method {@code getContentType()} which looks at the response
* header field "Content-Type". If none is found it will guess the content
* type from the filename extension. If that fails the stream itself will be
* used to guess the content type. The content type must match with one of
* the list {@code types}.
*
* @param types
* the list of acceptable content types.
* @return the content representing object or {@code null} if the content
* type does not match with one of the specified types.
* @throws IOException
* if an error occurs obtaining the content.
*/
// Param is not generic in spec
@SuppressWarnings("unchecked")
public Object getContent(Class[] types) throws IOException {
if (!connected) {
connect();
}
if ((contentType = getContentType()) == null) {
if ((contentType = guessContentTypeFromName(url.getFile())) == null) {
contentType = guessContentTypeFromStream(getInputStream());
}
}
if (contentType != null) {
return getContentHandler(contentType).getContent(this, types);
}
return null;
}
/**
* Gets the content encoding type specified by the response header field
* {@code content-encoding} or {@code null} if this field is not set.
*
* @return the value of the response header field {@code content-encoding}.
*/
public String getContentEncoding() {
return getHeaderField("Content-Encoding"); //$NON-NLS-1$
}
/**
* Returns the specific ContentHandler that will handle the type {@code
* contentType}.
*
* @param type
* The type that needs to be handled
* @return An instance of the Content Handler
*/
private ContentHandler getContentHandler(String type) throws IOException {
// Replace all non-alphanumeric character by '_'
final String typeString = parseTypeString(type.replace('/', '.'));
// if there's a cached content handler, use it
Object cHandler = contentHandlers.get(type);
if (cHandler != null) {
return (ContentHandler) cHandler;
}
if (contentHandlerFactory != null) {
cHandler = contentHandlerFactory.createContentHandler(type);
contentHandlers.put(type, cHandler);
return (ContentHandler) cHandler;
}
// search through the package list for the right class for the Content
// Type
String packageList = AccessController
.doPrivileged(new PriviAction<String>(
"java.content.handler.pkgs")); //$NON-NLS-1$
if (packageList != null) {
final StringTokenizer st = new StringTokenizer(packageList, "|"); //$NON-NLS-1$
while (st.countTokens() > 0) {
try {
Class<?> cl = Class.forName(st.nextToken() + "." //$NON-NLS-1$
+ typeString, true, ClassLoader
.getSystemClassLoader());
cHandler = cl.newInstance();
} catch (ClassNotFoundException e) {
} catch (IllegalAccessException e) {
} catch (InstantiationException e) {
}
}
}
if (cHandler == null) {
cHandler = AccessController
.doPrivileged(new PrivilegedAction<Object>() {
public Object run() {
try {
// Try looking up AWT image content handlers
String className = "org.apache.harmony.awt.www.content." //$NON-NLS-1$
+ typeString;
return Class.forName(className).newInstance();
} catch (ClassNotFoundException e) {
} catch (IllegalAccessException e) {
} catch (InstantiationException e) {
}
return null;
}
});
}
if (cHandler != null) {
if (!(cHandler instanceof ContentHandler)) {
throw new UnknownServiceException();
}
contentHandlers.put(type, cHandler); // if we got the handler,
// cache it for next time
return (ContentHandler) cHandler;
}
return defaultHandler;
}
/**
* Gets the content length in bytes specified by the response header field
* {@code content-length} or {@code -1} if this field is not set.
*
* @return the value of the response header field {@code content-length}.
*/
public int getContentLength() {
return getHeaderFieldInt("Content-Length", -1); //$NON-NLS-1$
}
/**
* Gets the MIME-type of the content specified by the response header field
* {@code content-type} or {@code null} if type is unknown.
*
* @return the value of the response header field {@code content-type}.
*/
public String getContentType() {
return getHeaderField("Content-Type"); //$NON-NLS-1$
}
/**
* Gets the timestamp when this response has been sent as a date in
* milliseconds since January 1, 1970 GMT or {@code 0} if this timestamp is
* unknown.
*
* @return the sending timestamp of the current response.
*/
public long getDate() {
return getHeaderFieldDate("Date", 0); //$NON-NLS-1$
}
/**
* Gets the default setting whether this connection allows user interaction.
*
* @return the value of the default setting {@code
* defaultAllowUserInteraction}.
* @see #allowUserInteraction
*/
public static boolean getDefaultAllowUserInteraction() {
return defaultAllowUserInteraction;
}
/**
* Gets the default value for the specified request {@code field} or {@code
* null} if the field could not be found. The current implementation of this
* method returns always {@code null}.
*
* @param field
* the request field whose default value shall be returned.
* @return the default value for the given field.
* @deprecated Use {@link #getRequestProperty}
*/
@Deprecated
public static String getDefaultRequestProperty(String field) {
return null;
}
/**
* Gets the default setting whether this connection allows using caches.
*
* @return the value of the default setting {@code defaultUseCaches}.
* @see #useCaches
*/
public boolean getDefaultUseCaches() {
return defaultUseCaches;
}
/**
* Gets the value of the option {@code doInput} which specifies whether this
* connection allows to receive data.
*
* @return {@code true} if this connection allows input, {@code false}
* otherwise.
* @see #doInput
*/
public boolean getDoInput() {
return doInput;
}
/**
* Gets the value of the option {@code doOutput} which specifies whether
* this connection allows to send data.
*
* @return {@code true} if this connection allows output, {@code false}
* otherwise.
* @see #doOutput
*/
public boolean getDoOutput() {
return doOutput;
}
/**
* Gets the timestamp when this response will be expired in milliseconds
* since January 1, 1970 GMT or {@code 0} if this timestamp is unknown.
*
* @return the value of the response header field {@code expires}.
*/
public long getExpiration() {
return getHeaderFieldDate("Expires", 0); //$NON-NLS-1$
}
/**
* Gets the table which is used by all {@code URLConnection} instances to
* determine the MIME-type according to a file extension.
*
* @return the file name map to determine the MIME-type.
*/
public static FileNameMap getFileNameMap() {
// Must use lazy initialization or there is a bootstrap problem
// trying to load the MimeTable resource from a .jar before
// JarURLConnection has finished initialization.
synchronized (URLConnection.class) {
if (fileNameMap == null) {
fileNameMap = new MimeTable();
}
return fileNameMap;
}
}
/**
* Gets the header value at the field position {@code pos} or {@code null}
* if the header has fewer than {@code pos} fields. The current
* implementation of this method returns always {@code null}.
*
* @param pos
* the field position of the response header.
* @return the value of the field at position {@code pos}.
*/
public String getHeaderField(int pos) {
return null;
}
/**
* Gets an unchangeable map of the response-header fields and values. The
* response-header field names are the key values of the map. The map values
* are lists of header field values associated with a particular key name.
*
* @return the response-header representing generic map.
* @since 1.4
*/
public Map<String, List<String>> getHeaderFields() {
return Collections.emptyMap();
}
/**
* Gets an unchangeable map of general request properties used by this
* connection. The request property names are the key values of the map. The
* map values are lists of property values of the corresponding key name.
*
* @return the request-property representing generic map.
* @since 1.4
*/
public Map<String, List<String>> getRequestProperties() {
if (connected) {
throw new IllegalStateException(Msg.getString("K0037")); //$NON-NLS-1$
}
return Collections.emptyMap();
}
/**
* Adds the given property to the request header. Existing properties with
* the same name will not be overwritten by this method.
*
* @param field
* the request property field name to add.
* @param newValue
* the value of the property which is to add.
* @throws IllegalStateException
* if the connection has been already established.
* @throws NullPointerException
* if the property name is {@code null}.
* @since 1.4
*/
public void addRequestProperty(String field, String newValue) {
if (connected) {
throw new IllegalStateException(Msg.getString("K0037")); //$NON-NLS-1$
}
if (field == null) {
throw new NullPointerException(Msg.getString("KA007")); //$NON-NLS-1$
}
}
/**
* Gets the value of the header field specified by {@code key} or {@code
* null} if there is no field with this name. The current implementation of
* this method returns always {@code null}.
*
* @param key
* the name of the header field.
* @return the value of the header field.
*/
public String getHeaderField(String key) {
return null;
}
/**
* Gets the specified header value as a date in milliseconds since January
* 1, 1970 GMT. Returns the {@code defaultValue} if no such header field
* could be found.
*
* @param field
* the header field name whose value is needed.
* @param defaultValue
* the default value if no field has been found.
* @return the value of the specified header field as a date in
* milliseconds.
*/
@SuppressWarnings("deprecation")
public long getHeaderFieldDate(String field, long defaultValue) {
String date = getHeaderField(field);
if (date == null) {
return defaultValue;
}
try {
return Date.parse(date);
} catch (Exception e) {
return defaultValue;
}
}
/**
* Gets the specified header value as a number. Returns the {@code
* defaultValue} if no such header field could be found or the value could
* not be parsed as an {@code Integer}.
*
* @param field
* the header field name whose value is needed.
* @param defaultValue
* the default value if no field has been found.
* @return the value of the specified header field as a number.
*/
public int getHeaderFieldInt(String field, int defaultValue) {
try {
return Integer.parseInt(getHeaderField(field));
} catch (NumberFormatException e) {
return defaultValue;
}
}
/**
* Gets the name of the header field at the given position {@code posn} or
* {@code null} if there are fewer than {@code posn} fields. The current
* implementation of this method returns always {@code null}.
*
* @param posn
* the position of the header field which has to be returned.
* @return the header field name at the given position.
*/
public String getHeaderFieldKey(int posn) {
return null;
}
/**
* Gets the point of time since when the data must be modified to be
* transmitted. Some protocols transmit data only if it has been modified
* more recently than a particular time.
*
* @return the time in milliseconds since January 1, 1970 GMT.
* @see #ifModifiedSince
*/
public long getIfModifiedSince() {
return ifModifiedSince;
}
/**
* Gets an {@code InputStream} for reading data from the resource pointed by
* this {@code URLConnection}. It throws an UnknownServiceException by
* default. This method must be overridden by its subclasses.
*
* @return the InputStream to read data from.
* @throws IOException
* if no InputStream could be created.
*/
public InputStream getInputStream() throws IOException {
throw new UnknownServiceException(Msg.getString("K004d")); //$NON-NLS-1$
}
/**
* Gets the value of the response header field {@code last-modified} or
* {@code 0} if this value is not set.
*
* @return the value of the {@code last-modified} header field.
*/
public long getLastModified() {
if (lastModified != -1) {
return lastModified;
}
return lastModified = getHeaderFieldDate("Last-Modified", 0); //$NON-NLS-1$
}
/**
* Gets an {@code OutputStream} for writing data to this {@code
* URLConnection}. It throws an {@code UnknownServiceException} by default.
* This method must be overridden by its subclasses.
*
* @return the OutputStream to write data.
* @throws IOException
* if no OutputStream could be created.
*/
public OutputStream getOutputStream() throws IOException {
throw new UnknownServiceException(Msg.getString("K005f")); //$NON-NLS-1$
}
/**
* Gets a {@code Permission} object representing all needed permissions to
* open this connection. The returned permission object depends on the state
* of the connection and will be {@code null} if no permissions are
* necessary. By default, this method returns {@code AllPermission}.
* Subclasses should overwrite this method to return an appropriate
* permission object.
*
* @return the permission object representing the needed permissions to open
* this connection.
* @throws IOException
* if an I/O error occurs while creating the permission object.
*/
public java.security.Permission getPermission() throws IOException {
return new java.security.AllPermission();
}
/**
* Gets the value of the request header property specified by {code field}
* or {@code null} if there is no field with this name. The current
* implementation of this method returns always {@code null}.
*
* @param field
* the name of the request header property.
* @return the value of the property.
* @throws IllegalStateException
* if the connection has been already established.
*/
public String getRequestProperty(String field) {
if (connected) {
throw new IllegalStateException(Msg.getString("K0037")); //$NON-NLS-1$
}
return null;
}
/**
* Gets the URL represented by this {@code URLConnection}.
*
* @return the URL of this connection.
*/
public URL getURL() {
return url;
}
/**
* Gets the value of the flag which specifies whether this {@code
* URLConnection} allows to use caches.
*
* @return {@code true} if using caches is allowed, {@code false} otherwise.
*/
public boolean getUseCaches() {
return useCaches;
}
/**
* Determines the MIME-type of the given resource {@code url} by resolving
* the filename extension with the internal FileNameMap. Any fragment
* identifier is removed before processing.
*
* @param url
* the URL with the filename to get the MIME type.
* @return the guessed content type or {@code null} if the type could not be
* determined.
*/
public static String guessContentTypeFromName(String url) {
return getFileNameMap().getContentTypeFor(url);
}
/**
* Determines the MIME-type of the resource represented by the input stream
* {@code is} by reading its first few characters.
*
* @param is
* the resource representing input stream to determine the
* content type.
* @return the guessed content type or {@code null} if the type could not be
* determined.
* @throws IOException
* if an I/O error occurs while reading from the input stream.
*/
@SuppressWarnings("nls")
public static String guessContentTypeFromStream(InputStream is)
throws IOException {
if (!is.markSupported()) {
return null;
}
// Look ahead up to 64 bytes for the longest encoded header
is.mark(64);
byte[] bytes = new byte[64];
int length = is.read(bytes);
is.reset();
// Check for Unicode BOM encoding indicators
String encoding = "ASCII";
int start = 0;
if (length > 1) {
if ((bytes[0] == (byte) 0xFF) && (bytes[1] == (byte) 0xFE)) {
encoding = "UTF-16LE";
start = 2;
length -= length & 1;
}
if ((bytes[0] == (byte) 0xFE) && (bytes[1] == (byte) 0xFF)) {
encoding = "UTF-16BE";
start = 2;
length -= length & 1;
}
if (length > 2) {
if ((bytes[0] == (byte) 0xEF) && (bytes[1] == (byte) 0xBB)
&& (bytes[2] == (byte) 0xBF)) {
encoding = "UTF-8";
start = 3;
}
if (length > 3) {
if ((bytes[0] == (byte) 0x00) && (bytes[1] == (byte) 0x00)
&& (bytes[2] == (byte) 0xFE)
&& (bytes[3] == (byte) 0xFF)) {
encoding = "UTF-32BE";
start = 4;
length -= length & 3;
}
if ((bytes[0] == (byte) 0xFF) && (bytes[1] == (byte) 0xFE)
&& (bytes[2] == (byte) 0x00)
&& (bytes[3] == (byte) 0x00)) {
encoding = "UTF-32LE";
start = 4;
length -= length & 3;
}
}
}
}
String header = new String(bytes, start, length - start, encoding);
// Check binary types
if (header.startsWith("PK")) {
return "application/zip";
}
if (header.startsWith("GI")) {
return "image/gif";
}
// Check text types
String textHeader = header.trim().toUpperCase();
if (textHeader.startsWith("<!DOCTYPE HTML") ||
textHeader.startsWith("<HTML") ||
textHeader.startsWith("<HEAD") ||
textHeader.startsWith("<BODY") ||
textHeader.startsWith("<HEAD")) {
return "text/html";
}
if (textHeader.startsWith("<?XML")) {
return "application/xml";
}
// Give up
return null;
}
/**
* Performs any necessary string parsing on the input string such as
* converting non-alphanumeric character into underscore.
*
* @param typeString
* the parsed string
* @return the string to be parsed
*/
private String parseTypeString(String typeString) {
StringBuilder typeStringBuffer = new StringBuilder(typeString);
for (int i = 0; i < typeStringBuffer.length(); i++) {
// if non-alphanumeric, replace it with '_'
char c = typeStringBuffer.charAt(i);
if (!(Character.isLetter(c) || Character.isDigit(c) || c == '.')) {
typeStringBuffer.setCharAt(i, '_');
}
}
return typeStringBuffer.toString();
}
/**
* Sets the flag indicating whether this connection allows user interaction
* or not. This method can only be called prior to the connection
* establishment.
*
* @param newValue
* the value of the flag to be set.
* @throws IllegalStateException
* if this method attempts to change the flag after the
* connection has been established.
* @see #allowUserInteraction
*/
public void setAllowUserInteraction(boolean newValue) {
if (connected) {
throw new IllegalStateException(Msg.getString("K0037")); //$NON-NLS-1$
}
this.allowUserInteraction = newValue;
}
/**
* Sets the internally used content handler factory. The content factory can
* only be set if it is allowed by the security manager and only once during
* the lifetime of the application.
*
* @param contentFactory
* the content factory to be set.
* @throws Error
* if the security manager does not allow to set the content
* factory or it has been already set earlier ago.
*/
public static synchronized void setContentHandlerFactory(
ContentHandlerFactory contentFactory) {
if (contentHandlerFactory != null) {
throw new Error(Msg.getString("K004e")); //$NON-NLS-1$
}
SecurityManager sManager = System.getSecurityManager();
if (sManager != null) {
sManager.checkSetFactory();
}
contentHandlerFactory = contentFactory;
}
/**
* Sets the default value for the flag indicating whether this connection
* allows user interaction or not. Existing {@code URLConnection}s are
* unaffected.
*
* @param allows
* the default value of the flag to be used for new connections.
* @see #defaultAllowUserInteraction
* @see #allowUserInteraction
*/
public static void setDefaultAllowUserInteraction(boolean allows) {
defaultAllowUserInteraction = allows;
}
/**
* Sets the default value of the specified request header field. This value
* will be used for the specific field of every newly created connection.
* The current implementation of this method does nothing.
*
* @param field
* the request header field to be set.
* @param value
* the default value to be used.
* @deprecated Use {@link #setRequestProperty} of an existing {@code
* URLConnection} instance.
*/
@Deprecated
public static void setDefaultRequestProperty(String field, String value) {
}
/**
* Sets the default value for the flag indicating whether this connection
* allows to use caches. Existing {@code URLConnection}s are unaffected.
*
* @param newValue
* the default value of the flag to be used for new connections.
* @see #defaultUseCaches
* @see #useCaches
*/
public void setDefaultUseCaches(boolean newValue) {
if (connected) {
throw new IllegalAccessError(Msg.getString("K0037")); //$NON-NLS-1$
}
defaultUseCaches = newValue;
}
/**
* Sets the flag indicating whether this {@code URLConnection} allows input.
* It cannot be set after the connection is established.
*
* @param newValue
* the new value for the flag to be set.
* @throws IllegalAccessError
* if this method attempts to change the value after the
* connection has been already established.
* @see #doInput
*/
public void setDoInput(boolean newValue) {
if (connected) {
throw new IllegalStateException(Msg.getString("K0037")); //$NON-NLS-1$
}
this.doInput = newValue;
}
/**
* Sets the flag indicating whether this {@code URLConnection} allows
* output. It cannot be set after the connection is established.
*
* @param newValue
* the new value for the flag to be set.
* @throws IllegalAccessError
* if this method attempts to change the value after the
* connection has been already established.
* @see #doOutput
*/
public void setDoOutput(boolean newValue) {
if (connected) {
throw new IllegalStateException(Msg.getString("K0037")); //$NON-NLS-1$
}
this.doOutput = newValue;
}
/**
* Sets the internal map which is used by all {@code URLConnection}
* instances to determine the MIME-type according to a filename extension.
*
* @param map
* the MIME table to be set.
*/
public static void setFileNameMap(FileNameMap map) {
SecurityManager manager = System.getSecurityManager();
if (manager != null) {
manager.checkSetFactory();
}
synchronized (URLConnection.class) {
fileNameMap = map;
}
}
/**
* Sets the point of time since when the data must be modified to be
* transmitted. Some protocols transmit data only if it has been modified
* more recently than a particular time. The data will be transmitted
* regardless of its timestamp if this option is set to {@code 0}.
*
* @param newValue
* the time in milliseconds since January 1, 1970 GMT.
* @throws IllegalStateException
* if this {@code URLConnection} has already been connected.
* @see #ifModifiedSince
*/
public void setIfModifiedSince(long newValue) {
if (connected) {
throw new IllegalStateException(Msg.getString("K0037")); //$NON-NLS-1$
}
this.ifModifiedSince = newValue;
}
/**
* Sets the value of the specified request header field. The value will only
* be used by the current {@code URLConnection} instance. This method can
* only be called before the connection is established.
*
* @param field
* the request header field to be set.
* @param newValue
* the new value of the specified property.
* @throws IllegalStateException
* if the connection has been already established.
* @throws NullPointerException
* if the parameter {@code field} is {@code null}.
*/
public void setRequestProperty(String field, String newValue) {
if (connected) {
throw new IllegalStateException(Msg.getString("K0037")); //$NON-NLS-1$
}
if (field == null) {
throw new NullPointerException(Msg.getString("KA007")); //$NON-NLS-1$
}
}
/**
* Sets the flag indicating whether this connection allows to use caches or
* not. This method can only be called prior to the connection
* establishment.
*
* @param newValue
* the value of the flag to be set.
* @throws IllegalStateException
* if this method attempts to change the flag after the
* connection has been established.
* @see #useCaches
*/
public void setUseCaches(boolean newValue) {
if (connected) {
throw new IllegalStateException(Msg.getString("K0037")); //$NON-NLS-1$
}
this.useCaches = newValue;
}
/**
* Sets the timeout value in milliseconds for establishing the connection to
* the resource pointed by this {@code URLConnection} instance. A {@code
* SocketTimeoutException} is thrown if the connection could not be
* established in this time. Default is {@code 0} which stands for an
* infinite timeout.
*
* @param timeout
* the connecting timeout in milliseconds.
* @throws IllegalArgumentException
* if the parameter {@code timeout} is less than zero.
*/
public void setConnectTimeout(int timeout) {
if (0 > timeout) {
throw new IllegalArgumentException(Msg.getString("K0036")); //$NON-NLS-1$
}
this.connectTimeout = timeout;
}
/**
* Gets the configured connecting timeout.
*
* @return the connecting timeout value in milliseconds.
*/
public int getConnectTimeout() {
return connectTimeout;
}
/**
* Sets the timeout value in milliseconds for reading from the input stream
* of an established connection to the resource. A {@code
* SocketTimeoutException} is thrown if the connection could not be
* established in this time. Default is {@code 0} which stands for an
* infinite timeout.
*
* @param timeout
* the reading timeout in milliseconds.
* @throws IllegalArgumentException
* if the parameter {@code timeout} is less than zero.
*/
public void setReadTimeout(int timeout) {
if (0 > timeout) {
throw new IllegalArgumentException(Msg.getString("K0036")); //$NON-NLS-1$
}
this.readTimeout = timeout;
}
/**
* Gets the configured timeout for reading from the input stream of an
* established connection to the resource.
*
* @return the reading timeout value in milliseconds.
*/
public int getReadTimeout() {
return readTimeout;
}
/**
* Returns the string representation containing the name of this class and
* the URL.
*
* @return the string representation of this {@code URLConnection} instance.
*/
@Override
public String toString() {
return getClass().getName() + ":" + url.toString(); //$NON-NLS-1$
}
static class DefaultContentHandler extends java.net.ContentHandler {
/**
* @param u
* the URL connection
*
* @see java.net.ContentHandler#getContent(java.net.URLConnection)
*/
@Override
public Object getContent(URLConnection u) throws IOException {
return u.getInputStream();
}
}
}