View Javadoc

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