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