Coverage Report - org.mule.transport.AbstractTransportMessageHandler
 
Classes in this File Line Coverage Branch Coverage Complexity
AbstractTransportMessageHandler
0%
0/119
0%
0/30
0
AbstractTransportMessageHandler$1
0%
0/5
N/A
0
AbstractTransportMessageHandler$2
0%
0/3
N/A
0
AbstractTransportMessageHandler$3
0%
0/3
N/A
0
AbstractTransportMessageHandler$4
0%
0/6
N/A
0
 
 1  
 /*
 2  
  * Copyright (c) MuleSoft, Inc.  All rights reserved.  http://www.mulesoft.com
 3  
  * The software in this package is published under the terms of the CPAL v1.0
 4  
  * license, a copy of which has been included with this distribution in the
 5  
  * LICENSE.txt file.
 6  
  */
 7  
 package org.mule.transport;
 8  
 
 9  
 import org.mule.api.MuleException;
 10  
 import org.mule.api.MuleMessage;
 11  
 import org.mule.api.config.MuleConfiguration;
 12  
 import org.mule.api.context.WorkManager;
 13  
 import org.mule.api.endpoint.ImmutableEndpoint;
 14  
 import org.mule.api.lifecycle.CreateException;
 15  
 import org.mule.api.lifecycle.InitialisationException;
 16  
 import org.mule.api.lifecycle.LifecycleCallback;
 17  
 import org.mule.api.lifecycle.LifecycleState;
 18  
 import org.mule.api.lifecycle.LifecycleStateEnabled;
 19  
 import org.mule.api.retry.RetryContext;
 20  
 import org.mule.api.retry.RetryPolicyTemplate;
 21  
 import org.mule.api.transport.Connectable;
 22  
 import org.mule.api.transport.Connector;
 23  
 import org.mule.api.transport.MuleMessageFactory;
 24  
 import org.mule.config.i18n.CoreMessages;
 25  
 import org.mule.config.i18n.Message;
 26  
 import org.mule.config.i18n.MessageFactory;
 27  
 import org.mule.context.notification.ConnectionNotification;
 28  
 import org.mule.util.ClassUtils;
 29  
 
 30  
 import edu.emory.mathcs.backport.java.util.concurrent.atomic.AtomicBoolean;
 31  
 
 32  
 import org.apache.commons.logging.Log;
 33  
 import org.apache.commons.logging.LogFactory;
 34  
 
 35  
 /**
 36  
  * Provide a default dispatch (client) support for handling threads lifecycle and validation.
 37  
  */
 38  
 public abstract class AbstractTransportMessageHandler<O> implements Connectable, LifecycleStateEnabled
 39  
 {
 40  0
     protected transient Log logger = LogFactory.getLog(getClass());
 41  
 
 42  
     protected ImmutableEndpoint endpoint;
 43  
     protected final AbstractConnector connector;
 44  
     protected RetryPolicyTemplate retryTemplate;
 45  0
     protected MuleMessageFactory muleMessageFactory = null;
 46  
 
 47  
     protected ConnectableLifecycleManager<O> lifecycleManager;
 48  
     // TODO This state info. needs to be incorporated into the ConnectableLifecycleManager
 49  0
     protected final AtomicBoolean connected = new AtomicBoolean(false);
 50  
     
 51  
     public AbstractTransportMessageHandler(ImmutableEndpoint endpoint)
 52  0
     {
 53  0
         this.endpoint = endpoint;
 54  0
         this.connector = (AbstractConnector) endpoint.getConnector();
 55  0
         this.lifecycleManager = createLifecycleManager();
 56  0
     }
 57  
 
 58  
     protected abstract ConnectableLifecycleManager<O> createLifecycleManager();
 59  
 
 60  
     public LifecycleState getLifecycleState()
 61  
     {
 62  0
         return lifecycleManager.getState();
 63  
     }
 64  
 
 65  
     protected void disposeAndLogException()
 66  
     {
 67  
         try
 68  
         {
 69  0
             dispose();
 70  
         }
 71  0
         catch (Throwable t)
 72  
         {
 73  0
             logger.error("Could not dispose of the message dispatcher!", t);
 74  0
         }
 75  0
     }
 76  
 
 77  
     public boolean validate()
 78  
     {
 79  
         // by default a dispatcher/requester can be used unless disposed
 80  0
         return !getLifecycleState().isDisposed();
 81  
     }
 82  
 
 83  
     public void activate()
 84  
     {
 85  
         // nothing to do by default
 86  0
     }
 87  
 
 88  
     public void passivate()
 89  
     {
 90  
         // nothing to do by default
 91  0
     }
 92  
 
 93  
     public void initialise() throws InitialisationException
 94  
     {
 95  
         try
 96  
         {
 97  0
             lifecycleManager.fireInitialisePhase(new LifecycleCallback<O>()
 98  0
             {
 99  
                 public void onTransition(String phaseName, O object) throws MuleException
 100  
                 {
 101  0
                     initializeRetryPolicy();
 102  0
                     initializeMessageFactory();
 103  0
                     doInitialise();
 104  0
                 }
 105  
             });
 106  
         }
 107  0
         catch (InitialisationException e)
 108  
         {
 109  0
             throw e;
 110  
         }
 111  0
         catch (MuleException e)
 112  
         {
 113  0
             throw new InitialisationException(e, this);
 114  0
         }
 115  
 
 116  0
     }
 117  
 
 118  
     protected void initializeRetryPolicy()
 119  
     {
 120  0
         if (endpoint.getRetryPolicyTemplate() != null)
 121  
         {
 122  0
             retryTemplate = endpoint.getRetryPolicyTemplate();
 123  
         }
 124  
         else
 125  
         {
 126  0
             retryTemplate = connector.getRetryPolicyTemplate();
 127  
         }
 128  0
     }
 129  
 
 130  
     /**
 131  
      * Subclasses can override this method to create a custom {@link MuleMessageFactory} instead
 132  
      * of re-using the instance from the connector.
 133  
      */
 134  
     protected void initializeMessageFactory() throws InitialisationException
 135  
     {
 136  
         try
 137  
         {
 138  0
             muleMessageFactory = connector.getMuleMessageFactory();
 139  
         }
 140  0
         catch (CreateException ce)
 141  
         {
 142  0
             Message message = MessageFactory.createStaticMessage(ce.getMessage());
 143  0
             throw new InitialisationException(message, ce, this);
 144  0
         }
 145  0
     }
 146  
 
 147  
     /**
 148  
      * Template method to destroy any resources held by the Message Dispatcher
 149  
      */
 150  
     public synchronized void dispose()
 151  
     {
 152  
         try
 153  
         {
 154  0
             if (isStarted())
 155  
             {
 156  0
                 stop();
 157  
             }
 158  0
             if (isConnected())
 159  
             {
 160  0
                 disconnect();
 161  
             }
 162  
         }
 163  0
         catch (Exception e)
 164  
         {
 165  0
             logger.warn(e.getMessage(), e);
 166  0
         }
 167  
 
 168  
         try
 169  
         {
 170  0
             lifecycleManager.fireDisposePhase(new LifecycleCallback<O>() 
 171  0
             {
 172  
                 public void onTransition(String phaseName, O object) throws MuleException
 173  
                 {
 174  0
                     doDispose();
 175  0
                 }
 176  
             });
 177  
         }
 178  0
         catch (MuleException e)
 179  
         {
 180  0
             logger.warn(e.getMessage(), e);
 181  0
         }
 182  0
     }
 183  
 
 184  
     public Connector getConnector()
 185  
     {
 186  0
         return connector;
 187  
     }
 188  
 
 189  
     public ImmutableEndpoint getEndpoint()
 190  
     {
 191  0
         return endpoint;
 192  
     }
 193  
 
 194  
     public final synchronized void connect() throws Exception
 195  
     {
 196  
         // This method may be called to ensure transport is connected, if it is
 197  
         // already connected then just return.
 198  0
         if (connected.get())
 199  
         {
 200  0
             return;
 201  
         }
 202  
 
 203  0
         if (getLifecycleState().isDisposed())
 204  
         {
 205  0
             throw new IllegalStateException(
 206  
                     "Requester/dispatcher has been disposed; cannot connect to resource:" + this);
 207  
         }
 208  
 
 209  0
         if (logger.isDebugEnabled())
 210  
         {
 211  0
             logger.debug("Connecting: " + this);
 212  
         }
 213  
 
 214  0
         doConnect();
 215  0
         connected.set(true);
 216  
 
 217  0
         if (logger.isDebugEnabled())
 218  
         {
 219  0
             logger.debug("Connected: " + getConnectionDescription());
 220  
         }
 221  0
     }
 222  
 
 223  
     public RetryContext validateConnection(RetryContext retryContext)
 224  
     {
 225  0
         retryContext.setOk();
 226  0
         return retryContext;
 227  
     }
 228  
 
 229  
     public final synchronized void disconnect() throws Exception
 230  
     {
 231  0
         if (isStarted())
 232  
         {
 233  0
             stop();
 234  
         }
 235  
         
 236  0
         if (logger.isDebugEnabled())
 237  
         {
 238  0
             logger.debug("Disconnecting: " + this);
 239  
         }
 240  
 
 241  0
         doDisconnect();
 242  0
         connected.set(false);
 243  
 
 244  0
         if (logger.isDebugEnabled())
 245  
         {
 246  0
             logger.debug("Disconnected: " + this);
 247  
         }
 248  0
         connector.fireNotification(new ConnectionNotification(this, getConnectEventId(endpoint),
 249  
                 ConnectionNotification.CONNECTION_DISCONNECTED));
 250  0
     }
 251  
 
 252  
     protected String getConnectEventId(ImmutableEndpoint endpoint)
 253  
     {
 254  0
         return connector.getName() + ".dispatcher(" + endpoint.getEndpointURI().getUri() + ")";
 255  
     }
 256  
 
 257  
     public final boolean isConnected()
 258  
     {
 259  0
         return connected.get();
 260  
     }
 261  
 
 262  
     protected boolean isDoThreading()
 263  
     {
 264  0
         return connector.getDispatcherThreadingProfile().isDoThreading();
 265  
     }
 266  
 
 267  
     /**
 268  
      * Returns a string identifying the underlying resource
 269  
      */
 270  
     public String getConnectionDescription()
 271  
     {
 272  0
         return "endpoint.outbound." + endpoint.getEndpointURI().toString();
 273  
     }
 274  
 
 275  
     /**
 276  
      * This method will start the connectable, calling {@link #connect()} if it is
 277  
      * needed.
 278  
      * <p/>
 279  
      * This method is synchronous or not depending on how the {@link #retryTemplate}
 280  
      * behaves.
 281  
      * <p/>
 282  
      * This method ensures that {@link #doStart()} will be called at most one time
 283  
      * and will return without error if the component is already started.
 284  
      */
 285  
     public final void start() throws MuleException
 286  
     {
 287  0
         if (isStarted() || isStarting())
 288  
         {
 289  0
             return;
 290  
         }
 291  
 
 292  0
         if (!isConnected())
 293  
         {
 294  
             try
 295  
             {
 296  0
                 connect();
 297  
             }
 298  0
             catch (MuleException me)
 299  
             {
 300  0
                 throw me;
 301  
             }
 302  0
             catch (Exception e)
 303  
             {
 304  0
                 throw new ConnectException(e, this);
 305  0
             }
 306  
         }
 307  
 
 308  0
         lifecycleManager.fireStartPhase(new LifecycleCallback<O>()
 309  0
         {
 310  
             public void onTransition(String phaseName, O object) throws MuleException
 311  
             {
 312  0
                 doStart();
 313  0
             }
 314  
         });
 315  0
     }
 316  
 
 317  
     public final void stop() throws MuleException
 318  
     {
 319  0
         lifecycleManager.fireStopPhase(new LifecycleCallback<O>()
 320  0
         {
 321  
             public void onTransition(String phaseName, O object) throws MuleException
 322  
             {
 323  
                 try
 324  
                 {
 325  0
                     doStop();
 326  
                 }
 327  0
                 catch (MuleException e)
 328  
                 {
 329  0
                     logger.error(e.getMessage(), e);
 330  0
                 }
 331  0
             }
 332  
         });
 333  
 
 334  0
     }
 335  
 
 336  
     protected void doInitialise() throws InitialisationException
 337  
     {
 338  
         // nothing to do by default
 339  0
     }
 340  
 
 341  
     protected void doDispose()
 342  
     {
 343  
         // nothing to do by default
 344  0
     }
 345  
 
 346  
     protected void doConnect() throws Exception
 347  
     {
 348  
         // nothing to do by default
 349  0
     }
 350  
 
 351  
     protected void doDisconnect() throws Exception
 352  
     {
 353  
         // nothing to do by default
 354  0
     }
 355  
 
 356  
     protected void doStart() throws MuleException
 357  
     {
 358  
         // nothing to do by default
 359  0
     }
 360  
 
 361  
     protected void doStop() throws MuleException
 362  
     {
 363  
         // nothing to do by default
 364  0
     }
 365  
 
 366  
     @Override
 367  
     public String toString()
 368  
     {
 369  0
         final StringBuffer sb = new StringBuffer(80);
 370  0
         sb.append(ClassUtils.getSimpleName(this.getClass()));
 371  0
         sb.append("{this=").append(Integer.toHexString(System.identityHashCode(this)));
 372  0
         sb.append(", endpoint=").append(endpoint.getEndpointURI());
 373  0
         sb.append(", disposed=").append(getLifecycleState().isDisposed());
 374  0
         sb.append('}');
 375  0
         return sb.toString();
 376  
     }
 377  
 
 378  
     // TODO MULE-4871 Endpoint should not be mutable
 379  
 
 380  
     public void setEndpoint(ImmutableEndpoint endpoint)
 381  
     {
 382  0
         if (endpoint == null)
 383  
         {
 384  0
             throw new IllegalArgumentException("Endpoint cannot be null");
 385  
         }
 386  0
         this.endpoint = endpoint;
 387  0
     }
 388  
 
 389  
     abstract protected WorkManager getWorkManager() throws MuleException;
 390  
 
 391  
     public boolean isStarted()
 392  
     {
 393  0
         return getLifecycleState().isStarted();
 394  
     }
 395  
 
 396  
     public boolean isStarting()
 397  
     {
 398  0
         return getLifecycleState().isStarting();
 399  
     }
 400  
 
 401  
     public boolean isStopped()
 402  
     {
 403  0
         return getLifecycleState().isStopped();
 404  
     }
 405  
 
 406  
     public boolean isStopping()
 407  
     {
 408  0
         return getLifecycleState().isStopping();
 409  
     }
 410  
 
 411  
     /**
 412  
      * This method uses the connector's <code>createMuleMessageFactory</code> method to create
 413  
      * a new {@link MuleMessageFactory}. Subclasses may need to override this method in order to
 414  
      * perform additional initialization on the message factory before it's actually used.
 415  
      */
 416  
     protected MuleMessageFactory createMuleMessageFactory() throws CreateException
 417  
     {
 418  0
         return connector.createMuleMessageFactory();
 419  
     }
 420  
 
 421  
     /**
 422  
      * Uses this object's {@link MuleMessageFactory} to create a new {@link MuleMessage} instance.
 423  
      * The payload of the new message will be taken from <code>transportMessage</code>, all
 424  
      * message properties will be copied from <code>previousMessage</code>.
 425  
      */
 426  
     public MuleMessage createMuleMessage(Object transportMessage, MuleMessage previousMessage,
 427  
                                          String encoding) throws MuleException
 428  
     {
 429  
         try
 430  
         {
 431  0
             return muleMessageFactory.create(transportMessage, previousMessage, encoding);
 432  
         }
 433  0
         catch (Exception e)
 434  
         {
 435  0
             throw new CreateException(CoreMessages.failedToCreate("MuleMessage"), e);
 436  
         }
 437  
     }
 438  
 
 439  
     /**
 440  
      * Uses this object's {@link MuleMessageFactory} to create a new {@link MuleMessage} instance.
 441  
      * This is the designated way to build {@link MuleMessage}s from the transport specific message.
 442  
      */
 443  
     public MuleMessage createMuleMessage(Object transportMessage, String encoding) throws MuleException
 444  
     {
 445  
         try
 446  
         {
 447  0
             return muleMessageFactory.create(transportMessage, encoding);
 448  
         }
 449  0
         catch (Exception e)
 450  
         {
 451  0
             throw new CreateException(CoreMessages.failedToCreate("MuleMessage"), e, this);
 452  
         }
 453  
     }
 454  
 
 455  
     /**
 456  
      * Uses this object's {@link MuleMessageFactory} to create a new {@link MuleMessage} instance.
 457  
      * Uses the default encoding.
 458  
      *
 459  
      * @see MuleConfiguration#getDefaultEncoding()
 460  
      */
 461  
     public MuleMessage createMuleMessage(Object transportMessage) throws MuleException
 462  
     {
 463  0
         String encoding = endpoint.getMuleContext().getConfiguration().getDefaultEncoding();
 464  0
         return createMuleMessage(transportMessage, encoding);
 465  
     }
 466  
 
 467  
     /**
 468  
      * Uses this object's {@link MuleMessageFactory} to create a new {@link MuleMessage} instance.
 469  
      * Rather than passing in a transport message instance, {@link NullPayload} is used instead.
 470  
      * Uses the default encoding.
 471  
      */
 472  
     protected MuleMessage createNullMuleMessage() throws MuleException
 473  
     {
 474  0
         return createMuleMessage(null);
 475  
     }
 476  
 }