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