1
2
3
4
5
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
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
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
110 }
111
112 @Override
113 protected void doStop() throws MuleException
114 {
115
116 }
117
118 protected DatagramSocket createSocket(URI uri, InetAddress inetAddress) throws IOException
119 {
120 return new DatagramSocket(uri.getPort(), inetAddress);
121 }
122
123
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
133
134
135
136
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
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
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 }