1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31 package org.apache.commons.httpclient.protocol;
32
33 import java.io.IOException;
34 import java.lang.reflect.Constructor;
35 import java.lang.reflect.InvocationTargetException;
36 import java.lang.reflect.Method;
37 import java.net.InetAddress;
38 import java.net.Socket;
39 import java.net.UnknownHostException;
40
41 import org.apache.commons.httpclient.ConnectTimeoutException;
42
43 /***
44 * This helper class uses refelction in order to execute Socket methods
45 * available in Java 1.4 and above
46 *
47 * @author Oleg Kalnichevski
48 *
49 * @since 3.0
50 */
51 public final class ReflectionSocketFactory {
52
53 private static boolean REFLECTION_FAILED = false;
54
55 private static Constructor INETSOCKETADDRESS_CONSTRUCTOR = null;
56 private static Method SOCKETCONNECT_METHOD = null;
57 private static Method SOCKETBIND_METHOD = null;
58 private static Class SOCKETTIMEOUTEXCEPTION_CLASS = null;
59
60 private ReflectionSocketFactory() {
61 super();
62 }
63
64 /***
65 * This method attempts to execute Socket method available since Java 1.4
66 * using reflection. If the methods are not available or could not be executed
67 * <tt>null</tt> is returned
68 *
69 * @param socketfactoryName name of the socket factory class
70 * @param host the host name/IP
71 * @param port the port on the host
72 * @param localAddress the local host name/IP to bind the socket to
73 * @param localPort the port on the local machine
74 * @param timeout the timeout value to be used in milliseconds. If the socket cannot be
75 * completed within the given time limit, it will be abandoned
76 *
77 * @return a connected Socket
78 *
79 * @throws IOException if an I/O error occurs while creating the socket
80 * @throws UnknownHostException if the IP address of the host cannot be
81 * determined
82 * @throws ConnectTimeoutException if socket cannot be connected within the
83 * given time limit
84 *
85 */
86 public static Socket createSocket(
87 final String socketfactoryName,
88 final String host,
89 final int port,
90 final InetAddress localAddress,
91 final int localPort,
92 int timeout)
93 throws IOException, UnknownHostException, ConnectTimeoutException
94 {
95 if (REFLECTION_FAILED) {
96
97 return null;
98 }
99
100
101
102
103
104
105
106
107
108 try {
109 Class socketfactoryClass = Class.forName(socketfactoryName);
110 Method method = socketfactoryClass.getMethod("getDefault",
111 new Class[] {});
112 Object socketfactory = method.invoke(null,
113 new Object[] {});
114 method = socketfactoryClass.getMethod("createSocket",
115 new Class[] {});
116 Socket socket = (Socket) method.invoke(socketfactory, new Object[] {});
117
118 if (INETSOCKETADDRESS_CONSTRUCTOR == null) {
119 Class addressClass = Class.forName("java.net.InetSocketAddress");
120 INETSOCKETADDRESS_CONSTRUCTOR = addressClass.getConstructor(
121 new Class[] { InetAddress.class, Integer.TYPE });
122 }
123
124 Object remoteaddr = INETSOCKETADDRESS_CONSTRUCTOR.newInstance(
125 new Object[] { InetAddress.getByName(host), new Integer(port)});
126
127 Object localaddr = INETSOCKETADDRESS_CONSTRUCTOR.newInstance(
128 new Object[] { localAddress, new Integer(localPort)});
129
130 if (SOCKETCONNECT_METHOD == null) {
131 SOCKETCONNECT_METHOD = Socket.class.getMethod("connect",
132 new Class[] {Class.forName("java.net.SocketAddress"), Integer.TYPE});
133 }
134
135 if (SOCKETBIND_METHOD == null) {
136 SOCKETBIND_METHOD = Socket.class.getMethod("bind",
137 new Class[] {Class.forName("java.net.SocketAddress")});
138 }
139 SOCKETBIND_METHOD.invoke(socket, new Object[] { localaddr});
140 SOCKETCONNECT_METHOD.invoke(socket, new Object[] { remoteaddr, new Integer(timeout)});
141 return socket;
142 }
143 catch (InvocationTargetException e) {
144 Throwable cause = e.getTargetException();
145 if (SOCKETTIMEOUTEXCEPTION_CLASS == null) {
146 try {
147 SOCKETTIMEOUTEXCEPTION_CLASS = Class.forName("java.net.SocketTimeoutException");
148 } catch (ClassNotFoundException ex) {
149
150 REFLECTION_FAILED = true;
151 return null;
152 }
153 }
154 if (SOCKETTIMEOUTEXCEPTION_CLASS.isInstance(cause)) {
155 throw new ConnectTimeoutException(
156 "The host did not accept the connection within timeout of "
157 + timeout + " ms", cause);
158 }
159 if (cause instanceof IOException) {
160 throw (IOException)cause;
161 }
162 return null;
163 }
164 catch (Exception e) {
165 REFLECTION_FAILED = true;
166 return null;
167 }
168 }
169 }