Coverage Report - org.mule.transport.SimpleRetryConnectionStrategy
 
Classes in this File Line Coverage Branch Coverage Complexity
SimpleRetryConnectionStrategy
0%
0/43
0%
0/16
2.4
SimpleRetryConnectionStrategy$RetryCounter
0%
0/6
N/A
2.4
 
 1  
 /*
 2  
  * $Id: SimpleRetryConnectionStrategy.java 10489 2008-01-23 17:53:38Z dfeist $
 3  
  * --------------------------------------------------------------------------------------
 4  
  * Copyright (c) MuleSource, Inc.  All rights reserved.  http://www.mulesource.com
 5  
  *
 6  
  * The software in this package is published under the terms of the CPAL v1.0
 7  
  * license, a copy of which has been included with this distribution in the
 8  
  * LICENSE.txt file.
 9  
  */
 10  
 
 11  
 package org.mule.transport;
 12  
 
 13  
 import org.mule.api.transport.Connectable;
 14  
 import org.mule.config.ExceptionHelper;
 15  
 import org.mule.config.i18n.CoreMessages;
 16  
 import org.mule.util.ObjectUtils;
 17  
 
 18  
 import edu.emory.mathcs.backport.java.util.concurrent.atomic.AtomicInteger;
 19  
 
 20  
 /**
 21  
  * A simple connection retry strategy where the a connection will be attempted X
 22  
  * number of retryCount every Y milliseconds. The <i>retryCount</i> and <i>frequency</i>
 23  
  * properties can be set to customise the behaviour.
 24  
  */
 25  
 
 26  0
 public class SimpleRetryConnectionStrategy extends AbstractConnectionStrategy
 27  
 {
 28  
     public static final int DEFAULT_FREQUENCY = 2000;
 29  
     public static final int DEFAULT_RETRY_COUNT = 2;
 30  
     public static final int RETRY_COUNT_FOREVER = -1;
 31  
 
 32  0
     protected static class RetryCounter extends ThreadLocal
 33  
     {
 34  
         public int countRetry()
 35  
         {
 36  0
             return ((AtomicInteger) get()).incrementAndGet();
 37  
         }
 38  
         
 39  
         public void reset()
 40  
         {
 41  0
             ((AtomicInteger) get()).set(0);
 42  0
         }
 43  
 
 44  
         //@Override
 45  
         public AtomicInteger current()
 46  
         {
 47  0
             return (AtomicInteger) get();
 48  
         }
 49  
 
 50  
         // @Override
 51  
         protected Object initialValue()
 52  
         {
 53  0
             return new AtomicInteger(0);
 54  
         }
 55  
     }
 56  
 
 57  0
     protected static final RetryCounter retryCounter = new RetryCounter();
 58  
 
 59  0
     protected static final ThreadLocal called = new ThreadLocal();
 60  
 
 61  0
     private volatile int retryCount = DEFAULT_RETRY_COUNT;
 62  0
     private volatile long retryFrequency = DEFAULT_FREQUENCY;
 63  
 
 64  
     protected void doConnect(Connectable connectable) throws FatalConnectException
 65  
     {
 66  
         while (true)
 67  
         {
 68  0
             final Boolean recursiveCallDetected = (Boolean) ObjectUtils.defaultIfNull(called.get(), Boolean.FALSE);
 69  0
             if (!recursiveCallDetected.booleanValue())
 70  
             {
 71  0
                 retryCounter.countRetry();
 72  
             }
 73  0
             called.set(Boolean.TRUE);
 74  
 
 75  
             try
 76  
             {
 77  0
                 connectable.connect();
 78  0
                 if (logger.isDebugEnabled())
 79  
                 {
 80  0
                     logger.debug("Successfully connected to " + getDescription(connectable));
 81  
                 }
 82  
                 break;
 83  
             }
 84  0
             catch (InterruptedException ie)
 85  
             {
 86  
                 // If we were interrupted it's probably because the server is
 87  
                 // shutting down
 88  0
                 throw new FatalConnectException(
 89  
                     // TODO it's not only endpoint that is reconnected, connectors too
 90  
                     CoreMessages.reconnectStrategyFailed(this.getClass(), 
 91  
                         this.getDescription(connectable)), ie, connectable);
 92  
             }
 93  0
             catch (Exception e)
 94  
             {
 95  0
                 if (e instanceof FatalConnectException)
 96  
                 {
 97  
                     // rethrow
 98  0
                     throw (FatalConnectException) e;
 99  
                 }
 100  0
                 if (retryCount != RETRY_COUNT_FOREVER && retryCounter.current().get() >= retryCount)
 101  
                 {
 102  0
                     throw new FatalConnectException(
 103  
                         // TODO it's not only endpoint that is reconnected, connectors too
 104  
                         CoreMessages.reconnectStrategyFailed(this.getClass(),
 105  
                             this.getDescription(connectable)), e, connectable);
 106  
                 }
 107  
 
 108  0
                 if (logger.isErrorEnabled())
 109  
                 {
 110  0
                     StringBuffer msg = new StringBuffer(512);
 111  0
                     msg.append("Failed to connect/reconnect: ").append(
 112  
                             getDescription(connectable));
 113  0
                     Throwable t = ExceptionHelper.getRootException(e);
 114  0
                     msg.append(". Root Exception was: ").append(ExceptionHelper.writeException(t));
 115  0
                     logger.error(msg.toString(), e);
 116  
                 }
 117  
 
 118  0
                 if (logger.isInfoEnabled())
 119  
                 {
 120  0
                     logger.info("Waiting for " + retryFrequency + "ms before reconnecting. Failed attempt "
 121  
                                 + retryCounter.current().get() + " of " +
 122  
                                 (retryCount != RETRY_COUNT_FOREVER ? String.valueOf(retryCount) : "unlimited"));
 123  
                 }
 124  
 
 125  
                 try
 126  
                 {
 127  0
                     Thread.sleep(retryFrequency);
 128  
                 }
 129  0
                 catch (InterruptedException e1)
 130  
                 {
 131  0
                     throw new FatalConnectException(
 132  
                         // TODO it's not only endpoint that is reconnected, connectors too
 133  
                         CoreMessages.reconnectStrategyFailed(this.getClass(), 
 134  
                             this.getDescription(connectable)), e, connectable);
 135  0
                 }
 136  
             }
 137  
             finally
 138  
             {
 139  0
                 called.set(Boolean.FALSE);
 140  0
             }
 141  0
         }
 142  0
     }
 143  
 
 144  
     /**
 145  
      * Resets any state stored in the retry strategy
 146  
      */
 147  
     public synchronized void resetState()
 148  
     {
 149  0
         retryCounter.reset();
 150  0
     }
 151  
 
 152  
     public int getRetryCount()
 153  
     {
 154  0
         return retryCount;
 155  
     }
 156  
 
 157  
     /**
 158  
      * How many times to retry. Set to -1 to retry forever.
 159  
      * @param retryCount number of retries
 160  
      */
 161  
     public void setRetryCount(int retryCount)
 162  
     {
 163  0
         this.retryCount = retryCount;
 164  0
     }
 165  
 
 166  
     public long getRetryFrequency()
 167  
     {
 168  0
         return retryFrequency;
 169  
     }
 170  
 
 171  
     public void setRetryFrequency(long retryFrequency)
 172  
     {
 173  0
         this.retryFrequency = retryFrequency;
 174  0
     }
 175  
 }