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 AbstractConnectable<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 AbstractConnectable(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, AbstractConnectable.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
372
373
374
375
376
377
378
379
380
381
382 }
383 catch (MuleException e)
384 {
385 throw e;
386 }
387 catch (Exception e)
388 {
389 throw new StartException(CoreMessages.failedToStart("Connectable: " + this), e, AbstractConnectable.this);
390 }
391 }
392 }
393
394
395
396
397
398
399
400
401 protected void connectAndThenStart() throws LifecycleException
402 {
403 startOnConnect = true;
404
405
406 try
407 {
408 connect();
409 }
410 catch (Exception e)
411 {
412 throw new LifecycleException(e, this);
413 }
414 }
415
416
417
418
419
420
421
422
423
424
425 protected void callDoStartWhenItIsConnected() throws InterruptedException, MuleException
426 {
427 try
428 {
429 connected.whenTrue(new Runnable()
430 {
431 public void run()
432 {
433 try
434 {
435 lifecycleManager.fireStartPhase(new LifecycleCallback<O>()
436 {
437 public void onTransition(String phaseName, O object) throws MuleException
438 {
439 doStart();
440 }
441 });
442 }
443 catch (MuleException e)
444 {
445 throw new MuleRuntimeException(
446 CoreMessages.createStaticMessage("wrapper exception for a MuleException"), e);
447 }
448 }
449 });
450 }
451 catch (MuleRuntimeException e)
452 {
453 if (e.getCause() instanceof MuleException)
454 {
455 throw (MuleException) e.getCause();
456 }
457 else
458 {
459 throw e;
460 }
461 }
462 }
463
464 public final void stop() throws MuleException
465 {
466 try
467 {
468 if (connected.get())
469 {
470 disconnect();
471 }
472 }
473 catch (Exception e)
474 {
475 logger.error(e.getMessage(), e);
476 }
477
478 lifecycleManager.fireStopPhase(new LifecycleCallback<O>()
479 {
480 public void onTransition(String phaseName, O object) throws MuleException
481 {
482 try
483 {
484 doStop();
485 }
486 catch (MuleException e)
487 {
488 logger.error(e.getMessage(), e);
489 }
490 }
491 });
492
493 }
494
495 protected void doInitialise() throws InitialisationException
496 {
497
498 }
499
500 protected void doDispose()
501 {
502
503 }
504
505 protected void doConnect() throws Exception
506 {
507
508 }
509
510 protected void doDisconnect() throws Exception
511 {
512
513 }
514
515 protected void doStart() throws MuleException
516 {
517
518 }
519
520 protected void doStop() throws MuleException
521 {
522
523 }
524
525 @Override
526 public String toString()
527 {
528 final StringBuffer sb = new StringBuffer(80);
529 sb.append(ClassUtils.getSimpleName(this.getClass()));
530 sb.append("{this=").append(Integer.toHexString(System.identityHashCode(this)));
531 sb.append(", endpoint=").append(endpoint.getEndpointURI());
532 sb.append(", disposed=").append(getLifecycleState().isDisposed());
533 sb.append('}');
534 return sb.toString();
535 }
536
537
538
539 public void setEndpoint(ImmutableEndpoint endpoint)
540 {
541 if (endpoint == null)
542 {
543 throw new IllegalArgumentException("Endpoint cannot be null");
544 }
545 this.endpoint = endpoint;
546 }
547
548 abstract protected WorkManager getWorkManager() throws MuleException;
549
550 public boolean isStarted()
551 {
552 return getLifecycleState().isStarted();
553 }
554
555
556
557
558
559
560 protected MuleMessageFactory createMuleMessageFactory() throws CreateException
561 {
562 return connector.createMuleMessageFactory();
563 }
564
565
566
567
568
569
570 public MuleMessage createMuleMessage(Object transportMessage, MuleMessage previousMessage,
571 String encoding) throws MuleException
572 {
573 try
574 {
575 return muleMessageFactory.create(transportMessage, previousMessage, encoding);
576 }
577 catch (Exception e)
578 {
579 throw new CreateException(CoreMessages.failedToCreate("MuleMessage"), e);
580 }
581 }
582
583
584
585
586
587 public MuleMessage createMuleMessage(Object transportMessage, String encoding) throws MuleException
588 {
589 try
590 {
591 return muleMessageFactory.create(transportMessage, encoding);
592 }
593 catch (Exception e)
594 {
595 throw new CreateException(CoreMessages.failedToCreate("MuleMessage"), e, this);
596 }
597 }
598
599
600
601
602
603
604
605 public MuleMessage createMuleMessage(Object transportMessage) throws MuleException
606 {
607 String encoding = endpoint.getMuleContext().getConfiguration().getDefaultEncoding();
608 return createMuleMessage(transportMessage, encoding);
609 }
610
611
612
613
614
615
616 protected MuleMessage createNullMuleMessage() throws MuleException
617 {
618 return createMuleMessage(null);
619 }
620
621
622
623
624 protected boolean isDoStartMustFollowDoConnect()
625 {
626 return false;
627 }
628 }