1
2
3
4
5
6
7
8
9
10
11 package org.mule.providers;
12
13 import org.mule.MuleRuntimeException;
14 import org.mule.config.MuleProperties;
15 import org.mule.config.i18n.CoreMessages;
16 import org.mule.impl.OptimizedRequestContext;
17 import org.mule.impl.RequestContext;
18 import org.mule.impl.internal.notifications.ConnectionNotification;
19 import org.mule.impl.internal.notifications.MessageNotification;
20 import org.mule.impl.internal.notifications.SecurityNotification;
21 import org.mule.transaction.TransactionCoordination;
22 import org.mule.umo.TransactionException;
23 import org.mule.umo.UMOEvent;
24 import org.mule.umo.UMOException;
25 import org.mule.umo.UMOMessage;
26 import org.mule.umo.UMOTransaction;
27 import org.mule.umo.endpoint.UMOImmutableEndpoint;
28 import org.mule.umo.manager.UMOWorkManager;
29 import org.mule.umo.provider.DispatchException;
30 import org.mule.umo.provider.ReceiveException;
31 import org.mule.umo.provider.UMOConnector;
32 import org.mule.umo.provider.UMOMessageDispatcher;
33 import org.mule.util.ClassUtils;
34
35 import java.beans.ExceptionListener;
36
37 import javax.resource.spi.work.Work;
38 import javax.resource.spi.work.WorkManager;
39
40 import org.apache.commons.logging.Log;
41 import org.apache.commons.logging.LogFactory;
42
43
44
45
46
47 public abstract class AbstractMessageDispatcher implements UMOMessageDispatcher, ExceptionListener
48 {
49
50
51
52 protected transient Log logger = LogFactory.getLog(getClass());
53
54
55
56
57 protected UMOWorkManager workManager = null;
58
59 protected final UMOImmutableEndpoint endpoint;
60 protected final AbstractConnector connector;
61
62 protected boolean disposed = false;
63
64 protected ConnectionStrategy connectionStrategy;
65
66 protected volatile boolean connecting = false;
67 protected volatile boolean connected = false;
68
69 public AbstractMessageDispatcher(UMOImmutableEndpoint endpoint)
70 {
71 this.endpoint = endpoint;
72 this.connector = (AbstractConnector) endpoint.getConnector();
73
74 connectionStrategy = connector.getConnectionStrategy();
75 if (connectionStrategy instanceof AbstractConnectionStrategy)
76 {
77
78
79
80 final AbstractConnectionStrategy connStrategy = (AbstractConnectionStrategy) connectionStrategy;
81 if (connStrategy.isDoThreading())
82 {
83 if (logger.isDebugEnabled())
84 {
85 logger.debug("Overriding doThreading to false on " + connStrategy);
86 }
87 connStrategy.setDoThreading(false);
88 }
89 }
90
91 if (isDoThreading())
92 {
93 try
94 {
95 workManager = connector.getDispatcherWorkManager();
96 }
97 catch (UMOException e)
98 {
99 dispose();
100 throw new MuleRuntimeException(CoreMessages.failedToStart("WorkManager"), e);
101 }
102 }
103 }
104
105
106
107
108
109
110 public final void dispatch(UMOEvent event) throws DispatchException
111 {
112 event.setSynchronous(false);
113 event.getMessage().setProperty(MuleProperties.MULE_ENDPOINT_PROPERTY,
114 event.getEndpoint().getEndpointURI().toString());
115 event = OptimizedRequestContext.criticalSetEvent(event);
116
117
118 UMOImmutableEndpoint endpoint = event.getEndpoint();
119 if (endpoint.getSecurityFilter() != null)
120 {
121 try
122 {
123 endpoint.getSecurityFilter().authenticate(event);
124 }
125 catch (org.mule.umo.security.SecurityException e)
126 {
127
128 logger.warn("Outbound Request was made but was not authenticated: " + e.getMessage(), e);
129 connector.fireNotification(new SecurityNotification(e,
130 SecurityNotification.ADMIN_EVENT_ACTION_START_RANGE));
131 connector.handleException(e);
132 return;
133 }
134 catch (UMOException e)
135 {
136 dispose();
137 throw new DispatchException(event.getMessage(), event.getEndpoint(), e);
138 }
139 }
140
141
142 event = RequestContext.getEvent();
143
144 try
145 {
146 UMOTransaction tx = TransactionCoordination.getInstance().getTransaction();
147 if (isDoThreading() && !event.isSynchronous() && tx == null)
148 {
149 workManager.scheduleWork(new Worker(event), WorkManager.INDEFINITE, null, connector);
150 }
151 else
152 {
153
154 connectionStrategy.connect(this);
155 doDispatch(event);
156 if (connector.isEnableMessageEvents())
157 {
158 String component = null;
159 if (event.getComponent() != null)
160 {
161 component = event.getComponent().getDescriptor().getName();
162 }
163 connector.fireNotification(new MessageNotification(event.getMessage(), event
164 .getEndpoint(), component, MessageNotification.MESSAGE_DISPATCHED));
165 }
166 }
167 }
168 catch (DispatchException e)
169 {
170 dispose();
171 throw e;
172 }
173 catch (Exception e)
174 {
175 dispose();
176 throw new DispatchException(event.getMessage(), event.getEndpoint(), e);
177 }
178 }
179
180 public final UMOMessage send(UMOEvent event) throws DispatchException
181 {
182
183 if (isTransactionRollback())
184 {
185 return event.getMessage();
186 }
187
188 event.setSynchronous(true);
189 event.getMessage().setProperty(MuleProperties.MULE_ENDPOINT_PROPERTY,
190 event.getEndpoint().getEndpointURI().toString());
191 event = OptimizedRequestContext.unsafeSetEvent(event);
192
193
194 UMOImmutableEndpoint endpoint = event.getEndpoint();
195 if (endpoint.getSecurityFilter() != null)
196 {
197 try
198 {
199 endpoint.getSecurityFilter().authenticate(event);
200 }
201 catch (org.mule.umo.security.SecurityException e)
202 {
203 logger.warn("Outbound Request was made but was not authenticated: " + e.getMessage(), e);
204 connector.fireNotification(new SecurityNotification(e,
205 SecurityNotification.SECURITY_AUTHENTICATION_FAILED));
206 connector.handleException(e);
207 return event.getMessage();
208 }
209 catch (UMOException e)
210 {
211 dispose();
212 throw new DispatchException(event.getMessage(), event.getEndpoint(), e);
213 }
214 }
215
216
217 event = RequestContext.getEvent();
218
219 try
220 {
221
222 connectionStrategy.connect(this);
223
224 UMOMessage result = doSend(event);
225 if (connector.isEnableMessageEvents())
226 {
227 String component = null;
228 if (event.getComponent() != null)
229 {
230 component = event.getComponent().getDescriptor().getName();
231 }
232 connector.fireNotification(new MessageNotification(event.getMessage(), event.getEndpoint(),
233 component, MessageNotification.MESSAGE_SENT));
234 }
235
236
237
238 if (result != null)
239 {
240 result.removeProperty(MuleProperties.MULE_REMOTE_SYNC_PROPERTY);
241 }
242 return result;
243 }
244 catch (DispatchException e)
245 {
246 dispose();
247 throw e;
248 }
249 catch (Exception e)
250 {
251 dispose();
252 throw new DispatchException(event.getMessage(), event.getEndpoint(), e);
253 }
254 }
255
256
257
258
259
260
261
262
263
264
265
266
267 public final UMOMessage receive(long timeout) throws Exception
268 {
269 try
270 {
271
272 connectionStrategy.connect(this);
273 UMOMessage result = doReceive(timeout);
274 if (result != null && connector.isEnableMessageEvents())
275 {
276 connector.fireNotification(new MessageNotification(result, endpoint, null,
277 MessageNotification.MESSAGE_RECEIVED));
278 }
279 return result;
280 }
281 catch (DispatchException e)
282 {
283 dispose();
284 throw e;
285 }
286 catch (Exception e)
287 {
288 dispose();
289 throw new ReceiveException(endpoint, timeout, e);
290 }
291 }
292
293
294
295
296
297
298 public void exceptionThrown(Exception e)
299 {
300 try
301 {
302 getConnector().handleException(e);
303 }
304 finally
305 {
306 dispose();
307 }
308 }
309
310 public boolean validate()
311 {
312
313 return !disposed;
314 }
315
316 public void activate()
317 {
318
319 }
320
321 public void passivate()
322 {
323
324 }
325
326
327
328
329 public final synchronized void dispose()
330 {
331 if (!disposed)
332 {
333 try
334 {
335 try
336 {
337 this.disconnect();
338 }
339 catch (Exception e)
340 {
341
342 logger.warn(e.getMessage(), e);
343 }
344
345 this.doDispose();
346
347 if (workManager != null)
348 {
349 workManager.dispose();
350 }
351 }
352 finally
353 {
354 disposed = true;
355 }
356 }
357 }
358
359 public UMOConnector getConnector()
360 {
361 return connector;
362 }
363
364 public UMOImmutableEndpoint getEndpoint()
365 {
366 return endpoint;
367 }
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386 protected boolean useRemoteSync(UMOEvent event)
387 {
388 boolean remoteSync = false;
389 if (event.getEndpoint().getConnector().isRemoteSyncEnabled())
390 {
391 remoteSync = event.getEndpoint().isRemoteSync()
392 || event.getMessage().getBooleanProperty(
393 MuleProperties.MULE_REMOTE_SYNC_PROPERTY, false);
394 if (remoteSync)
395 {
396
397 if (event.getComponent() != null)
398 {
399 remoteSync = event.getComponent().getDescriptor().getResponseRouter() == null;
400 }
401 }
402 }
403 if (!remoteSync)
404 {
405 event.getMessage().removeProperty(MuleProperties.MULE_REMOTE_SYNC_PROPERTY);
406 }
407 return remoteSync;
408 }
409
410 public synchronized void connect() throws Exception
411 {
412 if (disposed)
413 {
414 throw new IllegalStateException("Dispatcher has been disposed; cannot connect to resource");
415 }
416
417 if (connected)
418 {
419 return;
420 }
421
422 if (!connecting)
423 {
424 connecting = true;
425
426 if (logger.isDebugEnabled())
427 {
428 logger.debug("Connecting: " + this);
429 }
430
431 connectionStrategy.connect(this);
432
433 logger.info("Connected: " + this);
434 return;
435 }
436
437 try
438 {
439 this.doConnect();
440 connected = true;
441 connecting = false;
442
443 connector.fireNotification(new ConnectionNotification(this, getConnectEventId(endpoint),
444 ConnectionNotification.CONNECTION_CONNECTED));
445 }
446 catch (Exception e)
447 {
448 connected = false;
449 connecting = false;
450
451 connector.fireNotification(new ConnectionNotification(this, getConnectEventId(endpoint),
452 ConnectionNotification.CONNECTION_FAILED));
453
454 if (e instanceof ConnectException)
455 {
456 throw (ConnectException) e;
457 }
458 else
459 {
460 throw new ConnectException(e, this);
461 }
462 }
463 }
464
465 public synchronized void disconnect() throws Exception
466 {
467 if (!connected)
468 {
469 return;
470 }
471
472 if (logger.isDebugEnabled())
473 {
474 logger.debug("Disconnecting: " + this);
475 }
476
477 this.doDisconnect();
478 connected = false;
479
480 logger.info("Disconnected: " + this);
481
482 connector.fireNotification(new ConnectionNotification(this, getConnectEventId(endpoint),
483 ConnectionNotification.CONNECTION_DISCONNECTED));
484 }
485
486 protected String getConnectEventId(UMOImmutableEndpoint endpoint)
487 {
488 return connector.getName() + ".dispatcher(" + endpoint.getEndpointURI() + ")";
489 }
490
491 public final boolean isConnected()
492 {
493 return connected;
494 }
495
496 protected boolean isDoThreading ()
497 {
498 return connector.getDispatcherThreadingProfile().isDoThreading();
499 }
500
501
502
503
504
505
506 public String getConnectionDescription()
507 {
508 return endpoint.getEndpointURI().toString();
509 }
510
511 public synchronized void reconnect() throws Exception
512 {
513 disconnect();
514 connect();
515 }
516
517 protected abstract void doDispose();
518
519 protected abstract void doDispatch(UMOEvent event) throws Exception;
520
521 protected abstract UMOMessage doSend(UMOEvent event) throws Exception;
522
523 protected abstract void doConnect() throws Exception;
524
525 protected abstract void doDisconnect() throws Exception;
526
527
528
529
530
531
532
533
534
535
536
537
538 protected abstract UMOMessage doReceive(long timeout) throws Exception;
539
540 private class Worker implements Work
541 {
542 private UMOEvent event;
543
544 public Worker(UMOEvent event)
545 {
546 this.event = event;
547 }
548
549
550
551
552
553
554 public void run()
555 {
556 try
557 {
558 event = OptimizedRequestContext.criticalSetEvent(event);
559
560 connectionStrategy.connect(AbstractMessageDispatcher.this);
561 AbstractMessageDispatcher.this.doDispatch(event);
562
563 if (connector.isEnableMessageEvents())
564 {
565 String component = null;
566 if (event.getComponent() != null)
567 {
568 component = event.getComponent().getDescriptor().getName();
569 }
570
571 connector.fireNotification(new MessageNotification(event.getMessage(), event
572 .getEndpoint(), component, MessageNotification.MESSAGE_DISPATCHED));
573 }
574 }
575 catch (Exception e)
576 {
577 AbstractMessageDispatcher.this.getConnector().handleException(e);
578 }
579 }
580
581 public void release()
582 {
583
584 }
585 }
586
587
588
589
590
591
592 protected boolean isTransactionRollback()
593 {
594 try
595 {
596 UMOTransaction tx = TransactionCoordination.getInstance().getTransaction();
597 if (tx != null && tx.isRollbackOnly())
598 {
599 return true;
600 }
601 }
602 catch (TransactionException e)
603 {
604
605 logger.warn(e.getMessage());
606 }
607 return false;
608 }
609
610
611 public String toString()
612 {
613 final StringBuffer sb = new StringBuffer(80);
614 sb.append(ClassUtils.getSimpleName(this.getClass()));
615 sb.append("{this=").append(Integer.toHexString(System.identityHashCode(this)));
616 sb.append(", endpoint=").append(endpoint.getEndpointURI());
617 sb.append('}');
618 return sb.toString();
619 }
620 }