1
2
3
4
5
6
7
8
9
10
11 package org.mule.transport;
12
13 import org.mule.api.MuleException;
14 import org.mule.api.MuleMessage;
15 import org.mule.api.MuleRuntimeException;
16 import org.mule.api.config.MuleConfiguration;
17 import org.mule.api.context.WorkManager;
18 import org.mule.api.endpoint.ImmutableEndpoint;
19 import org.mule.api.lifecycle.CreateException;
20 import org.mule.api.lifecycle.InitialisationException;
21 import org.mule.api.lifecycle.LifecycleCallback;
22 import org.mule.api.lifecycle.LifecycleException;
23 import org.mule.api.lifecycle.LifecycleState;
24 import org.mule.api.lifecycle.LifecycleStateEnabled;
25 import org.mule.api.lifecycle.StartException;
26 import org.mule.api.retry.RetryCallback;
27 import org.mule.api.retry.RetryContext;
28 import org.mule.api.retry.RetryPolicyTemplate;
29 import org.mule.api.transport.Connectable;
30 import org.mule.api.transport.Connector;
31 import org.mule.api.transport.MuleMessageFactory;
32 import org.mule.config.i18n.CoreMessages;
33 import org.mule.config.i18n.Message;
34 import org.mule.config.i18n.MessageFactory;
35 import org.mule.context.notification.ConnectionNotification;
36 import org.mule.util.ClassUtils;
37 import org.mule.util.concurrent.WaitableBoolean;
38
39 import org.apache.commons.logging.Log;
40 import org.apache.commons.logging.LogFactory;
41
42
43
44
45 public abstract class AbstractTransportMessageHandler<O> implements Connectable, LifecycleStateEnabled
46 {
47 protected transient Log logger = LogFactory.getLog(getClass());
48
49 protected ImmutableEndpoint endpoint;
50 protected final AbstractConnector connector;
51 protected RetryPolicyTemplate retryTemplate;
52 protected MuleMessageFactory muleMessageFactory = null;
53
54 protected final WaitableBoolean connected = new WaitableBoolean(false);
55 protected final WaitableBoolean connecting = new WaitableBoolean(false);
56
57
58
59
60
61
62 protected volatile boolean startOnConnect = false;
63
64 protected ConnectableLifecycleManager<O> lifecycleManager;
65
66 public AbstractTransportMessageHandler(ImmutableEndpoint endpoint)
67 {
68 this.endpoint = endpoint;
69 this.connector = (AbstractConnector) endpoint.getConnector();
70 this.lifecycleManager = createLifecycleManager();
71 }
72
73 protected abstract ConnectableLifecycleManager<O> createLifecycleManager();
74
75 public LifecycleState getLifecycleState()
76 {
77 return lifecycleManager.getState();
78 }
79
80 protected void disposeAndLogException()
81 {
82 try
83 {
84 dispose();
85 }
86 catch (Throwable t)
87 {
88 logger.error("Could not dispose of the message dispatcher!", t);
89 }
90 }
91
92 public boolean validate()
93 {
94
95 return !getLifecycleState().isDisposed();
96 }
97
98 public void activate()
99 {
100
101 }
102
103 public void passivate()
104 {
105
106 }
107
108 public void initialise() throws InitialisationException
109 {
110 try
111 {
112 lifecycleManager.fireInitialisePhase(new LifecycleCallback<O>()
113 {
114 public void onTransition(String phaseName, O object) throws MuleException
115 {
116 initializeRetryPolicy();
117 initializeMessageFactory();
118 doInitialise();
119 }
120 });
121 }
122 catch (InitialisationException e)
123 {
124 throw e;
125 }
126 catch (MuleException e)
127 {
128 throw new InitialisationException(e, this);
129 }
130
131 }
132
133 protected void initializeRetryPolicy()
134 {
135 if (endpoint.getRetryPolicyTemplate() != null)
136 {
137 retryTemplate = endpoint.getRetryPolicyTemplate();
138 }
139 else
140 {
141 retryTemplate = connector.getRetryPolicyTemplate();
142 }
143 }
144
145
146
147
148
149 protected void initializeMessageFactory() throws InitialisationException
150 {
151 try
152 {
153 muleMessageFactory = connector.getMuleMessageFactory();
154 }
155 catch (CreateException ce)
156 {
157 Message message = MessageFactory.createStaticMessage(ce.getMessage());
158 throw new InitialisationException(message, ce, this);
159 }
160 }
161
162
163
164
165 public synchronized void dispose()
166 {
167 try
168 {
169 try
170 {
171 disconnect();
172 }
173 catch (Exception e)
174 {
175 logger.warn(e.getMessage(), e);
176 }
177 if (isStarted())
178 {
179 stop();
180 }
181
182
183 lifecycleManager.fireDisposePhase(new LifecycleCallback<O>() {
184 public void onTransition(String phaseName, O object) throws MuleException
185 {
186 doDispose();
187 }
188 });
189 }
190 catch (Exception e)
191 {
192 logger.warn(e.getMessage(), e);
193 }
194 }
195
196 public Connector getConnector()
197 {
198 return connector;
199 }
200
201 public ImmutableEndpoint getEndpoint()
202 {
203 return endpoint;
204 }
205
206 public final synchronized void connect() throws Exception
207 {
208
209
210 if (connected.get() || connecting.get())
211 {
212 return;
213 }
214
215 if (getLifecycleState().isDisposed())
216 {
217 throw new IllegalStateException(
218 "Requester/dispatcher has been disposed; cannot connect to resource:" + this);
219 }
220
221 if (!connecting.compareAndSet(false, true))
222 {
223 return;
224 }
225
226 if (logger.isDebugEnabled())
227 {
228 logger.debug("Connecting: " + this);
229 }
230
231 retryTemplate.execute(
232 new RetryCallback()
233 {
234 public void doWork(RetryContext context) throws Exception
235 {
236 try
237 {
238 doConnect();
239 connected.set(true);
240 connecting.set(false);
241
242 if (logger.isDebugEnabled())
243 {
244 logger.debug("Connected: " + getWorkDescription());
245 }
246
247
248
249
250 if (startOnConnect)
251 {
252 start();
253 }
254 }
255 catch (Exception e)
256 {
257 if (logger.isDebugEnabled())
258 {
259 logger.debug("exception in doWork", e);
260 }
261 throw e;
262 }
263 }
264
265 public String getWorkDescription()
266 {
267 return getConnectionDescription();
268 }
269 },
270 getWorkManager()
271 );
272 }
273
274 public RetryContext validateConnection(RetryContext retryContext)
275 {
276 retryContext.setOk();
277 return retryContext;
278 }
279
280 public final synchronized void disconnect() throws Exception
281 {
282 if (!connected.get())
283 {
284 return;
285 }
286
287 if (logger.isDebugEnabled())
288 {
289 logger.debug("Disconnecting: " + this);
290 }
291
292 this.doDisconnect();
293 connected.set(false);
294
295 if (logger.isDebugEnabled())
296 {
297 logger.debug("Disconnected: " + this);
298 }
299 connector.fireNotification(new ConnectionNotification(this, getConnectEventId(endpoint),
300 ConnectionNotification.CONNECTION_DISCONNECTED));
301 }
302
303 protected String getConnectEventId(ImmutableEndpoint endpoint)
304 {
305 return connector.getName() + ".dispatcher(" + endpoint.getEndpointURI().getUri() + ")";
306 }
307
308 public final boolean isConnected()
309 {
310 return connected.get();
311 }
312
313 public final boolean isConnecting()
314 {
315 return connecting.get();
316 }
317
318 protected boolean isDoThreading()
319 {
320 return connector.getDispatcherThreadingProfile().isDoThreading();
321 }
322
323
324
325
326 public String getConnectionDescription()
327 {
328 return "endpoint.outbound." + endpoint.getEndpointURI().toString();
329 }
330
331
332
333
334
335
336
337
338
339
340
341 public final void start() throws MuleException
342 {
343
344 if (!connected.get() && !connecting.get())
345 {
346 connectAndThenStart();
347 }
348 else if (connecting.get() && isDoStartMustFollowDoConnect())
349 {
350 try
351 {
352 callDoStartWhenItIsConnected();
353 }
354 catch (InterruptedException e)
355 {
356 throw new StartException(CoreMessages.failedToStart("Connectable: " + this), e, this);
357 }
358 }
359 else
360 {
361 try
362 {
363 lifecycleManager.fireStartPhase(new LifecycleCallback<O>()
364 {
365 public void onTransition(String phaseName, O object) throws MuleException
366 {
367 doStart();
368 }
369 });
370 }
371 catch (MuleException e)
372 {
373 throw e;
374 }
375 catch (Exception e)
376 {
377 throw new StartException(CoreMessages.failedToStart("Connectable: " + this), e, this);
378 }
379 }
380 }
381
382
383
384
385
386
387
388
389 protected void connectAndThenStart() throws LifecycleException
390 {
391 startOnConnect = true;
392
393
394 try
395 {
396 connect();
397 }
398 catch (Exception e)
399 {
400 throw new LifecycleException(e, this);
401 }
402 }
403
404
405
406
407
408
409
410
411
412
413 protected void callDoStartWhenItIsConnected() throws InterruptedException, MuleException
414 {
415 try
416 {
417 connected.whenTrue(new Runnable()
418 {
419 public void run()
420 {
421 try
422 {
423 lifecycleManager.fireStartPhase(new LifecycleCallback<O>()
424 {
425 public void onTransition(String phaseName, O object) throws MuleException
426 {
427 doStart();
428 }
429 });
430 }
431 catch (MuleException e)
432 {
433 throw new MuleRuntimeException(
434 CoreMessages.createStaticMessage("wrapper exception for a MuleException"), e);
435 }
436 }
437 });
438 }
439 catch (MuleRuntimeException e)
440 {
441 if (e.getCause() instanceof MuleException)
442 {
443 throw (MuleException) e.getCause();
444 }
445 else
446 {
447 throw e;
448 }
449 }
450 }
451
452 public final void stop() throws MuleException
453 {
454 try
455 {
456 if (connected.get())
457 {
458 disconnect();
459 }
460 }
461 catch (Exception e)
462 {
463 logger.error(e.getMessage(), e);
464 }
465
466 lifecycleManager.fireStopPhase(new LifecycleCallback<O>()
467 {
468 public void onTransition(String phaseName, O object) throws MuleException
469 {
470 try
471 {
472 doStop();
473 }
474 catch (MuleException e)
475 {
476 logger.error(e.getMessage(), e);
477 }
478 }
479 });
480
481 }
482
483 protected void doInitialise() throws InitialisationException
484 {
485
486 }
487
488 protected void doDispose()
489 {
490
491 }
492
493 protected void doConnect() throws Exception
494 {
495
496 }
497
498 protected void doDisconnect() throws Exception
499 {
500
501 }
502
503 protected void doStart() throws MuleException
504 {
505
506 }
507
508 protected void doStop() throws MuleException
509 {
510
511 }
512
513 @Override
514 public String toString()
515 {
516 final StringBuffer sb = new StringBuffer(80);
517 sb.append(ClassUtils.getSimpleName(this.getClass()));
518 sb.append("{this=").append(Integer.toHexString(System.identityHashCode(this)));
519 sb.append(", endpoint=").append(endpoint.getEndpointURI());
520 sb.append(", disposed=").append(getLifecycleState().isDisposed());
521 sb.append('}');
522 return sb.toString();
523 }
524
525
526
527 public void setEndpoint(ImmutableEndpoint endpoint)
528 {
529 if (endpoint == null)
530 {
531 throw new IllegalArgumentException("Endpoint cannot be null");
532 }
533 this.endpoint = endpoint;
534 }
535
536 abstract protected WorkManager getWorkManager() throws MuleException;
537
538 public boolean isStarted()
539 {
540 return getLifecycleState().isStarted();
541 }
542
543
544
545
546
547
548 protected MuleMessageFactory createMuleMessageFactory() throws CreateException
549 {
550 return connector.createMuleMessageFactory();
551 }
552
553
554
555
556
557
558 public MuleMessage createMuleMessage(Object transportMessage, MuleMessage previousMessage,
559 String encoding) throws MuleException
560 {
561 try
562 {
563 return muleMessageFactory.create(transportMessage, previousMessage, encoding);
564 }
565 catch (Exception e)
566 {
567 throw new CreateException(CoreMessages.failedToCreate("MuleMessage"), e);
568 }
569 }
570
571
572
573
574
575 public MuleMessage createMuleMessage(Object transportMessage, String encoding) throws MuleException
576 {
577 try
578 {
579 return muleMessageFactory.create(transportMessage, encoding);
580 }
581 catch (Exception e)
582 {
583 throw new CreateException(CoreMessages.failedToCreate("MuleMessage"), e, this);
584 }
585 }
586
587
588
589
590
591
592
593 public MuleMessage createMuleMessage(Object transportMessage) throws MuleException
594 {
595 String encoding = endpoint.getMuleContext().getConfiguration().getDefaultEncoding();
596 return createMuleMessage(transportMessage, encoding);
597 }
598
599
600
601
602
603
604 protected MuleMessage createNullMuleMessage() throws MuleException
605 {
606 return createMuleMessage(null);
607 }
608
609
610
611
612 protected boolean isDoStartMustFollowDoConnect()
613 {
614 return false;
615 }
616 }