1
2
3
4
5
6
7
8
9
10
11 package org.mule.providers.tcp;
12
13 import org.mule.config.i18n.CoreMessages;
14 import org.mule.impl.model.streaming.CallbackOutputStream;
15 import org.mule.providers.AbstractConnector;
16 import org.mule.providers.tcp.i18n.TcpMessages;
17 import org.mule.providers.tcp.protocols.DefaultProtocol;
18 import org.mule.umo.MessagingException;
19 import org.mule.umo.UMOException;
20 import org.mule.umo.UMOMessage;
21 import org.mule.umo.endpoint.UMOImmutableEndpoint;
22 import org.mule.umo.lifecycle.InitialisationException;
23 import org.mule.util.ClassUtils;
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.URI;
32
33 import org.apache.commons.pool.impl.GenericKeyedObjectPool;
34
35
36
37
38
39
40
41 public class TcpConnector extends AbstractConnector
42 {
43
44
45
46 public static final String KEEP_SEND_SOCKET_OPEN_PROPERTY = "keepSendSocketOpen";
47 public static final int DEFAULT_SOCKET_TIMEOUT = INT_VALUE_NOT_SET;
48 public static final int DEFAULT_BUFFER_SIZE = INT_VALUE_NOT_SET;
49 public static final int DEFAULT_BACKLOG = INT_VALUE_NOT_SET;
50
51 private int sendTimeout = DEFAULT_SOCKET_TIMEOUT;
52 private int receiveTimeout = DEFAULT_SOCKET_TIMEOUT;
53 private int sendBufferSize = DEFAULT_BUFFER_SIZE;
54 private int receiveBufferSize = DEFAULT_BUFFER_SIZE;
55 private int receiveBacklog = DEFAULT_BACKLOG;
56 private boolean sendTcpNoDelay;
57 private boolean validateConnections = true;
58 private Boolean reuseAddress = null;
59 private int socketLinger = INT_VALUE_NOT_SET;
60 private String tcpProtocolClassName;
61 private TcpProtocol tcpProtocol;
62 private boolean keepSendSocketOpen = false;
63 private boolean keepAlive = false;
64 private PooledSocketFactory socketFactory;
65 private SimpleServerSocketFactory serverSocketFactory;
66 private GenericKeyedObjectPool dispatcherSocketsPool = new GenericKeyedObjectPool();
67
68 public TcpConnector()
69 {
70 setSocketFactory (new TcpSocketFactory());
71 setServerSocketFactory(new TcpServerSocketFactory());
72 setTcpProtocolClassName(DefaultProtocol.class.getName());
73 }
74
75 protected void doInitialise() throws InitialisationException
76 {
77 if (tcpProtocol == null)
78 {
79 try
80 {
81 tcpProtocol = (TcpProtocol) ClassUtils.instanciateClass(tcpProtocolClassName, null);
82 }
83 catch (Exception e)
84 {
85 throw new InitialisationException(TcpMessages.failedToInitMessageReader(), e);
86 }
87 }
88
89 dispatcherSocketsPool.setFactory(getSocketFactory());
90 dispatcherSocketsPool.setTestOnBorrow(true);
91 dispatcherSocketsPool.setTestOnReturn(true);
92
93 dispatcherSocketsPool.setMaxActive(1);
94 }
95
96 protected void doDispose()
97 {
98 logger.debug("Closing TCP connector");
99 try
100 {
101 dispatcherSocketsPool.close();
102 }
103 catch (Exception e)
104 {
105 logger.warn("Failed to close dispatcher socket pool: " + e.getMessage());
106 }
107 }
108
109
110
111
112
113 protected Socket getSocket(UMOImmutableEndpoint endpoint) throws Exception
114 {
115 Socket socket = (Socket) dispatcherSocketsPool.borrowObject(endpoint);
116 if (logger.isDebugEnabled())
117 {
118 logger.debug("borrowing socket; debt " + dispatcherSocketsPool.getNumActive());
119 }
120 return socket;
121 }
122
123 void releaseSocket(Socket socket, UMOImmutableEndpoint endpoint) throws Exception
124 {
125 dispatcherSocketsPool.returnObject(endpoint, socket);
126 if (logger.isDebugEnabled())
127 {
128 logger.debug("returned socket; debt " + dispatcherSocketsPool.getNumActive());
129 }
130 }
131
132 public OutputStream getOutputStream(final UMOImmutableEndpoint endpoint, UMOMessage message)
133 throws UMOException
134 {
135 final Socket socket;
136 try
137 {
138 socket = getSocket(endpoint);
139 }
140 catch (Exception e)
141 {
142 throw new MessagingException(CoreMessages.failedToGetOutputStream(), message, e);
143 }
144 if (socket == null)
145 {
146
147 throw new IllegalStateException("could not get socket for endpoint: "
148 + endpoint.getEndpointURI().getAddress());
149 }
150 try
151 {
152 return new CallbackOutputStream(
153 new DataOutputStream(new BufferedOutputStream(socket.getOutputStream())),
154 new CallbackOutputStream.Callback()
155 {
156 public void onClose() throws Exception
157 {
158 releaseSocket(socket, endpoint);
159 }
160 });
161 }
162 catch (IOException e)
163 {
164 throw new MessagingException(CoreMessages.failedToGetOutputStream(), message, e);
165 }
166 }
167
168 protected void doConnect() throws Exception
169 {
170
171 }
172
173 protected void doDisconnect() throws Exception
174 {
175 dispatcherSocketsPool.clear();
176 }
177
178 protected void doStart() throws UMOException
179 {
180
181 }
182
183 protected void doStop() throws UMOException
184 {
185
186 }
187
188 public String getProtocol()
189 {
190 return "tcp";
191 }
192
193
194
195 public boolean isKeepSendSocketOpen()
196 {
197 return keepSendSocketOpen;
198 }
199
200 public void setKeepSendSocketOpen(boolean keepSendSocketOpen)
201 {
202 this.keepSendSocketOpen = keepSendSocketOpen;
203 }
204
205
206
207
208
209 public void setTimeout(int timeout)
210 {
211 setSendTimeout(timeout);
212 setReceiveTimeout(timeout);
213 }
214
215 public int getSendTimeout()
216 {
217 return this.sendTimeout;
218 }
219
220 public void setSendTimeout(int timeout)
221 {
222 this.sendTimeout = valueOrDefault(timeout, 0, DEFAULT_SOCKET_TIMEOUT);
223 }
224
225 public int getReceiveTimeout()
226 {
227 return receiveTimeout;
228 }
229
230 public void setReceiveTimeout(int timeout)
231 {
232 this.receiveTimeout = valueOrDefault(timeout, 0, DEFAULT_SOCKET_TIMEOUT);
233 }
234
235
236
237
238 public int getBufferSize()
239 {
240 return sendBufferSize;
241 }
242
243
244
245
246 public void setBufferSize(int bufferSize)
247 {
248 sendBufferSize = valueOrDefault(bufferSize, 1, DEFAULT_BUFFER_SIZE);
249 }
250
251 public int getSendBufferSize()
252 {
253 return sendBufferSize;
254 }
255
256 public void setSendBufferSize(int bufferSize)
257 {
258 sendBufferSize = valueOrDefault(bufferSize, 1, DEFAULT_BUFFER_SIZE);
259 }
260
261 public int getReceiveBufferSize()
262 {
263 return receiveBufferSize;
264 }
265
266 public void setReceiveBufferSize(int bufferSize)
267 {
268 receiveBufferSize = valueOrDefault(bufferSize, 1, DEFAULT_BUFFER_SIZE);
269 }
270
271 public int getReceiveBacklog()
272 {
273 return receiveBacklog;
274 }
275
276 public void setReceiveBacklog(int receiveBacklog)
277 {
278 this.receiveBacklog = valueOrDefault(receiveBacklog, 0, DEFAULT_BACKLOG);
279 }
280
281 public int getSendSocketLinger()
282 {
283 return socketLinger;
284 }
285
286 public void setSendSocketLinger(int soLinger)
287 {
288 this.socketLinger = valueOrDefault(soLinger, 0, INT_VALUE_NOT_SET);
289 }
290
291
292
293
294
295
296 public int getBacklog()
297 {
298 return receiveBacklog;
299 }
300
301
302
303
304
305
306 public void setBacklog(int backlog)
307 {
308 this.receiveBacklog = backlog;
309 }
310
311 public TcpProtocol getTcpProtocol()
312 {
313 return tcpProtocol;
314 }
315
316 public void setTcpProtocol(TcpProtocol tcpProtocol)
317 {
318 this.tcpProtocol = tcpProtocol;
319 }
320
321 public String getTcpProtocolClassName()
322 {
323 return tcpProtocolClassName;
324 }
325
326 public void setTcpProtocolClassName(String protocolClassName)
327 {
328 this.tcpProtocolClassName = protocolClassName;
329 }
330
331 public boolean isRemoteSyncEnabled()
332 {
333 return true;
334 }
335
336 public boolean isKeepAlive()
337 {
338 return keepAlive;
339 }
340
341 public void setKeepAlive(boolean keepAlive)
342 {
343 this.keepAlive = keepAlive;
344 }
345
346 public boolean isSendTcpNoDelay()
347 {
348 return sendTcpNoDelay;
349 }
350
351 public void setSendTcpNoDelay(boolean sendTcpNoDelay)
352 {
353 this.sendTcpNoDelay = sendTcpNoDelay;
354 }
355
356 protected void setSocketFactory(PooledSocketFactory socketFactory)
357 {
358 this.socketFactory = socketFactory;
359 }
360
361 protected PooledSocketFactory getSocketFactory()
362 {
363 return socketFactory;
364 }
365
366 public SimpleServerSocketFactory getServerSocketFactory()
367 {
368 return serverSocketFactory;
369 }
370
371 public void setServerSocketFactory(SimpleServerSocketFactory serverSocketFactory)
372 {
373 this.serverSocketFactory = serverSocketFactory;
374 }
375
376 protected ServerSocket getServerSocket(URI uri) throws IOException
377 {
378 return getServerSocketFactory().createServerSocket(uri, getReceiveBacklog(), isReuseAddress());
379 }
380
381 private static int valueOrDefault(int value, int threshhold, int deflt)
382 {
383 if (value < threshhold)
384 {
385 return deflt;
386 }
387 else
388 {
389 return value;
390 }
391 }
392
393
394
395
396
397
398 public boolean isValidateConnections() {
399 return validateConnections;
400 }
401
402
403
404
405
406 public void setValidateConnections(boolean validateConnections) {
407 this.validateConnections = validateConnections;
408 }
409
410
411
412
413 public Boolean isReuseAddress()
414 {
415 return reuseAddress;
416 }
417
418
419
420
421
422
423 public void setReuseAddress(Boolean reuseAddress)
424 {
425 this.reuseAddress = reuseAddress;
426 }
427
428 }