1
2
3
4
5
6
7
8
9
10
11 package org.mule.module.client;
12
13 import org.mule.DefaultMuleEvent;
14 import org.mule.DefaultMuleMessage;
15 import org.mule.MessageExchangePattern;
16 import org.mule.RequestContext;
17 import org.mule.api.FutureMessageResult;
18 import org.mule.api.MuleContext;
19 import org.mule.api.MuleEvent;
20 import org.mule.api.MuleException;
21 import org.mule.api.MuleMessage;
22 import org.mule.api.MuleSession;
23 import org.mule.api.config.MuleProperties;
24 import org.mule.api.endpoint.EndpointBuilder;
25 import org.mule.api.endpoint.EndpointFactory;
26 import org.mule.api.endpoint.ImmutableEndpoint;
27 import org.mule.api.endpoint.OutboundEndpoint;
28 import org.mule.api.lifecycle.Disposable;
29 import org.mule.api.security.Credentials;
30 import org.mule.api.transformer.wire.WireFormat;
31 import org.mule.api.transport.DispatchException;
32 import org.mule.client.DefaultLocalMuleClient.MuleClientFlowConstruct;
33 import org.mule.module.client.i18n.ClientMessages;
34 import org.mule.module.client.remoting.RemoteDispatcherException;
35 import org.mule.module.client.remoting.ServerHandshake;
36 import org.mule.module.client.remoting.UnsupportedWireFormatException;
37 import org.mule.module.client.remoting.notification.RemoteDispatcherNotification;
38 import org.mule.security.MuleCredentials;
39 import org.mule.session.DefaultMuleSession;
40 import org.mule.transformer.TransformerUtils;
41 import org.mule.transport.NullPayload;
42 import org.mule.util.ClassUtils;
43 import org.mule.util.IOUtils;
44
45 import java.io.ByteArrayInputStream;
46 import java.io.ByteArrayOutputStream;
47 import java.io.InputStream;
48 import java.util.Map;
49
50 import edu.emory.mathcs.backport.java.util.concurrent.Callable;
51 import edu.emory.mathcs.backport.java.util.concurrent.Executor;
52
53 import org.apache.commons.lang.SerializationUtils;
54 import org.apache.commons.logging.Log;
55 import org.apache.commons.logging.LogFactory;
56
57
58
59
60
61
62
63 public class RemoteDispatcher implements Disposable
64 {
65
66
67
68
69 protected static final Log logger = LogFactory.getLog(RemoteDispatcher.class);
70
71
72
73
74 private OutboundEndpoint asyncServerEndpoint;
75 private OutboundEndpoint syncServerEndpoint;
76 private Credentials credentials = null;
77 private MuleContext muleContext;
78
79
80
81
82 private Executor asyncExecutor;
83
84
85
86
87 private WireFormat wireFormat;
88
89 protected RemoteDispatcher(String endpoint, Credentials credentials, MuleContext muleContext) throws MuleException
90 {
91 this(endpoint, muleContext);
92 this.credentials = credentials;
93 }
94
95 protected RemoteDispatcher(String endpoint, MuleContext muleContext) throws MuleException
96 {
97 this.muleContext = muleContext;
98 EndpointFactory endpointFactory = muleContext.getRegistry().lookupEndpointFactory();
99 asyncServerEndpoint = endpointFactory.getOutboundEndpoint(endpoint);
100
101 EndpointBuilder endpointBuilder = endpointFactory.getEndpointBuilder(endpoint);
102 endpointBuilder.setExchangePattern(MessageExchangePattern.REQUEST_RESPONSE);
103 syncServerEndpoint = muleContext.getEndpointFactory().getOutboundEndpoint(
104 endpointBuilder);
105
106 wireFormat = requestWireFormat();
107 }
108
109 protected WireFormat requestWireFormat() throws MuleException
110 {
111 MuleMessage msg = new DefaultMuleMessage(ServerHandshake.SERVER_HANDSHAKE_PROPERTY, muleContext);
112 MuleMessage result = null;
113
114 MuleEvent resultEvent = syncServerEndpoint.process(new DefaultMuleEvent(msg, syncServerEndpoint,
115 new DefaultMuleSession(new MuleClientFlowConstruct(muleContext), muleContext)));
116 if (resultEvent != null)
117 {
118 result = resultEvent.getMessage();
119 }
120
121 if(result==null)
122 {
123 throw new RemoteDispatcherException(ClientMessages.failedToDispatchActionNoResponseFromServer("request wire format", 5000));
124 }
125
126 ServerHandshake handshake;
127 try
128 {
129 ByteArrayInputStream in = new ByteArrayInputStream(result.getPayloadAsBytes());
130 handshake = (ServerHandshake) SerializationUtils.deserialize(in);
131 }
132 catch (Exception e)
133 {
134 throw new RemoteDispatcherException(ClientMessages.failedToDeserializeHandshakeFromServer(), e);
135 }
136
137 try
138 {
139 WireFormat wf = (WireFormat)ClassUtils.instanciateClass(handshake.getWireFormatClass(),
140 ClassUtils.NO_ARGS, getClass());
141
142 wf.setMuleContext(muleContext);
143 return wf;
144 }
145 catch (Exception e)
146 {
147 throw new UnsupportedWireFormatException(handshake.getWireFormatClass(), e);
148 }
149 }
150
151 protected void setExecutor(Executor e)
152 {
153 this.asyncExecutor = e;
154 }
155
156
157
158
159
160
161
162
163
164
165
166
167
168 public void dispatchToRemoteComponent(String component, Object payload, Map messageProperties)
169 throws MuleException
170 {
171 doToRemoteComponent(component, payload, messageProperties, false);
172 }
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187 public MuleMessage sendToRemoteComponent(String component, Object payload, Map messageProperties)
188 throws MuleException
189 {
190 return doToRemoteComponent(component, payload, messageProperties, true);
191 }
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210 public FutureMessageResult sendAsyncToRemoteComponent(final String component,
211 String transformers,
212 final Object payload,
213 final Map messageProperties) throws MuleException
214 {
215 Callable callable = new Callable()
216 {
217 public Object call() throws Exception
218 {
219 return doToRemoteComponent(component, payload, messageProperties, true);
220 }
221 };
222
223 FutureMessageResult result = new FutureMessageResult(callable, muleContext);
224
225 if (asyncExecutor != null)
226 {
227 result.setExecutor(asyncExecutor);
228 }
229
230 if (transformers != null)
231 {
232 result.setTransformers(TransformerUtils.getTransformers(transformers, muleContext));
233 }
234
235 result.execute();
236 return result;
237 }
238
239 public MuleMessage sendRemote(String endpoint, Object payload, Map messageProperties, int timeout)
240 throws MuleException
241 {
242 return doToRemote(endpoint, payload, messageProperties, true, timeout);
243 }
244
245 public MuleMessage sendRemote(String endpoint, Object payload, Map messageProperties) throws MuleException
246 {
247 return doToRemote(endpoint, payload, messageProperties, true,
248 muleContext.getConfiguration().getDefaultResponseTimeout());
249 }
250
251 public void dispatchRemote(String endpoint, Object payload, Map messageProperties) throws MuleException
252 {
253 doToRemote(endpoint, payload, messageProperties, false, -1);
254 }
255
256 public FutureMessageResult sendAsyncRemote(final String endpoint,
257 final Object payload,
258 final Map messageProperties) throws MuleException
259 {
260 Callable callable = new Callable()
261 {
262 public Object call() throws Exception
263 {
264 return doToRemote(endpoint, payload, messageProperties, true, -1);
265 }
266 };
267
268 FutureMessageResult result = new FutureMessageResult(callable, muleContext);
269
270 if (asyncExecutor != null)
271 {
272 result.setExecutor(asyncExecutor);
273 }
274
275 result.execute();
276 return result;
277 }
278
279 public MuleMessage receiveRemote(String endpoint, int timeout) throws MuleException
280 {
281 RemoteDispatcherNotification action = new RemoteDispatcherNotification(null, RemoteDispatcherNotification.ACTION_RECEIVE, endpoint);
282 action.setProperty(MuleProperties.MULE_REMOTE_SYNC_PROPERTY, "true");
283 if (timeout != MuleEvent.TIMEOUT_NOT_SET_VALUE)
284 {
285 action.setProperty(MuleProperties.MULE_EVENT_TIMEOUT_PROPERTY, new Long(timeout));
286 }
287 return dispatchAction(action, true, timeout);
288 }
289
290 public FutureMessageResult asyncReceiveRemote(final String endpoint, final int timeout)
291 throws MuleException
292 {
293 Callable callable = new Callable()
294 {
295 public Object call() throws Exception
296 {
297 return receiveRemote(endpoint, timeout);
298 }
299 };
300
301 FutureMessageResult result = new FutureMessageResult(callable, muleContext);
302
303 if (asyncExecutor != null)
304 {
305 result.setExecutor(asyncExecutor);
306 }
307
308 result.execute();
309 return result;
310 }
311
312 protected MuleMessage doToRemoteComponent(String component,
313 Object payload,
314 Map messageProperties,
315 boolean synchronous) throws MuleException
316 {
317 MuleMessage message = new DefaultMuleMessage(payload, messageProperties, muleContext);
318 message.setOutboundProperty(MuleProperties.MULE_REMOTE_SYNC_PROPERTY, synchronous);
319 setCredentials(message);
320 RemoteDispatcherNotification action = new RemoteDispatcherNotification(message, RemoteDispatcherNotification.ACTION_INVOKE,
321 "mule://" + component);
322 return dispatchAction(action, synchronous,
323 muleContext.getConfiguration().getDefaultResponseTimeout());
324 }
325
326 protected MuleMessage doToRemote(String endpoint,
327 Object payload,
328 Map messageProperties,
329 boolean synchronous,
330 int timeout) throws MuleException
331 {
332 MuleMessage message = new DefaultMuleMessage(payload, messageProperties, muleContext);
333 message.setOutboundProperty(MuleProperties.MULE_REMOTE_SYNC_PROPERTY, String.valueOf(synchronous));
334 setCredentials(message);
335 RemoteDispatcherNotification action = new RemoteDispatcherNotification(message, (synchronous
336 ? RemoteDispatcherNotification.ACTION_SEND : RemoteDispatcherNotification.ACTION_DISPATCH), endpoint);
337
338 return dispatchAction(action, synchronous, timeout);
339 }
340
341 protected MuleMessage dispatchAction(RemoteDispatcherNotification action, boolean synchronous, int timeout)
342 throws MuleException
343 {
344 OutboundEndpoint serverEndpoint;
345 if (synchronous)
346 {
347 serverEndpoint = syncServerEndpoint;
348 }
349 else
350 {
351 serverEndpoint = asyncServerEndpoint;
352 }
353 MuleMessage serializeMessage = new DefaultMuleMessage(action, muleContext);
354
355 updateContext(serializeMessage, serverEndpoint, synchronous);
356
357 ByteArrayOutputStream out = new ByteArrayOutputStream();
358 wireFormat.write(out, serializeMessage, serverEndpoint.getEncoding());
359 byte[] payload = out.toByteArray();
360
361 MuleMessage message = action.getMessage();
362
363 if (message == null)
364 {
365 message = new DefaultMuleMessage(payload, muleContext);
366 }
367 else
368 {
369 message = new DefaultMuleMessage(payload, message, muleContext);
370 }
371
372 message.addProperties(action.getProperties());
373 MuleSession session = new DefaultMuleSession(muleContext);
374
375 MuleEvent event = new DefaultMuleEvent(message, serverEndpoint, session);
376 event.setTimeout(timeout);
377 if (logger.isDebugEnabled())
378 {
379 logger.debug("MuleClient sending remote call to: " + action.getResourceIdentifier() + ". At "
380 + serverEndpoint.toString() + " . Event is: " + event);
381 }
382
383
384 MuleMessage result = null;
385
386 try
387 {
388 MuleEvent resultEvent = serverEndpoint.process(event);
389 if (resultEvent != null)
390 {
391 result = resultEvent.getMessage();
392 }
393
394 if (result != null && result.getPayload() != null)
395 {
396 if (result.getPayload() instanceof NullPayload)
397 {
398 return null;
399 }
400
401 Object response;
402 if (result.getPayload() instanceof InputStream)
403 {
404 byte[] b = IOUtils.toByteArray((InputStream)result.getPayload());
405 if(b.length==0) return null;
406 ByteArrayInputStream in = new ByteArrayInputStream(b);
407 response = wireFormat.read(in);
408 }
409 else
410 {
411 ByteArrayInputStream in = new ByteArrayInputStream(result.getPayloadAsBytes());
412 response = wireFormat.read(in);
413 }
414
415 if (response instanceof RemoteDispatcherNotification)
416 {
417 response = ((RemoteDispatcherNotification)response).getMessage();
418 }
419 return (MuleMessage)response;
420 }
421 }
422 catch (Exception e)
423 {
424 throw new DispatchException(event, serverEndpoint, e);
425 }
426
427 if (logger.isDebugEnabled())
428 {
429 logger.debug("Result of MuleClient remote call is: "
430 + (result == null ? "null" : result.getPayload()));
431 }
432
433 return result;
434 }
435
436 public void dispose()
437 {
438
439 }
440
441 protected void setCredentials(MuleMessage message)
442 {
443 if (credentials != null)
444 {
445 message.setOutboundProperty(MuleProperties.MULE_USER_PROPERTY, MuleCredentials.createHeader(
446 credentials.getUsername(), credentials.getPassword()));
447 }
448 }
449
450 public WireFormat getWireFormat()
451 {
452 return wireFormat;
453 }
454
455 public void setWireFormat(WireFormat wireFormat)
456 {
457 this.wireFormat = wireFormat;
458 }
459
460 protected void updateContext(MuleMessage message, ImmutableEndpoint endpoint, boolean synchronous)
461 throws MuleException
462 {
463 RequestContext.setEvent(new DefaultMuleEvent(message, endpoint, new DefaultMuleSession(muleContext)));
464 }
465 }