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