View Javadoc

1   /*
2    * $Id: UdpMessageReceiver.java 19400 2010-09-07 20:20:09Z mike.schilling $
3    * --------------------------------------------------------------------------------------
4    * Copyright (c) MuleSoft, Inc.  All rights reserved.  http://www.mulesoft.com
5    *
6    * The software in this package is published under the terms of the CPAL v1.0
7    * license, a copy of which has been included with this distribution in the
8    * LICENSE.txt file.
9    */
10  
11  package org.mule.transport.udp;
12  
13  import org.mule.api.MuleEvent;
14  import org.mule.api.MuleException;
15  import org.mule.api.MuleMessage;
16  import org.mule.api.config.MuleProperties;
17  import org.mule.api.construct.FlowConstruct;
18  import org.mule.api.endpoint.InboundEndpoint;
19  import org.mule.api.lifecycle.CreateException;
20  import org.mule.api.lifecycle.Disposable;
21  import org.mule.api.transport.Connector;
22  import org.mule.api.transport.PropertyScope;
23  import org.mule.config.i18n.CoreMessages;
24  import org.mule.transport.AbstractMessageReceiver;
25  import org.mule.transport.ConnectException;
26  import org.mule.transport.udp.i18n.UdpMessages;
27  
28  import java.io.IOException;
29  import java.net.DatagramPacket;
30  import java.net.DatagramSocket;
31  import java.net.InetAddress;
32  import java.net.SocketAddress;
33  import java.net.SocketTimeoutException;
34  import java.net.URI;
35  import java.net.UnknownHostException;
36  import java.util.List;
37  
38  import javax.resource.spi.work.Work;
39  import javax.resource.spi.work.WorkException;
40  import javax.resource.spi.work.WorkManager;
41  
42  import edu.emory.mathcs.backport.java.util.concurrent.atomic.AtomicBoolean;
43  
44  /** <code>UdpMessageReceiver</code> receives UDP message packets. */
45  public class UdpMessageReceiver extends AbstractMessageReceiver implements Work
46  {
47      protected DatagramSocket socket = null;
48      protected InetAddress inetAddress;
49      protected int bufferSize;
50      private URI uri;
51      protected List responseTransformers = null;
52  
53      protected final AtomicBoolean disposing = new AtomicBoolean(false);
54  
55      public UdpMessageReceiver(Connector connector, FlowConstruct flowConstruct, InboundEndpoint endpoint)
56              throws CreateException
57      {
58  
59          super(connector, flowConstruct, endpoint);
60  
61          bufferSize = ((UdpConnector) connector).getReceiveBufferSize();
62  
63          uri = endpoint.getEndpointURI().getUri();
64  
65          try
66          {
67              if (!"null".equalsIgnoreCase(uri.getHost()))
68              {
69                  inetAddress = InetAddress.getByName(uri.getHost());
70              }
71          }
72          catch (UnknownHostException e)
73          {
74              throw new CreateException(UdpMessages.failedToLocateHost(uri), e, this);
75          }
76  
77          responseTransformers = getResponseTransformers();
78      }
79  
80      @Override
81      protected void doConnect() throws Exception
82      {
83          try
84          {
85              socket = ((UdpConnector) connector).getServerSocket(endpoint);
86          }
87          catch (Exception e)
88          {
89              throw new ConnectException(UdpMessages.failedToBind(uri), e, this);
90          }
91  
92          try
93          {
94              getWorkManager().scheduleWork(this, WorkManager.INDEFINITE, null, connector);
95          }
96          catch (WorkException e)
97          {
98              throw new ConnectException(CoreMessages.failedToScheduleWork(), e, this);
99          }
100     }
101 
102     @Override
103     protected void doDisconnect() throws Exception
104     {
105         // this will cause the server thread to quit
106         disposing.set(true);
107         if (socket != null)
108         {
109             socket.close();
110         }
111 
112     }
113 
114     @Override
115     protected void doStart() throws MuleException
116     {
117         // nothing to do
118     }
119 
120     @Override
121     protected void doStop() throws MuleException
122     {
123         // nothing to do
124     }
125 
126     protected List getResponseTransformers()
127     {
128         List transformers = endpoint.getResponseTransformers();
129         if (transformers == null)
130         {
131             return connector.getDefaultResponseTransformers(endpoint);
132         }
133         return transformers;
134     }
135 
136     protected DatagramSocket createSocket(URI uri, InetAddress inetAddress) throws IOException
137     {
138         return new DatagramSocket(uri.getPort(), inetAddress);
139     }
140 
141     /** Obtain the serverSocket */
142     public DatagramSocket getSocket()
143     {
144         return socket;
145     }
146 
147     protected DatagramPacket createPacket()
148     {
149         DatagramPacket packet = new DatagramPacket(new byte[bufferSize], bufferSize);
150 //        if (uri.getPort() > 0)
151 //        {
152 //            packet.setPort(uri.getPort());
153 //        }
154 //        packet.setAddress(inetAddress);
155         return packet;
156     }
157 
158     public void run()
159     {
160         while (!disposing.get())
161         {
162             if (connector.isStarted())
163             {
164 
165                 try
166                 {
167                     DatagramPacket packet = createPacket();
168                     try
169                     {
170                         if (logger.isDebugEnabled())
171                         {
172                             logger.debug("Receiving packet on " + uri);
173                         }
174                         socket.receive(packet);
175 
176                         if (logger.isTraceEnabled())
177                         {
178                             logger.trace("Received packet on: " + uri);
179                         }
180 
181                         Work work = createWork(packet);
182                         try
183                         {
184                             getWorkManager().scheduleWork(work, WorkManager.INDEFINITE, null, connector);
185                         }
186                         catch (WorkException e)
187                         {
188                             logger.error("Udp receiver interrupted: " + e.getMessage(), e);
189                         }
190                     }
191                     catch (SocketTimeoutException e)
192                     {
193                         // ignore
194                     }
195 
196                 }
197                 catch (Exception e)
198                 {
199                     if (!connector.isDisposed() && !disposing.get())
200                     {
201                         logger.debug("Accept failed on socket: " + e, e);
202                         getConnector().getMuleContext().getExceptionListener().handleException(e);
203                     }
204                 }
205             }
206         }
207     }
208 
209     public void release()
210     {
211         dispose();
212     }
213 
214     @Override
215     protected void doDispose()
216     {
217         if (socket != null && !socket.isClosed())
218         {
219             logger.debug("Closing Udp connection: " + uri);
220             socket.close();
221             logger.info("Closed Udp connection: " + uri);
222         }
223     }
224 
225     protected Work createWork(DatagramPacket packet) throws IOException
226     {
227         return new UdpWorker(new DatagramSocket(0), packet);
228     }
229 
230     protected class UdpWorker implements Work, Disposable
231     {
232         private DatagramSocket socket = null;
233         private DatagramPacket packet;
234 
235         public UdpWorker(DatagramSocket socket, DatagramPacket packet)
236         {
237             this.socket = socket;
238             this.packet = packet;
239         }
240 
241         public void release()
242         {
243             dispose();
244         }
245 
246         public void dispose()
247         {
248             if (socket != null && !socket.isClosed())
249             {
250                 try
251                 {
252                     socket.close();
253                 }
254                 catch (Exception e)
255                 {
256                     logger.error("Socket close failed", e);
257                 }
258             }
259             socket = null;
260         }
261 
262         /** Accept requests from a given Udp address */
263         public void run()
264         {
265             MuleMessage returnMessage = null;
266             try
267             {
268                 MuleMessage message = createMuleMessage(packet, endpoint.getEncoding());
269                 final SocketAddress clientAddress = socket.getRemoteSocketAddress();
270                 if (clientAddress != null)
271                 {
272                     message.setProperty(MuleProperties.MULE_REMOTE_CLIENT_ADDRESS, clientAddress, PropertyScope.INBOUND);
273                 }
274                 MuleEvent event = routeMessage(message);
275                 returnMessage = event == null ? null : event.getMessage();
276 
277                 if (returnMessage != null)
278                 {
279                     byte[] data;
280                     if (responseTransformers != null)
281                     {
282                         returnMessage.applyTransformers(event, responseTransformers);
283                         Object response = returnMessage.getPayload();
284                         if (response instanceof byte[])
285                         {
286                             data = (byte[]) response;
287                         }
288                         else
289                         {
290                             data = response.toString().getBytes();
291                         }
292                     }
293                     else
294                     {
295                         data = returnMessage.getPayloadAsBytes();
296                     }
297                     DatagramPacket result = new DatagramPacket(data, data.length, packet.getAddress(),
298                             packet.getPort());
299                     socket.send(result);
300                 }
301             }
302             catch (Exception e)
303             {
304                 if (!disposing.get())
305                 {
306                     getConnector().getMuleContext().getExceptionListener().handleException(e);
307                 }
308             }
309             finally
310             {
311                 dispose();
312             }
313         }
314     }
315 }