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