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