001: /*
002: * $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//httpclient/src/java/org/apache/commons/httpclient/protocol/ControllerThreadSocketFactory.java,v 1.2 2004/04/18 23:51:38 jsdever Exp $
003: * $Revision: 480424 $
004: * $Date: 2006-11-29 06:56:49 +0100 (Wed, 29 Nov 2006) $
005: *
006: * ====================================================================
007: *
008: * Licensed to the Apache Software Foundation (ASF) under one or more
009: * contributor license agreements. See the NOTICE file distributed with
010: * this work for additional information regarding copyright ownership.
011: * The ASF licenses this file to You under the Apache License, Version 2.0
012: * (the "License"); you may not use this file except in compliance with
013: * the License. You may obtain a copy of the License at
014: *
015: * http://www.apache.org/licenses/LICENSE-2.0
016: *
017: * Unless required by applicable law or agreed to in writing, software
018: * distributed under the License is distributed on an "AS IS" BASIS,
019: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
020: * See the License for the specific language governing permissions and
021: * limitations under the License.
022: * ====================================================================
023: *
024: * This software consists of voluntary contributions made by many
025: * individuals on behalf of the Apache Software Foundation. For more
026: * information on the Apache Software Foundation, please see
027: * <http://www.apache.org/>.
028: *
029: */
030:
031: package org.apache.commons.httpclient.protocol;
032:
033: import java.io.IOException;
034: import java.net.InetAddress;
035: import java.net.Socket;
036: import java.net.UnknownHostException;
037:
038: import org.apache.commons.httpclient.ConnectTimeoutException;
039: import org.apache.commons.httpclient.util.TimeoutController;
040:
041: /**
042: * This helper class is intedned to help work around the limitation of older Java versions
043: * (older than 1.4) that prevents from specifying a connection timeout when creating a
044: * socket. This factory executes a controller thread overssing the process of socket
045: * initialisation. If the socket constructor cannot be created within the specified time
046: * limit, the controller terminates and throws an {@link ConnectTimeoutException}
047: *
048: * @author Ortwin Glueck
049: * @author Oleg Kalnichevski
050: *
051: * @since 3.0
052: */
053: public final class ControllerThreadSocketFactory {
054:
055: private ControllerThreadSocketFactory() {
056: super ();
057: }
058:
059: /**
060: * This method spawns a controller thread overseeing the process of socket
061: * initialisation. If the socket constructor cannot be created within the specified time
062: * limit, the controller terminates and throws an {@link ConnectTimeoutException}
063: *
064: * @param host the host name/IP
065: * @param port the port on the host
066: * @param localAddress the local host name/IP to bind the socket to
067: * @param localPort the port on the local machine
068: * @param timeout the timeout value to be used in milliseconds. If the socket cannot be
069: * completed within the given time limit, it will be abandoned
070: *
071: * @return a connected Socket
072: *
073: * @throws IOException if an I/O error occurs while creating the socket
074: * @throws UnknownHostException if the IP address of the host cannot be
075: * determined
076: * @throws ConnectTimeoutException if socket cannot be connected within the
077: * given time limit
078: *
079: */
080: public static Socket createSocket(
081: final ProtocolSocketFactory socketfactory,
082: final String host, final int port,
083: final InetAddress localAddress, final int localPort,
084: int timeout) throws IOException, UnknownHostException,
085: ConnectTimeoutException {
086: SocketTask task = new SocketTask() {
087: public void doit() throws IOException {
088: setSocket(socketfactory.createSocket(host, port,
089: localAddress, localPort));
090: }
091: };
092: try {
093: TimeoutController.execute(task, timeout);
094: } catch (TimeoutController.TimeoutException e) {
095: throw new ConnectTimeoutException(
096: "The host did not accept the connection within timeout of "
097: + timeout + " ms");
098: }
099: Socket socket = task.getSocket();
100: if (task.exception != null) {
101: throw task.exception;
102: }
103: return socket;
104: }
105:
106: public static Socket createSocket(final SocketTask task, int timeout)
107: throws IOException, UnknownHostException,
108: ConnectTimeoutException {
109: try {
110: TimeoutController.execute(task, timeout);
111: } catch (TimeoutController.TimeoutException e) {
112: throw new ConnectTimeoutException(
113: "The host did not accept the connection within timeout of "
114: + timeout + " ms");
115: }
116: Socket socket = task.getSocket();
117: if (task.exception != null) {
118: throw task.exception;
119: }
120: return socket;
121: }
122:
123: /**
124: * Helper class for wrapping socket based tasks.
125: */
126: public static abstract class SocketTask implements Runnable {
127: /** The socket */
128: private Socket socket;
129: /** The exception */
130: private IOException exception;
131:
132: /**
133: * Set the socket.
134: * @param newSocket The new socket.
135: */
136: protected void setSocket(final Socket newSocket) {
137: socket = newSocket;
138: }
139:
140: /**
141: * Return the socket.
142: * @return Socket The socket.
143: */
144: protected Socket getSocket() {
145: return socket;
146: }
147:
148: /**
149: * Perform the logic.
150: * @throws IOException If an IO problem occurs
151: */
152: public abstract void doit() throws IOException;
153:
154: /** Execute the logic in this object and keep track of any exceptions. */
155: public void run() {
156: try {
157: doit();
158: } catch (IOException e) {
159: exception = e;
160: }
161: }
162: }
163: }
|