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