1
2
3
4
5
6
7
8
9
10
11 package org.mule.transport;
12
13 import org.mule.DefaultMuleEvent;
14 import org.mule.DefaultMuleSession;
15 import org.mule.NullSessionHandler;
16 import org.mule.OptimizedRequestContext;
17 import org.mule.RequestContext;
18 import org.mule.ResponseOutputStream;
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.context.WorkManager;
25 import org.mule.api.endpoint.EndpointURI;
26 import org.mule.api.endpoint.InboundEndpoint;
27 import org.mule.api.lifecycle.CreateException;
28 import org.mule.api.lifecycle.InitialisationException;
29 import org.mule.api.security.SecurityException;
30 import org.mule.api.service.Service;
31 import org.mule.api.transaction.Transaction;
32 import org.mule.api.transport.ConnectionStrategy;
33 import org.mule.api.transport.Connector;
34 import org.mule.api.transport.InternalMessageListener;
35 import org.mule.api.transport.MessageReceiver;
36 import org.mule.config.ExceptionHelper;
37 import org.mule.config.i18n.CoreMessages;
38 import org.mule.context.notification.ConnectionNotification;
39 import org.mule.context.notification.EndpointMessageNotification;
40 import org.mule.context.notification.SecurityNotification;
41 import org.mule.transaction.TransactionCoordination;
42 import org.mule.util.ClassUtils;
43 import org.mule.util.StringMessageUtils;
44 import org.mule.util.concurrent.WaitableBoolean;
45
46 import java.io.OutputStream;
47
48 import edu.emory.mathcs.backport.java.util.concurrent.atomic.AtomicBoolean;
49
50 import org.apache.commons.logging.Log;
51 import org.apache.commons.logging.LogFactory;
52
53
54
55
56
57
58 public abstract class AbstractMessageReceiver implements MessageReceiver
59 {
60
61 protected final Log logger = LogFactory.getLog(getClass());
62
63
64 protected Service service = null;
65
66
67 protected InboundEndpoint endpoint = null;
68
69 private InternalMessageListener listener;
70
71
72 protected AbstractConnector connector = null;
73
74 protected final AtomicBoolean disposing = new AtomicBoolean(false);
75
76 protected final WaitableBoolean connected = new WaitableBoolean(false);
77
78 protected final WaitableBoolean stopped = new WaitableBoolean(true);
79
80 protected final AtomicBoolean connecting = new AtomicBoolean(false);
81
82
83
84
85
86 protected String receiverKey = null;
87
88
89
90
91
92
93
94 private EndpointURI endpointUri;
95
96 private WorkManager workManager;
97
98 protected ConnectionStrategy connectionStrategy;
99
100 protected boolean responseEndpoint = false;
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118 public AbstractMessageReceiver(Connector connector, Service service, InboundEndpoint endpoint)
119 throws CreateException
120 {
121 setConnector(connector);
122 setService(service);
123 setEndpoint(endpoint);
124 if (service.getResponseRouter() != null && service.getResponseRouter().getEndpoints().contains(endpoint))
125 {
126 responseEndpoint = true;
127 }
128 }
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144 public void initialise() throws InitialisationException
145 {
146 listener = new DefaultInternalMessageListener();
147 endpointUri = endpoint.getEndpointURI();
148
149 try
150 {
151 workManager = this.connector.getReceiverWorkManager("receiver");
152 }
153 catch (MuleException e)
154 {
155 throw new InitialisationException(e, this);
156 }
157
158 connectionStrategy = this.endpoint.getConnectionStrategy();
159 doInitialise();
160 }
161
162
163
164
165
166
167 public InboundEndpoint getEndpoint()
168 {
169 return endpoint;
170 }
171
172
173
174
175
176
177 public void handleException(Exception exception)
178 {
179 if (exception instanceof ConnectException)
180 {
181 logger.info("Exception caught is a ConnectException, disconnecting receiver and invoking ReconnectStrategy");
182 try
183 {
184 disconnect();
185 }
186 catch (Exception e)
187 {
188 connector.getExceptionListener().exceptionThrown(e);
189 }
190 }
191 connector.getExceptionListener().exceptionThrown(exception);
192 if (exception instanceof ConnectException)
193 {
194 try
195 {
196 logger.warn("Reconnecting after exception: " + exception.getMessage(), exception);
197 connectionStrategy.connect(this);
198 }
199 catch (MuleException e)
200 {
201 connector.getExceptionListener().exceptionThrown(e);
202 }
203 }
204 }
205
206
207
208
209
210
211
212
213 protected void setExceptionDetails(MuleMessage message, Throwable exception)
214 {
215 String propName = ExceptionHelper.getErrorCodePropertyName(connector.getProtocol());
216
217
218 if (propName != null)
219 {
220 String code = ExceptionHelper.getErrorMapping(connector.getProtocol(), exception.getClass());
221 if (logger.isDebugEnabled())
222 {
223 logger.debug("Setting error code for: " + connector.getProtocol() + ", " + propName + "="
224 + code);
225 }
226 message.setProperty(propName, code);
227 }
228 }
229
230 public Connector getConnector()
231 {
232 return connector;
233 }
234
235 public void setConnector(Connector connector)
236 {
237 if (connector != null)
238 {
239 if (connector instanceof AbstractConnector)
240 {
241 this.connector = (AbstractConnector) connector;
242 }
243 else
244 {
245 throw new IllegalArgumentException(CoreMessages.propertyIsNotSupportedType(
246 "connector", AbstractConnector.class, connector.getClass()).getMessage());
247 }
248 }
249 else
250 {
251 throw new IllegalArgumentException(CoreMessages.objectIsNull("connector").getMessage());
252 }
253 }
254
255 public Service getService()
256 {
257 return service;
258 }
259
260 public final MuleMessage routeMessage(MuleMessage message) throws MuleException
261 {
262 return routeMessage(message, (endpoint.isSynchronous() || TransactionCoordination.getInstance()
263 .getTransaction() != null));
264 }
265
266 public final MuleMessage routeMessage(MuleMessage message, boolean synchronous) throws MuleException
267 {
268 Transaction tx = TransactionCoordination.getInstance().getTransaction();
269 return routeMessage(message, tx, tx != null || synchronous, null);
270 }
271
272 public final MuleMessage routeMessage(MuleMessage message, Transaction trans, boolean synchronous)
273 throws MuleException
274 {
275 return routeMessage(message, trans, synchronous, null);
276 }
277
278 public final MuleMessage routeMessage(MuleMessage message, OutputStream outputStream) throws MuleException
279 {
280 return routeMessage(message, endpoint.isSynchronous(), outputStream);
281 }
282
283 public final MuleMessage routeMessage(MuleMessage message, boolean synchronous, OutputStream outputStream)
284 throws MuleException
285 {
286 Transaction tx = TransactionCoordination.getInstance().getTransaction();
287 return routeMessage(message, tx, tx != null || synchronous, outputStream);
288 }
289
290 public final MuleMessage routeMessage(MuleMessage message,
291 Transaction trans,
292 boolean synchronous,
293 OutputStream outputStream) throws MuleException
294 {
295
296 if (connector.isEnableMessageEvents())
297 {
298 connector.fireNotification(
299 new EndpointMessageNotification(message, endpoint, service.getName(), EndpointMessageNotification.MESSAGE_RECEIVED));
300 }
301
302
303 if (endpoint.isRemoteSync())
304 {
305 message.setBooleanProperty(MuleProperties.MULE_REMOTE_SYNC_PROPERTY, true);
306 }
307
308 if (message.getBooleanProperty(MuleProperties.MULE_REMOTE_SYNC_PROPERTY, false))
309 {
310 synchronous = true;
311 }
312
313 if (logger.isDebugEnabled())
314 {
315 logger.debug("Message Received from: " + endpoint.getEndpointURI());
316 }
317 if (logger.isTraceEnabled())
318 {
319 try
320 {
321 logger.trace("Message Payload: \n"
322 + StringMessageUtils.truncate(StringMessageUtils.toString(message.getPayload()),
323 200, false));
324 }
325 catch (Exception e)
326 {
327
328 }
329 }
330
331
332 if (endpoint.getFilter() != null)
333 {
334 if (!endpoint.getFilter().accept(message))
335 {
336
337
338
339
340 message = handleUnacceptedFilter(message);
341 RequestContext.setEvent(new DefaultMuleEvent(message, endpoint,
342 new DefaultMuleSession(message, new NullSessionHandler(), connector.getMuleContext()), synchronous));
343 return message;
344 }
345 }
346 return listener.onMessage(message, trans, synchronous, outputStream);
347 }
348
349 protected MuleMessage handleUnacceptedFilter(MuleMessage message)
350 {
351 String messageId;
352 messageId = message.getUniqueId();
353
354 if (logger.isDebugEnabled())
355 {
356 logger.debug("Message " + messageId + " failed to pass filter on endpoint: " + endpoint
357 + ". Message is being ignored");
358 }
359
360 return message;
361 }
362
363
364
365
366
367
368 public void setEndpoint(InboundEndpoint endpoint)
369 {
370 if (endpoint == null)
371 {
372 throw new IllegalArgumentException("Endpoint cannot be null");
373 }
374 this.endpoint = endpoint;
375 }
376
377
378
379
380
381
382 public void setService(Service service)
383 {
384 if (service == null)
385 {
386 throw new IllegalArgumentException("Service cannot be null");
387 }
388 this.service = service;
389 }
390
391 public final void dispose()
392 {
393 stop();
394 disposing.set(true);
395 doDispose();
396 }
397
398 public EndpointURI getEndpointURI()
399 {
400 return endpointUri;
401 }
402
403 protected WorkManager getWorkManager()
404 {
405 return workManager;
406 }
407
408 protected void setWorkManager(WorkManager workManager)
409 {
410 this.workManager = workManager;
411 }
412
413 public void connect() throws Exception
414 {
415 if (connected.get())
416 {
417 return;
418 }
419
420 if (connecting.compareAndSet(false, true))
421 {
422 if (logger.isDebugEnabled())
423 {
424 logger.debug("Connecting: " + this);
425 }
426
427 connectionStrategy.connect(this);
428
429 logger.info("Connected: " + this);
430 return;
431 }
432
433 try
434 {
435
436 connectionStrategy.connect(connector);
437
438 this.doConnect();
439 connected.set(true);
440 connecting.set(false);
441
442 connector.fireNotification(new ConnectionNotification(this, getConnectEventId(),
443 ConnectionNotification.CONNECTION_CONNECTED));
444 }
445 catch (Exception e)
446 {
447 connected.set(false);
448 connecting.set(false);
449
450 connector.fireNotification(new ConnectionNotification(this, getConnectEventId(),
451 ConnectionNotification.CONNECTION_FAILED));
452
453 if (e instanceof ConnectException)
454 {
455 throw (ConnectException) e;
456 }
457 else
458 {
459 throw new ConnectException(e, this);
460 }
461 }
462 }
463
464 public void disconnect() throws Exception
465 {
466 if (logger.isDebugEnabled())
467 {
468 logger.debug("Disconnecting: " + this);
469 }
470
471 this.doDisconnect();
472 connected.set(false);
473
474 logger.info("Disconnected: " + this);
475
476 connector.fireNotification(new ConnectionNotification(this, getConnectEventId(),
477 ConnectionNotification.CONNECTION_DISCONNECTED));
478 }
479
480 public String getConnectionDescription()
481 {
482 return endpoint.getEndpointURI().toString();
483 }
484
485 public final void start() throws MuleException
486 {
487 if (stopped.compareAndSet(true, false))
488 {
489 if (!connected.get())
490 {
491 connectionStrategy.connect(this);
492 }
493 doStart();
494 }
495 }
496
497 public final void stop()
498 {
499 try
500 {
501 if (connected.get())
502 {
503 disconnect();
504 }
505 }
506 catch (Exception e)
507 {
508
509 logger.error(e.getMessage(), e);
510 }
511
512 if (stopped.compareAndSet(false, true))
513 {
514 try
515 {
516 doStop();
517 }
518 catch (MuleException e)
519 {
520
521 logger.error(e.getMessage(), e);
522 }
523
524 }
525 }
526
527 public final boolean isConnected()
528 {
529 return connected.get();
530 }
531
532 public InternalMessageListener getListener()
533 {
534 return listener;
535 }
536
537 public void setListener(InternalMessageListener listener)
538 {
539 this.listener = listener;
540 }
541
542 private class DefaultInternalMessageListener implements InternalMessageListener
543 {
544
545 public MuleMessage onMessage(MuleMessage message,
546 Transaction trans,
547 boolean synchronous,
548 OutputStream outputStream) throws MuleException
549 {
550
551 MuleMessage resultMessage = null;
552 ResponseOutputStream ros = null;
553 if (outputStream != null)
554 {
555 if (outputStream instanceof ResponseOutputStream)
556 {
557 ros = (ResponseOutputStream) outputStream;
558 }
559 else
560 {
561 ros = new ResponseOutputStream(outputStream);
562 }
563 }
564 MuleSession session = new DefaultMuleSession(message, connector.getSessionHandler(), service, connector.getMuleContext());
565 MuleEvent muleEvent = new DefaultMuleEvent(message, endpoint, session, synchronous, ros);
566 muleEvent = OptimizedRequestContext.unsafeSetEvent(muleEvent);
567
568
569 boolean authorised = false;
570 if (endpoint.getSecurityFilter() != null)
571 {
572 try
573 {
574 endpoint.getSecurityFilter().authenticate(muleEvent);
575 authorised = true;
576 }
577 catch (SecurityException e)
578 {
579 logger.warn("Request was made but was not authenticated: " + e.getMessage(), e);
580 connector.fireNotification(new SecurityNotification(e,
581 SecurityNotification.SECURITY_AUTHENTICATION_FAILED));
582 handleException(e);
583 resultMessage = RequestContext.getEvent().getMessage();
584 }
585 }
586 else
587 {
588 authorised = true;
589 }
590
591 if (authorised)
592 {
593
594 if (responseEndpoint)
595 {
596
597 muleEvent.transformMessage();
598 service.getResponseRouter().route(muleEvent);
599 return null;
600 }
601 else
602 {
603 resultMessage = service.getInboundRouter().route(muleEvent);
604 }
605 }
606 if (resultMessage != null)
607 {
608 if (resultMessage.getExceptionPayload() != null)
609 {
610 setExceptionDetails(resultMessage, resultMessage.getExceptionPayload().getException());
611 }
612 resultMessage.applyTransformers(endpoint.getResponseTransformers());
613 }
614 return resultMessage;
615 }
616 }
617
618 protected String getConnectEventId()
619 {
620 return connector.getName() + ".receiver (" + endpoint.getEndpointURI() + ")";
621 }
622
623 public void setReceiverKey(String receiverKey)
624 {
625 this.receiverKey = receiverKey;
626 }
627
628 public String getReceiverKey()
629 {
630 return receiverKey;
631 }
632
633 public String toString()
634 {
635 final StringBuffer sb = new StringBuffer(80);
636 sb.append(ClassUtils.getSimpleName(this.getClass()));
637 sb.append("{this=").append(Integer.toHexString(System.identityHashCode(this)));
638 sb.append(", receiverKey=").append(receiverKey);
639 sb.append(", endpoint=").append(endpoint.getEndpointURI());
640 sb.append('}');
641 return sb.toString();
642 }
643
644 protected void doInitialise() throws InitialisationException
645 {
646
647
648
649
650 }
651
652 protected abstract void doStart() throws MuleException;
653
654 protected abstract void doStop() throws MuleException;
655
656 protected abstract void doConnect() throws Exception;
657
658 protected abstract void doDisconnect() throws Exception;
659
660 protected abstract void doDispose();
661
662 }