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.MuleMessage;
15 import org.mule.impl.ResponseOutputStream;
16 import org.mule.impl.model.streaming.CloseCountDownInputStream;
17 import org.mule.impl.model.streaming.CloseCountDownOutputStream;
18 import org.mule.providers.AbstractMessageReceiver;
19 import org.mule.providers.AbstractReceiverResourceWorker;
20 import org.mule.providers.ConnectException;
21 import org.mule.providers.tcp.i18n.TcpMessages;
22 import org.mule.umo.TransactionException;
23 import org.mule.umo.UMOComponent;
24 import org.mule.umo.UMOException;
25 import org.mule.umo.UMOMessage;
26 import org.mule.umo.UMOTransaction;
27 import org.mule.umo.endpoint.UMOEndpoint;
28 import org.mule.umo.lifecycle.Disposable;
29 import org.mule.umo.lifecycle.DisposeException;
30 import org.mule.umo.lifecycle.InitialisationException;
31 import org.mule.umo.provider.UMOConnector;
32 import org.mule.umo.provider.UMOMessageAdapter;
33
34 import edu.emory.mathcs.backport.java.util.concurrent.CountDownLatch;
35 import edu.emory.mathcs.backport.java.util.concurrent.atomic.AtomicBoolean;
36
37 import java.io.BufferedInputStream;
38 import java.io.BufferedOutputStream;
39 import java.io.DataInputStream;
40 import java.io.DataOutputStream;
41 import java.io.IOException;
42 import java.io.InputStream;
43 import java.io.OutputStream;
44 import java.net.ServerSocket;
45 import java.net.Socket;
46 import java.net.SocketAddress;
47 import java.net.SocketTimeoutException;
48 import java.net.URI;
49 import java.util.Iterator;
50 import java.util.List;
51
52 import javax.resource.spi.work.Work;
53 import javax.resource.spi.work.WorkException;
54 import javax.resource.spi.work.WorkManager;
55
56
57
58
59
60 public class TcpMessageReceiver extends AbstractMessageReceiver implements Work
61 {
62 private ServerSocket serverSocket = null;
63
64 public TcpMessageReceiver(UMOConnector connector, UMOComponent component, UMOEndpoint endpoint)
65 throws InitialisationException
66 {
67 super(connector, component, endpoint);
68 }
69
70 protected void doConnect() throws ConnectException
71 {
72 disposing.set(false);
73
74 URI uri = endpoint.getEndpointURI().getUri();
75
76 try
77 {
78 serverSocket = ((TcpConnector) connector).getServerSocket(uri);
79 }
80 catch (Exception e)
81 {
82 throw new org.mule.providers.ConnectException(TcpMessages.failedToBindToUri(uri), e, this);
83 }
84
85 try
86 {
87 getWorkManager().scheduleWork(this, WorkManager.INDEFINITE, null, connector);
88 }
89 catch (WorkException e)
90 {
91 throw new ConnectException(CoreMessages.failedToScheduleWork(), e, this);
92 }
93 }
94
95 protected void doDisconnect() throws ConnectException
96 {
97
98 disposing.set(true);
99
100 try
101 {
102 if (serverSocket != null)
103 {
104 if (logger.isDebugEnabled())
105 {
106 logger.debug("Closing: " + serverSocket);
107 }
108 serverSocket.close();
109 }
110 }
111 catch (IOException e)
112 {
113 logger.warn("Failed to close server socket: " + e.getMessage(), e);
114 }
115 }
116
117 protected void doStart() throws UMOException
118 {
119
120 }
121
122 protected void doStop() throws UMOException
123 {
124
125 }
126
127
128
129
130
131
132 public ServerSocket getServerSocket()
133 {
134 return serverSocket;
135 }
136
137 public void run()
138 {
139 while (!disposing.get())
140 {
141 if (connector.isStarted() && !disposing.get())
142 {
143 Socket socket = null;
144 try
145 {
146 socket = serverSocket.accept();
147
148 if (logger.isTraceEnabled())
149 {
150 logger.trace("Accepted: " + serverSocket);
151 }
152 }
153 catch (java.io.InterruptedIOException iie)
154 {
155 if (logger.isDebugEnabled())
156 {
157 logger.debug("Interupted IO doing serverSocket.accept: " + iie.getMessage());
158 }
159 }
160 catch (Exception e)
161 {
162 if (!connector.isDisposed() && !disposing.get())
163 {
164 logger.warn("Accept failed on socket: " + e, e);
165 handleException(new ConnectException(e, this));
166 }
167 }
168
169 if (socket != null)
170 {
171 try
172 {
173 Work work = createWork(socket);
174 try
175 {
176 getWorkManager().scheduleWork(work, WorkManager.INDEFINITE, null, connector);
177 }
178 catch (WorkException e)
179 {
180 logger.error("Tcp Server receiver Work was not processed: " + e.getMessage(), e);
181 }
182 }
183 catch (IOException e)
184 {
185 handleException(e);
186 }
187 }
188 }
189 }
190 }
191
192 public void release()
193 {
194
195 }
196
197 protected void doDispose()
198 {
199 try
200 {
201 if (serverSocket != null && !serverSocket.isClosed())
202 {
203 if (logger.isDebugEnabled())
204 {
205 logger.debug("Closing: " + serverSocket);
206 }
207 serverSocket.close();
208 }
209 serverSocket = null;
210 }
211 catch (Exception e)
212 {
213 logger.error(new DisposeException(TcpMessages.failedToCloseSocket(), e));
214 }
215 logger.info("Closed Tcp port");
216 }
217
218 protected Work createWork(Socket socket) throws IOException
219 {
220 if (endpoint.isStreaming())
221 {
222 return new TcpStreamWorker(socket, this);
223 }
224 else
225 {
226 return new TcpWorker(socket, this);
227 }
228 }
229
230 protected class TcpWorker extends AbstractReceiverResourceWorker implements Disposable
231 {
232 protected Socket socket = null;
233 protected InputStream dataIn;
234 protected OutputStream dataOut;
235 protected AtomicBoolean closed = new AtomicBoolean(false);
236 protected TcpProtocol protocol;
237
238 public TcpWorker(Object resource, AbstractMessageReceiver receiver) throws IOException
239 {
240 super(resource, receiver, new ResponseOutputStream((Socket) resource));
241
242 this.socket = (Socket) resource;
243
244 final TcpConnector tcpConnector = ((TcpConnector) connector);
245 this.protocol = tcpConnector.getTcpProtocol();
246
247 try
248 {
249
250
251 if (tcpConnector.getReceiveBufferSize() != UMOConnector.INT_VALUE_NOT_SET
252 && socket.getReceiveBufferSize() != tcpConnector.getReceiveBufferSize())
253 {
254 socket.setReceiveBufferSize(tcpConnector.getReceiveBufferSize());
255 }
256 if (tcpConnector.getSendBufferSize() != UMOConnector.INT_VALUE_NOT_SET
257 && socket.getSendBufferSize() != tcpConnector.getSendBufferSize())
258 {
259 socket.setSendBufferSize(tcpConnector.getSendBufferSize());
260 }
261 if (tcpConnector.getReceiveTimeout() != UMOConnector.INT_VALUE_NOT_SET
262 && socket.getSoTimeout() != tcpConnector.getReceiveTimeout())
263 {
264 socket.setSoTimeout(tcpConnector.getReceiveTimeout());
265 }
266
267 socket.setTcpNoDelay(tcpConnector.isSendTcpNoDelay());
268 socket.setKeepAlive(tcpConnector.isKeepAlive());
269
270 dataIn = new DataInputStream(new BufferedInputStream(socket.getInputStream()));
271 dataOut = new DataOutputStream(new BufferedOutputStream(socket.getOutputStream()));
272
273 }
274 catch (IOException e)
275 {
276 logger.error("Failed to set Socket properties: " + e.getMessage(), e);
277 }
278
279 }
280
281 public void dispose()
282 {
283 release();
284 }
285
286 public void release()
287 {
288 closed.set(true);
289 try
290 {
291 if (socket != null && !socket.isClosed())
292 {
293 if (logger.isDebugEnabled())
294 {
295
296
297 final SocketAddress socketAddress = socket.getLocalSocketAddress();
298 if (socketAddress == null)
299 {
300 logger.debug("Listener has already been closed by other process.");
301 }
302 else
303 {
304 logger.debug("Closing listener: " + socketAddress);
305 }
306 }
307 socket.close();
308 }
309 }
310 catch (IOException e)
311 {
312 logger.warn("Socket close failed with: " + e);
313 }
314 }
315
316 protected void bindTransaction(UMOTransaction tx) throws TransactionException
317 {
318
319 }
320
321 protected Object getNextMessage(Object resource) throws Exception
322 {
323 while (!socket.isClosed() && !disposing.get())
324 {
325 try
326 {
327 Object readMsg = protocol.read(dataIn);
328 if (readMsg == null)
329 {
330 return null;
331 }
332 else
333 {
334 return readMsg;
335 }
336 }
337 catch (SocketTimeoutException e)
338 {
339 if (!socket.getKeepAlive())
340 {
341 return null;
342 }
343 }
344 }
345 return null;
346 }
347
348
349 protected void handleResults(List messages) throws Exception
350 {
351 for (Iterator iterator = messages.iterator(); iterator.hasNext();)
352 {
353 Object o = iterator.next();
354 protocol.write(dataOut, o);
355 dataOut.flush();
356 }
357 }
358
359 protected Object processData(Object data) throws Exception
360 {
361 UMOMessageAdapter adapter = connector.getMessageAdapter(data);
362 OutputStream os = new ResponseOutputStream(socket);
363 UMOMessage returnMessage = routeMessage(new MuleMessage(adapter), endpoint.isSynchronous(), os);
364 if (returnMessage != null)
365 {
366 return returnMessage;
367 }
368 else
369 {
370 return null;
371 }
372 }
373
374 }
375
376 protected class TcpStreamWorker extends TcpWorker
377 {
378
379 private CountDownLatch latch;
380
381 public TcpStreamWorker(Socket socket, TcpMessageReceiver receiver) throws IOException
382 {
383 super(socket, receiver);
384 }
385
386
387 protected Object getNextMessage(Object resource) throws Exception
388 {
389
390 if (endpoint.isSynchronous())
391 {
392 latch = new CountDownLatch(2);
393 dataOut = new CloseCountDownOutputStream(dataOut, latch);
394 }
395 else
396 {
397 latch = new CountDownLatch(2);
398 }
399 dataIn = new CloseCountDownInputStream(dataIn, latch);
400
401 UMOMessageAdapter adapter = connector.getStreamMessageAdapter(dataIn, dataOut);
402 return adapter;
403
404 }
405
406
407 protected void handleResults(List messages) throws Exception
408 {
409 latch.await();
410 }
411 }
412
413 }