1
2
3
4
5
6
7
8
9
10
11 package org.mule.module.client.remoting;
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.DefaultMuleException;
18 import org.mule.api.MuleContext;
19 import org.mule.api.MuleEvent;
20 import org.mule.api.MuleEventContext;
21 import org.mule.api.MuleException;
22 import org.mule.api.MuleMessage;
23 import org.mule.api.MuleSession;
24 import org.mule.api.config.MuleProperties;
25 import org.mule.api.construct.FlowConstruct;
26 import org.mule.api.endpoint.EndpointBuilder;
27 import org.mule.api.endpoint.EndpointFactory;
28 import org.mule.api.endpoint.ImmutableEndpoint;
29 import org.mule.api.endpoint.InboundEndpoint;
30 import org.mule.api.endpoint.OutboundEndpoint;
31 import org.mule.api.lifecycle.Callable;
32 import org.mule.api.lifecycle.Initialisable;
33 import org.mule.api.lifecycle.InitialisationException;
34 import org.mule.api.processor.MessageProcessor;
35 import org.mule.api.service.Service;
36 import org.mule.api.source.CompositeMessageSource;
37 import org.mule.api.transformer.DataType;
38 import org.mule.api.transformer.TransformerException;
39 import org.mule.api.transformer.wire.WireFormat;
40 import org.mule.component.SimpleCallableJavaComponent;
41 import org.mule.config.i18n.CoreMessages;
42 import org.mule.endpoint.EndpointURIEndpointBuilder;
43 import org.mule.message.DefaultExceptionPayload;
44 import org.mule.model.seda.SedaService;
45 import org.mule.module.client.i18n.ClientMessages;
46 import org.mule.module.client.remoting.notification.RemoteDispatcherNotification;
47 import org.mule.object.SingletonObjectFactory;
48 import org.mule.session.DefaultMuleSession;
49 import org.mule.transport.AbstractConnector;
50 import org.mule.transport.NullPayload;
51 import org.mule.util.MapUtils;
52
53 import java.io.ByteArrayInputStream;
54 import java.lang.reflect.Method;
55 import java.util.LinkedList;
56 import java.util.List;
57 import java.util.Map;
58
59 import org.apache.commons.io.output.ByteArrayOutputStream;
60 import org.apache.commons.logging.Log;
61 import org.apache.commons.logging.LogFactory;
62
63
64
65
66
67
68
69
70 public class RemoteDispatcherComponent implements Callable, Initialisable
71 {
72
73
74
75 protected static final Log logger = LogFactory.getLog(RemoteDispatcherComponent.class);
76
77 public static final String MANAGER_COMPONENT_NAME = "_muleManagerComponent";
78
79
80
81
82 protected WireFormat wireFormat;
83
84 protected String encoding;
85
86 protected int synchronousEventTimeout = 5000;
87
88 protected InboundEndpoint inboundEndpoint;
89
90 protected MuleContext muleContext;
91
92 public RemoteDispatcherComponent(InboundEndpoint inboundEndpoint, WireFormat wireFormat, String encoding, int synchronousEventTimeout)
93 {
94 this.inboundEndpoint = inboundEndpoint;
95 this.wireFormat = wireFormat;
96 this.encoding = encoding;
97 this.synchronousEventTimeout = synchronousEventTimeout;
98 }
99
100 public void initialise() throws InitialisationException
101 {
102 if (inboundEndpoint == null)
103 {
104 throw new InitialisationException(CoreMessages.objectIsNull("inboundEndpoint"), this);
105 }
106 if (wireFormat == null)
107 {
108 throw new InitialisationException(CoreMessages.objectIsNull("wireFormat"), this);
109 }
110 }
111
112 public Object onCall(MuleEventContext context) throws Exception
113 {
114 muleContext = context.getMuleContext();
115 byte[] messageBytes = (byte[]) context.transformMessage(byte[].class);
116 if(new String(messageBytes).equals(ServerHandshake.SERVER_HANDSHAKE_PROPERTY))
117 {
118 return doHandshake(context);
119 }
120
121 Object result;
122 logger.debug("Message received by RemoteDispatcherComponent");
123 ByteArrayInputStream in = new ByteArrayInputStream((byte[]) context.transformMessage(DataType.BYTE_ARRAY_DATA_TYPE));
124 RemoteDispatcherNotification action = (RemoteDispatcherNotification) ((MuleMessage)wireFormat.read(in)).getPayload();
125
126
127
128 if(action.getMessage()!=null)
129 {
130 Method m = action.getMessage().getClass().getDeclaredMethod("initAfterDeserialisation", MuleContext.class);
131 m.setAccessible(true);
132 m.invoke(action.getMessage(), muleContext);
133 }
134
135 if (RemoteDispatcherNotification.ACTION_INVOKE == action.getAction())
136 {
137 result = invokeAction(action, context);
138 }
139 else if (RemoteDispatcherNotification.ACTION_SEND == action.getAction() ||
140 RemoteDispatcherNotification.ACTION_DISPATCH == action.getAction())
141 {
142 result = sendAction(action, context);
143 }
144 else if (RemoteDispatcherNotification.ACTION_RECEIVE == action.getAction())
145 {
146 result = receiveAction(action, context);
147 }
148 else
149 {
150 result = handleException(null, new DefaultMuleException(
151 CoreMessages.eventTypeNotRecognised("RemoteDispatcherNotification:" + action.getAction())));
152 }
153 return result;
154 }
155
156 protected ServerHandshake doHandshake(MuleEventContext context) throws TransformerException
157 {
158 ServerHandshake handshake = new ServerHandshake();
159 handshake.setWireFormatClass(wireFormat.getClass().getName());
160 return handshake;
161 }
162
163 protected Object invokeAction(RemoteDispatcherNotification action, MuleEventContext context) throws MuleException
164 {
165 String destComponent;
166 MuleMessage result = null;
167 String endpoint = action.getResourceIdentifier();
168 if (action.getResourceIdentifier().startsWith("mule:"))
169 {
170 destComponent = endpoint.substring(endpoint.lastIndexOf("/") + 1);
171 }
172 else
173 {
174 destComponent = endpoint;
175 }
176
177 if (destComponent != null)
178 {
179 Object flowConstruct = muleContext.getRegistry().lookupObject(destComponent);
180 if (!(flowConstruct instanceof FlowConstruct && flowConstruct instanceof MessageProcessor))
181 {
182 return handleException(null, new DefaultMuleException(ClientMessages.noSuchFlowConstruct(destComponent)));
183 }
184 MuleSession session = new DefaultMuleSession((FlowConstruct) flowConstruct, muleContext);
185
186
187
188
189 EndpointBuilder builder = new EndpointURIEndpointBuilder(inboundEndpoint);
190
191 builder.setTransformers(new LinkedList());
192 InboundEndpoint ep = muleContext.getEndpointFactory().getInboundEndpoint(builder);
193 MuleEvent event = new DefaultMuleEvent(action.getMessage(), ep, context.getSession());
194 event = RequestContext.setEvent(event);
195
196 if (context.getExchangePattern().hasResponse())
197 {
198 MuleEvent resultEvent = ((MessageProcessor) flowConstruct).process(event);
199 result = resultEvent == null ? null : resultEvent.getMessage();
200 if (result == null)
201 {
202 return null;
203 }
204 else
205 {
206 ByteArrayOutputStream out = new ByteArrayOutputStream();
207 wireFormat.write(out, result, getEncoding());
208 return out.toByteArray();
209 }
210 }
211 else
212 {
213 ((MessageProcessor) flowConstruct).process(event);
214 return null;
215 }
216 }
217 else
218 {
219 return handleException(result, new DefaultMuleException(
220 CoreMessages.couldNotDetermineDestinationComponentFromEndpoint(endpoint)));
221 }
222 }
223
224 protected Object sendAction(RemoteDispatcherNotification action, MuleEventContext context) throws MuleException
225 {
226 MuleMessage result = null;
227 OutboundEndpoint endpoint = null;
228 MuleContext managementContext = context.getMuleContext();
229 try
230 {
231 if (RemoteDispatcherNotification.ACTION_DISPATCH == action.getAction())
232 {
233 endpoint = managementContext.getEndpointFactory().getOutboundEndpoint(
234 action.getResourceIdentifier());
235 context.dispatchEvent(action.getMessage(), endpoint);
236 return null;
237 }
238 else
239 {
240 EndpointFactory endpointFactory = managementContext.getEndpointFactory();
241
242 EndpointBuilder endpointBuilder = endpointFactory.getEndpointBuilder(action.getResourceIdentifier());
243 endpointBuilder.setExchangePattern(MessageExchangePattern.REQUEST_RESPONSE);
244
245 endpoint = managementContext.getEndpointFactory().getOutboundEndpoint(endpointBuilder);
246 result = context.sendEvent(action.getMessage(), endpoint);
247 if (result == null)
248 {
249 return null;
250 }
251 else
252 {
253 ByteArrayOutputStream out = new ByteArrayOutputStream();
254 wireFormat.write(out, result, getEncoding());
255 return out.toByteArray();
256 }
257 }
258 }
259 catch (Exception e)
260 {
261 return handleException(result, e);
262 }
263 }
264
265 protected Object receiveAction(RemoteDispatcherNotification action, MuleEventContext context) throws MuleException
266 {
267 MuleMessage result = null;
268 try
269 {
270 ImmutableEndpoint endpoint = context.getMuleContext().getEndpointFactory()
271 .getOutboundEndpoint(action.getResourceIdentifier());
272
273 long timeout = MapUtils.getLongValue(action.getProperties(),
274 MuleProperties.MULE_EVENT_TIMEOUT_PROPERTY, getSynchronousEventTimeout());
275
276 result = endpoint.getConnector().request(action.getResourceIdentifier(), timeout);
277 if (result != null)
278 {
279
280 List transformers = ((AbstractConnector) endpoint.getConnector()).getDefaultInboundTransformers(endpoint);
281 if (transformers != null)
282 {
283 result.applyTransformers(null, transformers);
284 }
285 ByteArrayOutputStream out = new ByteArrayOutputStream();
286 wireFormat.write(out, result, getEncoding());
287 return out.toByteArray();
288 }
289 else
290 {
291 return null;
292 }
293 }
294 catch (Exception e)
295 {
296 return handleException(result, e);
297 }
298
299 }
300
301
302 public static Service getSerivce(InboundEndpoint endpoint,
303 WireFormat wireFormat,
304 String encoding,
305 int eventTimeout,
306 MuleContext muleContext) throws MuleException
307 {
308 try
309 {
310 Service service = new SedaService(muleContext);
311 service.setName(MANAGER_COMPONENT_NAME);
312 service.setModel(muleContext.getRegistry().lookupSystemModel());
313
314 RemoteDispatcherComponent rdc = new RemoteDispatcherComponent(endpoint, wireFormat, encoding, new Integer(eventTimeout));
315
316 final SimpleCallableJavaComponent component = new SimpleCallableJavaComponent(
317 new SingletonObjectFactory(rdc));
318 component.setMuleContext(muleContext);
319 service.setComponent(component);
320
321
322 if (!(service.getMessageSource() instanceof CompositeMessageSource))
323 {
324 throw new IllegalStateException("Only 'CompositeMessageSource' is supported with RemoteDispatcherService");
325 }
326
327 ((CompositeMessageSource) service.getMessageSource()).addSource(endpoint);
328
329 return service;
330 }
331 catch (Exception e)
332 {
333 throw new InitialisationException(e, null);
334 }
335 }
336
337
338
339
340
341
342
343
344
345
346 protected Object handleException(MuleMessage result, Throwable e)
347 {
348 logger.error("Failed to process admin request: " + e.getMessage(), e);
349 if (result == null)
350 {
351 result = new DefaultMuleMessage(NullPayload.getInstance(), (Map) null, muleContext);
352 }
353 result.setExceptionPayload(new DefaultExceptionPayload(e));
354 try
355 {
356 ByteArrayOutputStream out = new ByteArrayOutputStream();
357 wireFormat.write(out, result, getEncoding());
358 return out.toByteArray();
359 }
360 catch (Exception e1)
361 {
362
363
364 logger.error("Failed to format message, using direct string (details at debug level): " + e1.getMessage());
365 logger.debug(e1.toString(), e1);
366 return e.getMessage();
367 }
368 }
369
370 public WireFormat getWireFormat()
371 {
372 return wireFormat;
373 }
374
375 public void setWireFormat(WireFormat wireFormat)
376 {
377 this.wireFormat = wireFormat;
378 }
379
380 public String getEncoding()
381 {
382 return encoding;
383 }
384
385 public void setEncoding(String encoding)
386 {
387 this.encoding = encoding;
388 }
389
390 public int getSynchronousEventTimeout()
391 {
392 return synchronousEventTimeout;
393 }
394
395 public void setSynchronousEventTimeout(int synchronousEventTimeout)
396 {
397 this.synchronousEventTimeout = synchronousEventTimeout;
398 }
399 }