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