1
2
3
4
5
6
7
8
9
10
11 package psiprobe.tools;
12
13 import java.io.IOException;
14 import java.net.Socket;
15
16 import org.slf4j.Logger;
17 import org.slf4j.LoggerFactory;
18
19
20
21
22 public final class AsyncSocketFactory {
23
24
25 private static final Logger logger = LoggerFactory.getLogger(AsyncSocketFactory.class);
26
27
28
29
30 private AsyncSocketFactory() {
31
32 }
33
34
35
36
37
38
39
40
41
42
43
44
45 public static Socket createSocket(String server, int port, long timeout) throws IOException {
46 SocketWrapper socketWrapper = new SocketWrapper();
47 socketWrapper.server = server;
48 socketWrapper.port = port;
49
50 Object sync = new Object();
51 Thread socketThread = new Thread(new SocketRunnable(socketWrapper, sync));
52 socketThread.setDaemon(true);
53 Thread timeoutThread = new Thread(new TimeoutRunnable(sync, timeout * 1000));
54 timeoutThread.setDaemon(true);
55
56 timeoutThread.start();
57 socketThread.start();
58
59 synchronized (sync) {
60 if (socketWrapper.socket == null) {
61 boolean inProgress = true;
62 while (inProgress) {
63 try {
64 sync.wait(timeout * 1000);
65 } catch (InterruptedException e) {
66
67 Thread.currentThread().interrupt();
68 logger.trace("", e);
69 }
70 inProgress = false;
71 }
72 }
73 }
74
75 timeoutThread.interrupt();
76 socketThread.interrupt();
77
78 socketWrapper.valid = false;
79
80 if (socketWrapper.socket == null && socketWrapper.exception != null) {
81 throw socketWrapper.exception;
82 }
83 if (socketWrapper.socket == null) {
84 throw new TimeoutException();
85 }
86
87 return socketWrapper.getSocket();
88 }
89
90
91
92
93 static final class SocketWrapper {
94
95
96 Socket socket;
97
98
99 String server;
100
101
102 int port;
103
104
105 IOException exception;
106
107
108 boolean valid = true;
109
110
111
112
113
114
115 public Socket getSocket() {
116 return socket;
117 }
118
119
120
121
122
123
124 public void setSocket(Socket socket) {
125 this.socket = socket;
126 }
127
128
129
130
131
132
133 public String getServer() {
134 return server;
135 }
136
137
138
139
140
141
142 public int getPort() {
143 return port;
144 }
145
146
147
148
149
150
151 public void setException(IOException exception) {
152 this.exception = exception;
153 }
154
155
156
157
158
159
160 public boolean isValid() {
161 return valid;
162 }
163
164
165
166
167 private SocketWrapper() {}
168
169 }
170
171
172
173
174 static final class SocketRunnable implements Runnable {
175
176
177 private final SocketWrapper socketWrapper;
178
179
180 private final Object sync;
181
182
183
184
185
186
187
188 private SocketRunnable(SocketWrapper socketWrapper, Object sync) {
189 this.socketWrapper = socketWrapper;
190 this.sync = sync;
191 }
192
193 @Override
194 public void run() {
195 try (Socket socket = new Socket(socketWrapper.getServer(), socketWrapper.getPort())) {
196 socketWrapper.setSocket(socket);
197 if (!socketWrapper.isValid()) {
198 socketWrapper.getSocket().close();
199 socketWrapper.setSocket(null);
200 }
201 } catch (IOException e) {
202 logger.trace("", e);
203 socketWrapper.setException(e);
204 }
205 synchronized (sync) {
206 sync.notifyAll();
207 }
208 }
209
210 }
211
212
213
214
215 static final class TimeoutRunnable implements Runnable {
216
217
218 private final Object sync;
219
220
221 private final long timeout;
222
223
224
225
226
227
228
229 private TimeoutRunnable(Object sync, long timeout) {
230 this.sync = sync;
231 this.timeout = timeout;
232 }
233
234 @Override
235 public void run() {
236 try {
237 Thread.sleep(timeout);
238 synchronized (sync) {
239 sync.notifyAll();
240 }
241 } catch (InterruptedException e) {
242
243 Thread.currentThread().interrupt();
244 logger.trace("", e);
245 }
246 }
247
248 }
249
250 }