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