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 socketfactoryName name of the socket factory class
68 * @param host the host name/IP
69 * @param port the port on the host
70 * @param localAddress the local host name/IP to bind the socket to
71 * @param localPort the port on the local machine
72 * @param timeout the timeout value to be used in milliseconds. If the socket cannot be
73 * completed within the given time limit, it will be abandoned
74 *
75 * @return a connected Socket
76 *
77 * @throws IOException if an I/O error occurs while creating the socket
78 * @throws UnknownHostException if the IP address of the host cannot be
79 * determined
80 * @throws ConnectTimeoutException if socket cannot be connected within the
81 * given time limit
82 *
83 */
84 public static Socket createSocket(
85 final String socketfactoryName,
86 final String host,
87 final int port,
88 final InetAddress localAddress,
89 final int localPort,
90 int timeout)
91 throws IOException, UnknownHostException, ConnectTimeoutException
92 {
93 if (REFLECTION_FAILED) {
94
95 return null;
96 }
97
98
99
100
101
102
103
104 try {
105 Class socketfactoryClass = Class.forName(socketfactoryName);
106 Method method = socketfactoryClass.getMethod("getDefault",
107 new Class[] {});
108 Object socketfactory = method.invoke(null,
109 new Object[] {});
110 method = socketfactoryClass.getMethod("createSocket",
111 new Class[] {});
112 Socket socket = (Socket) method.invoke(socketfactory, new Object[] {});
113
114 if (INETSOCKETADDRESS_CONSTRUCTOR == null) {
115 Class addressClass = Class.forName("java.net.InetSocketAddress");
116 INETSOCKETADDRESS_CONSTRUCTOR = addressClass.getConstructor(
117 new Class[] { String.class, Integer.TYPE });
118 }
119
120 Object addr = INETSOCKETADDRESS_CONSTRUCTOR.newInstance(
121 new Object[] { host, new Integer(port)});
122
123 if (SOCKETCONNECT_METHOD == null) {
124 SOCKETCONNECT_METHOD = Socket.class.getMethod("connect",
125 new Class[] {Class.forName("java.net.SocketAddress"), Integer.TYPE});
126 }
127
128 SOCKETCONNECT_METHOD.invoke(socket,
129 new Object[] { addr, new Integer(timeout)});
130
131 return socket;
132 }
133 catch (InvocationTargetException e) {
134 Throwable cause = e.getTargetException();
135 if (SOCKETTIMEOUTEXCEPTION_CLASS == null) {
136 try {
137 SOCKETTIMEOUTEXCEPTION_CLASS = Class.forName("java.net.SocketTimeoutException");
138 } catch (ClassNotFoundException ex) {
139
140 REFLECTION_FAILED = true;
141 return null;
142 }
143 }
144 if (SOCKETTIMEOUTEXCEPTION_CLASS.isInstance(cause)) {
145 throw new ConnectTimeoutException(
146 "The host did not accept the connection within timeout of "
147 + timeout + " ms", cause);
148 }
149 if (cause instanceof IOException) {
150 throw (IOException)cause;
151 }
152 return null;
153 }
154 catch (Exception e) {
155 REFLECTION_FAILED = true;
156 return null;
157 }
158 }
159 }