1
2
3
4
5
6
7
8
9
10
11 package org.mule.transport.tcp;
12
13 import org.mule.api.MessagingException;
14 import org.mule.api.MuleException;
15 import org.mule.api.MuleMessage;
16 import org.mule.api.endpoint.ImmutableEndpoint;
17 import org.mule.api.lifecycle.InitialisationException;
18 import org.mule.api.transport.Connector;
19 import org.mule.config.i18n.CoreMessages;
20 import org.mule.model.streaming.CallbackOutputStream;
21 import org.mule.transport.AbstractConnector;
22 import org.mule.transport.tcp.protocols.SafeProtocol;
23 import org.mule.util.monitor.ExpiryMonitor;
24
25 import java.io.BufferedOutputStream;
26 import java.io.DataOutputStream;
27 import java.io.IOException;
28 import java.io.OutputStream;
29 import java.net.ServerSocket;
30 import java.net.Socket;
31 import java.net.SocketException;
32 import java.net.URI;
33
34 import org.apache.commons.pool.impl.GenericKeyedObjectPool;
35
36
37
38
39
40
41
42 public class TcpConnector extends AbstractConnector
43 {
44 public static final String TCP = "tcp";
45
46
47 public static final String KEEP_SEND_SOCKET_OPEN_PROPERTY = "keepSendSocketOpen";
48 public static final int DEFAULT_SOCKET_TIMEOUT = INT_VALUE_NOT_SET;
49 public static final int DEFAULT_SO_LINGER = INT_VALUE_NOT_SET;
50 public static final int DEFAULT_BUFFER_SIZE = INT_VALUE_NOT_SET;
51 public static final int DEFAULT_BACKLOG = INT_VALUE_NOT_SET;
52
53
54 public static final boolean SERVER = false;
55 public static final boolean CLIENT = true;
56
57 private int clientSoTimeout = DEFAULT_SOCKET_TIMEOUT;
58 private int serverSoTimeout = DEFAULT_SOCKET_TIMEOUT;
59 private int sendBufferSize = DEFAULT_BUFFER_SIZE;
60 private int receiveBufferSize = DEFAULT_BUFFER_SIZE;
61 private int receiveBacklog = DEFAULT_BACKLOG;
62 private boolean sendTcpNoDelay;
63 private boolean validateConnections = true;
64 private Boolean reuseAddress = Boolean.TRUE;
65 private int socketSoLinger = DEFAULT_SO_LINGER;
66 private TcpProtocol tcpProtocol;
67 private boolean keepSendSocketOpen = false;
68 private boolean keepAlive = false;
69 private AbstractTcpSocketFactory socketFactory;
70 private SimpleServerSocketFactory serverSocketFactory;
71 private GenericKeyedObjectPool socketsPool = new GenericKeyedObjectPool();
72 private int keepAliveTimeout = 0;
73 private ExpiryMonitor keepAliveMonitor;
74
75
76 private TcpSocketKey lastSocketKey;
77
78 public TcpConnector()
79 {
80 setSocketFactory(new TcpSocketFactory());
81 setServerSocketFactory(new TcpServerSocketFactory());
82 setTcpProtocol(new SafeProtocol());
83 keepAliveMonitor = new ExpiryMonitor("SocketTimeoutMonitor", 1000);
84 }
85
86 public void configureSocket(boolean client, Socket socket) throws SocketException
87 {
88
89
90
91 if (newValue(getReceiveBufferSize(), socket.getReceiveBufferSize()))
92 {
93 socket.setReceiveBufferSize(getReceiveBufferSize());
94 }
95 if (newValue(getSendBufferSize(), socket.getSendBufferSize()))
96 {
97 socket.setSendBufferSize(getSendBufferSize());
98 }
99 if (client)
100 {
101 if (newValue(getClientSoTimeout(), socket.getSoTimeout()))
102 {
103 socket.setSoTimeout(getClientSoTimeout());
104 }
105 }
106 else
107 {
108 if (newValue(getServerSoTimeout(), socket.getSoTimeout()))
109 {
110 socket.setSoTimeout(getServerSoTimeout());
111 }
112 }
113 if (newValue(getSocketSoLinger(), socket.getSoLinger()))
114 {
115 socket.setSoLinger(true, getSocketSoLinger());
116 }
117 try
118 {
119 socket.setTcpNoDelay(isSendTcpNoDelay());
120 }
121 catch (SocketException e)
122 {
123
124 }
125 socket.setKeepAlive(isKeepAlive());
126 }
127
128 private boolean newValue(int parameter, int socketValue)
129 {
130 return parameter != Connector.INT_VALUE_NOT_SET && parameter != socketValue;
131 }
132
133 protected void doInitialise() throws InitialisationException
134 {
135 socketsPool.setFactory(getSocketFactory());
136 socketsPool.setTestOnBorrow(true);
137 socketsPool.setTestOnReturn(true);
138
139 socketsPool.setMaxActive(1);
140 socketsPool.setWhenExhaustedAction(GenericKeyedObjectPool.WHEN_EXHAUSTED_BLOCK);
141 }
142
143 protected void doDispose()
144 {
145 logger.debug("Closing TCP connector");
146 try
147 {
148 socketsPool.close();
149 }
150 catch (Exception e)
151 {
152 logger.warn("Failed to close dispatcher socket pool: " + e.getMessage());
153 }
154
155 keepAliveMonitor.dispose();
156 }
157
158
159
160
161
162 protected Socket getSocket(ImmutableEndpoint endpoint) throws Exception
163 {
164 TcpSocketKey socketKey = new TcpSocketKey(endpoint);
165 if (logger.isDebugEnabled())
166 {
167 logger.debug("borrowing socket for " + socketKey + "/" + socketKey.hashCode());
168 if (null != lastSocketKey)
169 {
170 logger.debug("same as " + lastSocketKey.hashCode() + "? " + lastSocketKey.equals(socketKey));
171 }
172 }
173 Socket socket = (Socket) socketsPool.borrowObject(socketKey);
174 if (logger.isDebugEnabled())
175 {
176 logger.debug("borrowed socket, "
177 + (socket.isClosed() ? "closed" : "open")
178 + "; debt " + socketsPool.getNumActive());
179 }
180 return socket;
181 }
182
183 void releaseSocket(Socket socket, ImmutableEndpoint endpoint) throws Exception
184 {
185 TcpSocketKey socketKey = new TcpSocketKey(endpoint);
186 lastSocketKey = socketKey;
187 socketsPool.returnObject(socketKey, socket);
188 if (logger.isDebugEnabled())
189 {
190 logger.debug("returning socket for " + socketKey.hashCode());
191 logger.debug("returned socket; debt " + socketsPool.getNumActive());
192 }
193 }
194
195 public OutputStream getOutputStream(final ImmutableEndpoint endpoint, MuleMessage message)
196 throws MuleException
197 {
198 final Socket socket;
199 try
200 {
201 socket = getSocket(endpoint);
202 }
203 catch (Exception e)
204 {
205 throw new MessagingException(CoreMessages.failedToGetOutputStream(), message, e);
206 }
207 if (socket == null)
208 {
209
210 throw new IllegalStateException("could not get socket for endpoint: "
211 + endpoint.getEndpointURI().getAddress());
212 }
213 try
214 {
215 return new CallbackOutputStream(
216 new DataOutputStream(new BufferedOutputStream(socket.getOutputStream())),
217 new CallbackOutputStream.Callback()
218 {
219 public void onClose() throws Exception
220 {
221 releaseSocket(socket, endpoint);
222 }
223 });
224 }
225 catch (IOException e)
226 {
227 throw new MessagingException(CoreMessages.failedToGetOutputStream(), message, e);
228 }
229 }
230
231 protected void doConnect() throws Exception
232 {
233
234 }
235
236 protected void doDisconnect() throws Exception
237 {
238 socketsPool.clear();
239 }
240
241 protected void doStart() throws MuleException
242 {
243
244 }
245
246 protected void doStop() throws MuleException
247 {
248
249 }
250
251 public String getProtocol()
252 {
253 return TCP;
254 }
255
256
257
258 public boolean isKeepSendSocketOpen()
259 {
260 return keepSendSocketOpen;
261 }
262
263 public void setKeepSendSocketOpen(boolean keepSendSocketOpen)
264 {
265 this.keepSendSocketOpen = keepSendSocketOpen;
266 }
267
268
269
270
271
272
273 public void setTimeout(int timeout)
274 {
275 setClientSoTimeout(timeout);
276 setServerSoTimeout(timeout);
277 }
278
279 public int getClientSoTimeout()
280 {
281 return this.clientSoTimeout;
282 }
283
284 public void setClientSoTimeout(int timeout)
285 {
286 this.clientSoTimeout = valueOrDefault(timeout, 0, DEFAULT_SOCKET_TIMEOUT);
287 }
288
289 public int getServerSoTimeout()
290 {
291 return serverSoTimeout;
292 }
293
294 public void setServerSoTimeout(int timeout)
295 {
296 this.serverSoTimeout = valueOrDefault(timeout, 0, DEFAULT_SOCKET_TIMEOUT);
297 }
298
299
300 public int getBufferSize()
301 {
302 return sendBufferSize;
303 }
304
305
306 public void setBufferSize(int bufferSize)
307 {
308 sendBufferSize = valueOrDefault(bufferSize, 1, DEFAULT_BUFFER_SIZE);
309 }
310
311 public int getSendBufferSize()
312 {
313 return sendBufferSize;
314 }
315
316 public void setSendBufferSize(int bufferSize)
317 {
318 sendBufferSize = valueOrDefault(bufferSize, 1, DEFAULT_BUFFER_SIZE);
319 }
320
321 public int getReceiveBufferSize()
322 {
323 return receiveBufferSize;
324 }
325
326 public void setReceiveBufferSize(int bufferSize)
327 {
328 receiveBufferSize = valueOrDefault(bufferSize, 1, DEFAULT_BUFFER_SIZE);
329 }
330
331 public int getReceiveBacklog()
332 {
333 return receiveBacklog;
334 }
335
336 public void setReceiveBacklog(int receiveBacklog)
337 {
338 this.receiveBacklog = valueOrDefault(receiveBacklog, 0, DEFAULT_BACKLOG);
339 }
340
341 public int getSocketSoLinger()
342 {
343 return socketSoLinger;
344 }
345
346 public void setSocketSoLinger(int soLinger)
347 {
348 this.socketSoLinger = valueOrDefault(soLinger, 0, INT_VALUE_NOT_SET);
349 }
350
351
352
353
354
355 public int getBacklog()
356 {
357 return receiveBacklog;
358 }
359
360
361
362
363
364 public void setBacklog(int backlog)
365 {
366 this.receiveBacklog = backlog;
367 }
368
369 public TcpProtocol getTcpProtocol()
370 {
371 return tcpProtocol;
372 }
373
374 public void setTcpProtocol(TcpProtocol tcpProtocol)
375 {
376 this.tcpProtocol = tcpProtocol;
377 }
378
379 public boolean isRemoteSyncEnabled()
380 {
381 return true;
382 }
383
384 public boolean isKeepAlive()
385 {
386 return keepAlive;
387 }
388
389 public void setKeepAlive(boolean keepAlive)
390 {
391 this.keepAlive = keepAlive;
392 }
393
394 public boolean isSendTcpNoDelay()
395 {
396 return sendTcpNoDelay;
397 }
398
399 public void setSendTcpNoDelay(boolean sendTcpNoDelay)
400 {
401 this.sendTcpNoDelay = sendTcpNoDelay;
402 }
403
404 protected void setSocketFactory(AbstractTcpSocketFactory socketFactory)
405 {
406 this.socketFactory = socketFactory;
407 }
408
409 protected AbstractTcpSocketFactory getSocketFactory()
410 {
411 return socketFactory;
412 }
413
414 public SimpleServerSocketFactory getServerSocketFactory()
415 {
416 return serverSocketFactory;
417 }
418
419 public void setServerSocketFactory(SimpleServerSocketFactory serverSocketFactory)
420 {
421 this.serverSocketFactory = serverSocketFactory;
422 }
423
424 protected ServerSocket getServerSocket(URI uri) throws IOException
425 {
426 return getServerSocketFactory().createServerSocket(uri, getReceiveBacklog(), isReuseAddress());
427 }
428
429 private static int valueOrDefault(int value, int threshhold, int deflt)
430 {
431 if (value < threshhold)
432 {
433 return deflt;
434 }
435 else
436 {
437 return value;
438 }
439 }
440
441
442
443
444
445
446 public boolean isValidateConnections()
447 {
448 return validateConnections;
449 }
450
451
452
453
454
455 public void setValidateConnections(boolean validateConnections)
456 {
457 this.validateConnections = validateConnections;
458 }
459
460
461
462
463 public Boolean isReuseAddress()
464 {
465 return reuseAddress;
466 }
467
468
469
470
471
472
473 public void setReuseAddress(Boolean reuseAddress)
474 {
475 this.reuseAddress = reuseAddress;
476 }
477
478 public ExpiryMonitor getKeepAliveMonitor()
479 {
480 return keepAliveMonitor;
481 }
482
483
484
485
486 public int getKeepAliveTimeout()
487 {
488 return keepAliveTimeout;
489 }
490
491
492
493
494 public void setKeepAliveTimeout(int keepAliveTimeout)
495 {
496 this.keepAliveTimeout = keepAliveTimeout;
497 }
498
499 }