You are viewing a plain text version of this content. The canonical link for it is here.
Posted to server-dev@james.apache.org by sb...@apache.org on 2011/12/12 12:55:02 UTC

svn commit: r1213196 [1/2] - in /james/server/trunk/util: ./ src/main/java/org/apache/james/util/retry/ src/main/java/org/apache/james/util/retry/api/ src/main/java/org/apache/james/util/retry/naming/ src/main/java/org/apache/james/util/retry/naming/di...

Author: sbrewin
Date: Mon Dec 12 11:55:01 2011
New Revision: 1213196

URL: http://svn.apache.org/viewvc?rev=1213196&view=rev
Log:
JAMES-1352 Supporting utility classes implementing a generic retry mechanism

Added:
    james/server/trunk/util/src/main/java/org/apache/james/util/retry/
    james/server/trunk/util/src/main/java/org/apache/james/util/retry/DoublingRetrySchedule.java   (with props)
    james/server/trunk/util/src/main/java/org/apache/james/util/retry/ExceptionRetryHandler.java   (with props)
    james/server/trunk/util/src/main/java/org/apache/james/util/retry/api/
    james/server/trunk/util/src/main/java/org/apache/james/util/retry/api/ExceptionRetryingProxy.java   (with props)
    james/server/trunk/util/src/main/java/org/apache/james/util/retry/api/RetryHandler.java   (with props)
    james/server/trunk/util/src/main/java/org/apache/james/util/retry/api/RetrySchedule.java   (with props)
    james/server/trunk/util/src/main/java/org/apache/james/util/retry/naming/
    james/server/trunk/util/src/main/java/org/apache/james/util/retry/naming/LoggingRetryHandler.java   (with props)
    james/server/trunk/util/src/main/java/org/apache/james/util/retry/naming/NamingExceptionRetryHandler.java   (with props)
    james/server/trunk/util/src/main/java/org/apache/james/util/retry/naming/RetryingContext.java   (with props)
    james/server/trunk/util/src/main/java/org/apache/james/util/retry/naming/directory/
    james/server/trunk/util/src/main/java/org/apache/james/util/retry/naming/directory/RetryingDirContext.java   (with props)
    james/server/trunk/util/src/main/java/org/apache/james/util/retry/naming/ldap/
    james/server/trunk/util/src/main/java/org/apache/james/util/retry/naming/ldap/RetryingLdapContext.java   (with props)
    james/server/trunk/util/src/test/java/org/apache/james/util/retry/
    james/server/trunk/util/src/test/java/org/apache/james/util/retry/DoublingRetryScheduleTest.java   (with props)
    james/server/trunk/util/src/test/java/org/apache/james/util/retry/ExceptionRetryHandlerTest.java   (with props)
    james/server/trunk/util/src/test/java/org/apache/james/util/retry/naming/
    james/server/trunk/util/src/test/java/org/apache/james/util/retry/naming/NamingExceptionRetryHandlerTest.java   (with props)
Modified:
    james/server/trunk/util/pom.xml

Modified: james/server/trunk/util/pom.xml
URL: http://svn.apache.org/viewvc/james/server/trunk/util/pom.xml?rev=1213196&r1=1213195&r2=1213196&view=diff
==============================================================================
--- james/server/trunk/util/pom.xml (original)
+++ james/server/trunk/util/pom.xml Mon Dec 12 11:55:01 2011
@@ -51,6 +51,10 @@
             <artifactId>${javax.mail.artifactId}</artifactId>
         </dependency>
         <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-api</artifactId>
+        </dependency>        
+        <dependency>
             <groupId>junit</groupId>
             <artifactId>junit</artifactId>
             <scope>test</scope>

Added: james/server/trunk/util/src/main/java/org/apache/james/util/retry/DoublingRetrySchedule.java
URL: http://svn.apache.org/viewvc/james/server/trunk/util/src/main/java/org/apache/james/util/retry/DoublingRetrySchedule.java?rev=1213196&view=auto
==============================================================================
--- james/server/trunk/util/src/main/java/org/apache/james/util/retry/DoublingRetrySchedule.java (added)
+++ james/server/trunk/util/src/main/java/org/apache/james/util/retry/DoublingRetrySchedule.java Mon Dec 12 11:55:01 2011
@@ -0,0 +1,106 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+
+package org.apache.james.util.retry;
+
+import org.apache.james.util.retry.api.RetrySchedule;
+
+
+/**
+ * <code>DoublingRetrySchedule</code> is an implementation of <code>RetrySchedule</code> that
+ * returns the lesser of an interval that is double the proceeding interval and the maximum interval.
+ * 
+ * <p>When the initial interval is 0, the next interval is 1.
+ * 
+ * <p>A multiplier can be specified to scale the results.
+ */
+/**
+ * <code>DoublingRetrySchedule</code>
+ */
+public class DoublingRetrySchedule implements RetrySchedule {
+    
+    private long _startInterval = 0;
+    private long _maxInterval = 0;
+    private long _multiplier = 1;
+
+    /**
+     * Creates a new instance of DoublingRetrySchedule.
+     *
+     */
+    private DoublingRetrySchedule() {
+    }
+    
+    /**
+     * Creates a new instance of DoublingRetrySchedule.
+     *
+     * @param startInterval
+     *      The interval for an index of 0
+     * @param maxInterval
+     *      The maximum interval for any index
+     */
+    public DoublingRetrySchedule(long startInterval, long maxInterval) {
+        this(startInterval, maxInterval, 1);
+    }
+    
+    /**
+     * Creates a new instance of DoublingRetrySchedule.
+     *
+     * @param startInterval
+     *      The interval for an index of 0
+     * @param maxInterval
+     *      The maximum interval for any index
+     * @param multiplier
+     *      The multiplier to apply to the result
+     */
+    public DoublingRetrySchedule(long startInterval, long maxInterval, int multiplier) {
+        this();
+        _startInterval = Math.max(0, startInterval);
+        _maxInterval = Math.max(0, maxInterval);
+        _multiplier = Math.max(1, multiplier);
+    }
+
+    /**
+     * @see org.apache.james.user.ldap.api.RetrySchedule#getInterval(int)
+     */
+    @Override
+    public long getInterval(int index) {
+        if (_startInterval > 0)
+        {
+            return getInterval(index, _startInterval);
+        }
+        return index == 0 ? 0 : getInterval(index - 1, 1);
+    }
+    
+    private long getInterval(int index, long startInterval) {
+        return _multiplier * Math.min((long) (startInterval * Math.pow(2, index)), _maxInterval);
+    }    
+
+    /**
+     * @see java.lang.Object#toString()
+     */
+    @Override
+    public String toString() {
+        StringBuilder builder = new StringBuilder();
+        builder.append("DoublingRetrySchedule [startInterval=").append(_startInterval).append(
+                ", maxInterval=").append(_maxInterval).append(", multiplier=").append(_multiplier).append("]");
+        return builder.toString();
+    }
+
+}

Propchange: james/server/trunk/util/src/main/java/org/apache/james/util/retry/DoublingRetrySchedule.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: james/server/trunk/util/src/main/java/org/apache/james/util/retry/DoublingRetrySchedule.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: james/server/trunk/util/src/main/java/org/apache/james/util/retry/ExceptionRetryHandler.java
URL: http://svn.apache.org/viewvc/james/server/trunk/util/src/main/java/org/apache/james/util/retry/ExceptionRetryHandler.java?rev=1213196&view=auto
==============================================================================
--- james/server/trunk/util/src/main/java/org/apache/james/util/retry/ExceptionRetryHandler.java (added)
+++ james/server/trunk/util/src/main/java/org/apache/james/util/retry/ExceptionRetryHandler.java Mon Dec 12 11:55:01 2011
@@ -0,0 +1,140 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+
+package org.apache.james.util.retry;
+
+import org.apache.james.util.retry.api.ExceptionRetryingProxy;
+import org.apache.james.util.retry.api.RetryHandler;
+import org.apache.james.util.retry.api.RetrySchedule;
+
+/**
+ * Abstract class <code>ExceptionRetryHandler</code> retries the behaviour defined in abstract method 
+ * <code>operation()</code> implemented in a concrete subclass when nominated subclasses of <code>Exception</code>
+ * are thrown. The intervals between retries are defined by a <code>RetrySchedule</code>.
+ * <p>
+ * Concrete subclasses are proxies that forward work via the <code>operation()</code> to a delegate
+ * instance for which retry behaviour is required. Both the proxy and the delegate implement the
+ * same interfaces. 
+ * <p>
+ * The method stubs required to perform the proxy call via <code>operation()</code> may be generated by many means,
+ * including explicit code, a <code>DynamicProxy</code> and compile time aspect injection.
+ *
+ * @see org.apache.james.util.retry.naming.RetryingContext
+ */
+abstract public class ExceptionRetryHandler implements RetryHandler {
+    private Class<?>[] _exceptionClasses = null;
+    
+        private ExceptionRetryingProxy _proxy = null;
+        private RetrySchedule _schedule;
+        private int _maxRetries = 0;
+
+        /**
+         * Creates a new instance of ExceptionRetryHandler.
+         *
+         */
+        private ExceptionRetryHandler() {
+            super();
+        }
+
+
+        /**
+         * Creates a new instance of ExceptionRetryHandler.
+         *
+         * @param exceptionClasses
+         * @param proxy
+         * @param maxRetries
+         */
+        public ExceptionRetryHandler(Class<?>[] exceptionClasses, ExceptionRetryingProxy proxy, RetrySchedule schedule, int maxRetries) {
+            this();
+            _exceptionClasses = exceptionClasses;
+            _proxy = proxy;
+            _schedule = schedule;
+            _maxRetries = maxRetries;
+        }
+
+        /**
+         * @see org.apache.james.user.ldap.api.RetryHandler#perform()
+         */
+        public Object perform() throws Exception {
+            boolean success = false;
+            Object result = null;
+            int retryCount = 0;
+            while (!success) {
+                try {
+                    if (retryCount > 0) {
+                        _proxy.resetDelegate();
+                    }
+                    result = operation();
+                    success = true;
+
+                }
+                catch (Exception ex) {
+                    if (retryCount >= _maxRetries || !isRetryable(ex)) {
+                        throw ex;
+                    }
+                    postFailure(ex, retryCount);
+                    try {
+                        Thread.sleep(getRetryInterval(retryCount));
+                    } catch (InterruptedException ex1) {
+                        // no-op
+                    }
+                    retryCount = _maxRetries < 0 ? _maxRetries
+                            : retryCount + 1;
+                }
+            }
+            return result;
+        }
+        
+        /**
+         * @param ex
+         * The <code>Throwable</code> to test
+         * 
+         * @return true if the array of exception classes contains <strong>ex</strong>
+         */
+        private boolean isRetryable(Throwable ex)
+        {
+            boolean isRetryable = false;
+            for (int i = 0; !isRetryable && i < _exceptionClasses.length; i++ )
+            {
+                isRetryable = _exceptionClasses[i].isInstance(ex);
+            }
+            return isRetryable;
+        }
+        
+        /**
+         * @see org.apache.james.user.ldap.api.RetryHandler#postFailure(javax.naming.NamingException, int)
+         */
+        public void postFailure(Exception ex, int retryCount)
+        {
+            // no-op
+        }        
+
+        /**
+         * @see org.apache.james.user.ldap.api.RetryHandler#operation()
+         */
+        abstract public Object operation() throws Exception;
+        
+        /**
+         * @return the retryInterval
+         */
+        public long getRetryInterval(int retryCount) {
+            return _schedule.getInterval(retryCount);
+        }
+}

Propchange: james/server/trunk/util/src/main/java/org/apache/james/util/retry/ExceptionRetryHandler.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: james/server/trunk/util/src/main/java/org/apache/james/util/retry/ExceptionRetryHandler.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: james/server/trunk/util/src/main/java/org/apache/james/util/retry/api/ExceptionRetryingProxy.java
URL: http://svn.apache.org/viewvc/james/server/trunk/util/src/main/java/org/apache/james/util/retry/api/ExceptionRetryingProxy.java?rev=1213196&view=auto
==============================================================================
--- james/server/trunk/util/src/main/java/org/apache/james/util/retry/api/ExceptionRetryingProxy.java (added)
+++ james/server/trunk/util/src/main/java/org/apache/james/util/retry/api/ExceptionRetryingProxy.java Mon Dec 12 11:55:01 2011
@@ -0,0 +1,49 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+
+package org.apache.james.util.retry.api;
+
+
+/**
+ * <code>ExceptionRetryingProxy</code> defines the behaviour for a
+ * proxy that can retry <codeException</code> and its subclasses.
+ */
+public interface ExceptionRetryingProxy {
+    /**
+     * @return a new instance that the proxy delegates to
+     * @throws Exception
+     */
+    abstract public Object newDelegate() throws Exception;
+    
+    /**
+     * @return the current instance of the proxy delegate
+     * @throws Exception
+     */
+    abstract public Object getDelegate() throws Exception;
+    
+    /**
+     * Resets the delegate instance to a state from which it can perform the 
+     * operations delegated to it.
+     *
+     * @throws Exception
+     */
+    abstract public void resetDelegate() throws Exception;
+
+}

Propchange: james/server/trunk/util/src/main/java/org/apache/james/util/retry/api/ExceptionRetryingProxy.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: james/server/trunk/util/src/main/java/org/apache/james/util/retry/api/ExceptionRetryingProxy.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: james/server/trunk/util/src/main/java/org/apache/james/util/retry/api/RetryHandler.java
URL: http://svn.apache.org/viewvc/james/server/trunk/util/src/main/java/org/apache/james/util/retry/api/RetryHandler.java?rev=1213196&view=auto
==============================================================================
--- james/server/trunk/util/src/main/java/org/apache/james/util/retry/api/RetryHandler.java (added)
+++ james/server/trunk/util/src/main/java/org/apache/james/util/retry/api/RetryHandler.java Mon Dec 12 11:55:01 2011
@@ -0,0 +1,52 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+
+package org.apache.james.util.retry.api;
+
+
+/**
+ * <code>RetryHandler</code>
+ */
+public interface RetryHandler {
+
+    /**
+     * @return the result of invoking an operation
+     * @throws Exception
+     */
+    public abstract Object perform() throws Exception;
+
+    /**
+     * A hook invoked each time an operation fails if a retry is scheduled
+     *
+     * @param ex
+     *      The <code>Exception</code> thrown when the operation was invoked
+     * @param retryCount
+     *      The number of times  
+     */
+    public abstract void postFailure(Exception ex, int retryCount);
+
+    /**
+     * Encapsulates desired behaviour
+     * @return The result of performing the behaviour
+     * @throws Exception
+     */
+    abstract public Object operation() throws Exception;
+
+}
\ No newline at end of file

Propchange: james/server/trunk/util/src/main/java/org/apache/james/util/retry/api/RetryHandler.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: james/server/trunk/util/src/main/java/org/apache/james/util/retry/api/RetryHandler.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: james/server/trunk/util/src/main/java/org/apache/james/util/retry/api/RetrySchedule.java
URL: http://svn.apache.org/viewvc/james/server/trunk/util/src/main/java/org/apache/james/util/retry/api/RetrySchedule.java?rev=1213196&view=auto
==============================================================================
--- james/server/trunk/util/src/main/java/org/apache/james/util/retry/api/RetrySchedule.java (added)
+++ james/server/trunk/util/src/main/java/org/apache/james/util/retry/api/RetrySchedule.java Mon Dec 12 11:55:01 2011
@@ -0,0 +1,35 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+
+package org.apache.james.util.retry.api;
+
+/**
+ * <code>RetrySchedule</code>
+ */
+public interface RetrySchedule {
+    /**
+     * Returns the interval time in milliseconds at the specified zero based index.
+     *
+     * @param index
+     * @return
+     */
+    public long getInterval(int index);
+
+}

Propchange: james/server/trunk/util/src/main/java/org/apache/james/util/retry/api/RetrySchedule.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: james/server/trunk/util/src/main/java/org/apache/james/util/retry/api/RetrySchedule.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: james/server/trunk/util/src/main/java/org/apache/james/util/retry/naming/LoggingRetryHandler.java
URL: http://svn.apache.org/viewvc/james/server/trunk/util/src/main/java/org/apache/james/util/retry/naming/LoggingRetryHandler.java?rev=1213196&view=auto
==============================================================================
--- james/server/trunk/util/src/main/java/org/apache/james/util/retry/naming/LoggingRetryHandler.java (added)
+++ james/server/trunk/util/src/main/java/org/apache/james/util/retry/naming/LoggingRetryHandler.java Mon Dec 12 11:55:01 2011
@@ -0,0 +1,67 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+
+package org.apache.james.util.retry.naming;
+
+import javax.naming.NamingException;
+
+import org.apache.james.util.retry.api.ExceptionRetryingProxy;
+import org.apache.james.util.retry.api.RetrySchedule;
+import org.slf4j.Logger;
+
+/**
+ * Abstract class <code>LoggingRetryHandler</code> implements logging of failures 
+ */
+abstract public class LoggingRetryHandler extends NamingExceptionRetryHandler {
+    
+    private Logger _logger = null;
+
+    /**
+     * Creates a new instance of LoggingRetryHandler.
+     *
+     * @param exceptionClasses
+     * @param proxy
+     * @param maxRetries
+     * @param retryInterval
+     * @param logger
+     */
+    public LoggingRetryHandler(Class<?>[] exceptionClasses, ExceptionRetryingProxy proxy,
+            RetrySchedule schedule, int maxRetries, Logger logger) {
+        super(exceptionClasses, proxy, schedule, maxRetries);
+        _logger = logger;
+    }
+
+    /**
+     * @see org.apache.james.user.ldap.AbstractRetryHandler1#postFailure(javax.naming.NamingException, int)
+     */
+    @Override
+    public void postFailure(NamingException ex, int retryCount) {
+        super.postFailure(ex, retryCount);
+        _logger.info(
+                new StringBuilder("Retry failure: ").
+                append(ex.getLocalizedMessage()).
+                append("\n Retrying in ").
+                append(getRetryInterval(retryCount)/1000).
+                append(" seconds").
+                toString()
+                );
+    }
+
+}

Propchange: james/server/trunk/util/src/main/java/org/apache/james/util/retry/naming/LoggingRetryHandler.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: james/server/trunk/util/src/main/java/org/apache/james/util/retry/naming/LoggingRetryHandler.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: james/server/trunk/util/src/main/java/org/apache/james/util/retry/naming/NamingExceptionRetryHandler.java
URL: http://svn.apache.org/viewvc/james/server/trunk/util/src/main/java/org/apache/james/util/retry/naming/NamingExceptionRetryHandler.java?rev=1213196&view=auto
==============================================================================
--- james/server/trunk/util/src/main/java/org/apache/james/util/retry/naming/NamingExceptionRetryHandler.java (added)
+++ james/server/trunk/util/src/main/java/org/apache/james/util/retry/naming/NamingExceptionRetryHandler.java Mon Dec 12 11:55:01 2011
@@ -0,0 +1,79 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+
+package org.apache.james.util.retry.naming;
+
+import javax.naming.NamingException;
+
+import org.apache.james.util.retry.ExceptionRetryHandler;
+import org.apache.james.util.retry.api.ExceptionRetryingProxy;
+import org.apache.james.util.retry.api.RetrySchedule;
+
+/**
+ * Abstract class <code>NamingExceptionRetryHandler</code> narrows the set of Exceptions throwable 
+ * by <code>perform</code> to <code>NamingException</code> and its subclasses.
+ * <p><code>RuntimeException</code>s are <strong>not</strong> retried.
+ * 
+ * @see org.apache.james.user.ldap.ExceptionRetryHandler
+ * 
+ */
+abstract public class NamingExceptionRetryHandler extends ExceptionRetryHandler {
+
+    /**
+     * Creates a new instance of NamingExceptionRetryHandler.
+     *
+     * @param exceptionClasses
+     * @param proxy
+     * @param schedule
+     * @param maxRetries
+     */
+    public NamingExceptionRetryHandler(Class<?>[] exceptionClasses, ExceptionRetryingProxy proxy,
+            RetrySchedule schedule, int maxRetries) {
+        super(exceptionClasses, proxy, schedule, maxRetries);
+    }
+
+    /**
+     * @see org.apache.james.user.ldap.ExceptionRetryHandler#perform()
+     */
+    @Override
+    public Object perform() throws NamingException {
+        try {
+            return super.perform();
+        } catch (RuntimeException ex) {
+            throw ex;
+        } catch (Exception ex) {
+            // Should only ever be a NamingException
+            throw ((NamingException) ex);
+        }
+    }
+
+    /**
+     * @see org.apache.james.user.ldap.api.RetryHandler#postFailure(java.lang.Exception, int)
+     */
+    @Override
+    public void postFailure(Exception ex, int retryCount) {
+        postFailure(((NamingException) ex), retryCount);        
+    }
+
+    public void postFailure(NamingException ex, int retryCount)
+    {
+        // no-op
+    }
+}

Propchange: james/server/trunk/util/src/main/java/org/apache/james/util/retry/naming/NamingExceptionRetryHandler.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: james/server/trunk/util/src/main/java/org/apache/james/util/retry/naming/NamingExceptionRetryHandler.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: james/server/trunk/util/src/main/java/org/apache/james/util/retry/naming/RetryingContext.java
URL: http://svn.apache.org/viewvc/james/server/trunk/util/src/main/java/org/apache/james/util/retry/naming/RetryingContext.java?rev=1213196&view=auto
==============================================================================
--- james/server/trunk/util/src/main/java/org/apache/james/util/retry/naming/RetryingContext.java (added)
+++ james/server/trunk/util/src/main/java/org/apache/james/util/retry/naming/RetryingContext.java Mon Dec 12 11:55:01 2011
@@ -0,0 +1,602 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+
+package org.apache.james.util.retry.naming;
+
+import java.util.Hashtable;
+
+import javax.naming.Binding;
+import javax.naming.CommunicationException;
+import javax.naming.Context;
+import javax.naming.Name;
+import javax.naming.NameClassPair;
+import javax.naming.NameParser;
+import javax.naming.NamingEnumeration;
+import javax.naming.NamingException;
+import javax.naming.ServiceUnavailableException;
+
+import org.apache.james.util.retry.api.ExceptionRetryingProxy;
+import org.apache.james.util.retry.api.RetrySchedule;
+import org.slf4j.Logger;
+
+/**
+ * <code>RetryingContext</code> retries the methods defined by <code>javax.naming.Context</code>
+ * according to the specified schedule. 
+ * 
+ * @see org.apache.james.util.retry.ExceptionRetryHandler
+ * @see org.apache.james.util.retry.api.ExceptionRetryingProxy
+ * @see javax.naming.Context
+ */
+abstract public class RetryingContext implements Context, ExceptionRetryingProxy {
+
+    static public final Class<?>[] DEFAULT_EXCEPTION_CLASSES = new Class<?>[] {
+            CommunicationException.class,
+            ServiceUnavailableException.class };
+
+    private Context _delegate = null;
+    private RetrySchedule _schedule = null;
+    private int _maxRetries = 0;
+    private Logger _logger = null;
+
+    /**
+     * Creates a new instance of RetryingContext.
+     * 
+     * @throws NamingException
+     * 
+     */
+    private RetryingContext() throws NamingException {
+        super();
+    }
+    
+    /**
+     * Creates a new instance of RetryingContext using the default exception
+     * classes thrown when an external interruption to services on which we
+     * depend occurs.
+     * 
+     * @param schedule
+     * @param maxRetries
+     * @param logger
+     * @throws NamingException
+     */
+    public RetryingContext(final RetrySchedule schedule, final int maxRetries, final Logger logger)
+            throws NamingException {
+        this(DEFAULT_EXCEPTION_CLASSES, schedule, maxRetries, logger);
+    }
+
+    /**
+     * Creates a new instance of RetryingContext.
+     *
+     * @param exceptionClasses
+     * @param schedule
+     * @param maxRetries
+     * @param logger
+     * @throws NamingException
+     */
+    public RetryingContext(final Class<?>[] exceptionClasses, final RetrySchedule schedule, final int maxRetries, final Logger logger)
+            throws NamingException {
+        this();
+        _schedule = schedule;
+        _maxRetries = maxRetries;
+        _logger = logger;
+        _delegate = (Context) new LoggingRetryHandler(exceptionClasses, this,
+                _schedule, _maxRetries,  _logger) {
+
+            @Override
+            public Object operation() throws Exception {
+                return newDelegate();
+            }
+        }.perform();
+    }
+
+    /**
+     * @see javax.naming.Context#addToEnvironment(java.lang.String,
+     *      java.lang.Object)
+     */
+    @Override
+    public Object addToEnvironment(final String propName, final Object propVal)
+            throws NamingException {
+        return new LoggingRetryHandler(DEFAULT_EXCEPTION_CLASSES, this, _schedule, _maxRetries,
+                 _logger) {
+
+            @Override
+            public Object operation() throws NamingException {
+                return getDelegate().addToEnvironment(propName, propVal);
+            }
+        }.perform();
+    }
+
+    /**
+     * @see javax.naming.Context#bind(javax.naming.Name, java.lang.Object)
+     */
+    @Override
+    public void bind(final Name name, final Object obj) throws NamingException {
+        new LoggingRetryHandler(DEFAULT_EXCEPTION_CLASSES, this, _schedule, _maxRetries, 
+                _logger) {
+
+            @Override
+            public Object operation() throws NamingException {
+                getDelegate().bind(name, obj);
+                return null;
+            }
+        }.perform();
+    }
+
+    /**
+     * @see javax.naming.Context#bind(java.lang.String, java.lang.Object)
+     */
+    @Override
+    public void bind(final String name, final Object obj) throws NamingException {
+        new LoggingRetryHandler(DEFAULT_EXCEPTION_CLASSES, this, _schedule, _maxRetries, 
+                _logger) {
+
+            @Override
+            public Object operation() throws NamingException {
+                getDelegate().bind(name, obj);
+                return null;
+            }
+        }.perform();
+    }
+
+    /**
+     * @see javax.naming.Context#close()
+     */
+    @Override
+    public void close() throws NamingException {
+        new LoggingRetryHandler(DEFAULT_EXCEPTION_CLASSES, this, _schedule, _maxRetries, 
+                _logger) {
+
+            @Override
+            public Object operation() throws NamingException {
+                getDelegate().close();
+                return null;
+            }
+        }.perform();
+    }
+
+    /**
+     * @see javax.naming.Context#composeName(javax.naming.Name,
+     *      javax.naming.Name)
+     */
+    @Override
+    public Name composeName(final Name name, final Name prefix) throws NamingException {
+        return (Name) new LoggingRetryHandler(DEFAULT_EXCEPTION_CLASSES, this, _schedule, _maxRetries,
+                 _logger) {
+
+            @Override
+            public Object operation() throws NamingException {
+                return getDelegate().composeName(name, prefix);
+            }
+        }.perform();
+    }
+
+    /**
+     * @see javax.naming.Context#composeName(java.lang.String, java.lang.String)
+     */
+    @Override
+    public String composeName(final String name, final String prefix) throws NamingException {
+        return (String) new LoggingRetryHandler(DEFAULT_EXCEPTION_CLASSES, this, _schedule, _maxRetries,
+                 _logger) {
+
+            @Override
+            public Object operation() throws NamingException {
+                return getDelegate().composeName(name, prefix);
+            }
+        }.perform();
+    }
+
+    /**
+     * @see javax.naming.Context#createSubcontext(javax.naming.Name)
+     */
+    @Override
+    public Context createSubcontext(final Name name) throws NamingException {
+        final Context context = getDelegate();
+        return new RetryingContext(getSchedule(), getMaxRetries(), getLogger()) {
+
+            @Override
+            public Context newDelegate() throws NamingException {
+                return context.createSubcontext(name);
+            }
+        };
+    }
+
+    /**
+     * @see javax.naming.Context#createSubcontext(java.lang.String)
+     */
+    @Override
+    public Context createSubcontext(final String name) throws NamingException {
+        final Context context = getDelegate();
+        return new RetryingContext( getSchedule(), getMaxRetries(), getLogger()) {
+
+            @Override
+            public Context newDelegate() throws NamingException {
+                return context.createSubcontext(name);
+            }
+        };
+    }
+
+    /**
+     * @return
+     * @see javax.naming.Context#destroySubcontext(javax.naming.Name)
+     */
+    @Override
+    public void destroySubcontext(final Name name) throws NamingException {
+        new LoggingRetryHandler(DEFAULT_EXCEPTION_CLASSES, this, _schedule, _maxRetries, 
+                _logger) {
+
+            @Override
+            public Object operation() throws NamingException {
+                getDelegate().destroySubcontext(name);
+                return null;
+            }
+        }.perform();
+    }
+
+    /**
+     * @see javax.naming.Context#destroySubcontext(java.lang.String)
+     */
+    @Override
+    public void destroySubcontext(final String name) throws NamingException {
+        new LoggingRetryHandler(DEFAULT_EXCEPTION_CLASSES, this, _schedule, _maxRetries, 
+                _logger) {
+
+            @Override
+            public Object operation() throws NamingException {
+                getDelegate().destroySubcontext(name);
+                return null;
+            }
+        }.perform();
+    }
+
+    /**
+     * @see javax.naming.Context#getEnvironment()
+     */
+    @Override
+    public Hashtable<?, ?> getEnvironment() throws NamingException {
+        return (Hashtable<?, ?>) new LoggingRetryHandler(DEFAULT_EXCEPTION_CLASSES, this,
+                _schedule, _maxRetries,  _logger) {
+
+            @Override
+            public Object operation() throws NamingException {
+                return getDelegate().getEnvironment();
+            }
+        }.perform();
+    }
+
+    /**
+     * @see javax.naming.Context#getNameInNamespace()
+     */
+    @Override
+    public String getNameInNamespace() throws NamingException {
+        return (String) new LoggingRetryHandler(DEFAULT_EXCEPTION_CLASSES, this, _schedule, _maxRetries,
+                 _logger) {
+
+            @Override
+            public Object operation() throws NamingException {
+                return getDelegate().getNameInNamespace();
+            }
+        }.perform();
+    }
+
+    /**
+     * @see javax.naming.Context#getNameParser(javax.naming.Name)
+     */
+    @Override
+    public NameParser getNameParser(final Name name) throws NamingException {
+        return (NameParser) new LoggingRetryHandler(DEFAULT_EXCEPTION_CLASSES, this, _schedule, _maxRetries,
+                 _logger) {
+
+            @Override
+            public Object operation() throws NamingException {
+                return getDelegate().getNameParser(name);
+            }
+        }.perform();
+    }
+
+    /**
+     * @see javax.naming.Context#getNameParser(java.lang.String)
+     */
+    @Override
+    public NameParser getNameParser(final String name) throws NamingException {
+        return (NameParser) new LoggingRetryHandler(DEFAULT_EXCEPTION_CLASSES, this, _schedule, _maxRetries,
+                 _logger) {
+
+            @Override
+            public Object operation() throws NamingException {
+                return getDelegate().getNameParser(name);
+            }
+        }.perform();
+    }
+
+    /**
+     * @see javax.naming.Context#list(javax.naming.Name)
+     */
+    @SuppressWarnings("unchecked")
+    @Override
+    public NamingEnumeration<NameClassPair> list(final Name name) throws NamingException {
+        return (NamingEnumeration<NameClassPair>) new LoggingRetryHandler(
+                DEFAULT_EXCEPTION_CLASSES, this, _schedule, _maxRetries,  _logger) {
+
+            @Override
+            public Object operation() throws NamingException {
+                return getDelegate().list(name);
+            }
+        }.perform();
+    }
+
+    /**
+     * @see javax.naming.Context#list(java.lang.String)
+     */
+    @SuppressWarnings("unchecked")
+    @Override
+    public NamingEnumeration<NameClassPair> list(final String name) throws NamingException {
+        return (NamingEnumeration<NameClassPair>) new LoggingRetryHandler(
+                DEFAULT_EXCEPTION_CLASSES, this, _schedule, _maxRetries,  _logger) {
+
+            @Override
+            public Object operation() throws NamingException {
+                return getDelegate().list(name);
+            }
+        }.perform();
+    }
+
+    /**
+     * @see javax.naming.Context#listBindings(javax.naming.Name)
+     */
+    @SuppressWarnings("unchecked")
+    @Override
+    public NamingEnumeration<Binding> listBindings(final Name name) throws NamingException {
+        return (NamingEnumeration<Binding>) new LoggingRetryHandler(DEFAULT_EXCEPTION_CLASSES,
+                this, _schedule, _maxRetries,  _logger) {
+
+            @Override
+            public Object operation() throws NamingException {
+                return getDelegate().listBindings(name);
+            }
+        }.perform();
+    }
+
+    /**
+     * @see javax.naming.Context#listBindings(java.lang.String)
+     */
+    @SuppressWarnings("unchecked")
+    @Override
+    public NamingEnumeration<Binding> listBindings(final String name) throws NamingException {
+        return (NamingEnumeration<Binding>) new LoggingRetryHandler(DEFAULT_EXCEPTION_CLASSES,
+                this, _schedule, _maxRetries,  _logger) {
+
+            @Override
+            public Object operation() throws NamingException {
+                return getDelegate().listBindings(name);
+            }
+        }.perform();
+    }
+
+    /**
+     * @see javax.naming.Context#lookup(javax.naming.Name)
+     */
+    @Override
+    public Object lookup(final Name name) throws NamingException {
+        return new LoggingRetryHandler(DEFAULT_EXCEPTION_CLASSES, this, _schedule, _maxRetries,
+                 _logger) {
+
+            @Override
+            public Object operation() throws NamingException {
+                return getDelegate().lookup(name);
+            }
+        }.perform();
+    }
+
+    /**
+     * @see javax.naming.Context#lookup(java.lang.String)
+     */
+    @Override
+    public Object lookup(final String name) throws NamingException {
+        return new LoggingRetryHandler(DEFAULT_EXCEPTION_CLASSES, this, _schedule, _maxRetries,
+                 _logger) {
+
+            @Override
+            public Object operation() throws NamingException {
+                return getDelegate().lookup(name);
+            }
+        }.perform();
+    }
+
+    /**
+     * @see javax.naming.Context#lookupLink(javax.naming.Name)
+     */
+    @Override
+    public Object lookupLink(final Name name) throws NamingException {
+        return new LoggingRetryHandler(DEFAULT_EXCEPTION_CLASSES, this, _schedule, _maxRetries,
+                 _logger) {
+
+            @Override
+            public Object operation() throws NamingException {
+                return getDelegate().lookupLink(name);
+            }
+        }.perform();
+    }
+
+    /**
+     * @see javax.naming.Context#lookupLink(java.lang.String)
+     */
+    @Override
+    public Object lookupLink(final String name) throws NamingException {
+        return new LoggingRetryHandler(DEFAULT_EXCEPTION_CLASSES, this, _schedule, _maxRetries,
+                 _logger) {
+
+            @Override
+            public Object operation() throws NamingException {
+                return getDelegate().lookupLink(name);
+            }
+        }.perform();
+    }
+
+    /**
+     * @see javax.naming.Context#rebind(javax.naming.Name, java.lang.Object)
+     */
+    @Override
+    public void rebind(final Name name, final Object obj) throws NamingException {
+        new LoggingRetryHandler(DEFAULT_EXCEPTION_CLASSES, this, _schedule, _maxRetries, 
+                _logger) {
+
+            @Override
+            public Object operation() throws NamingException {
+                getDelegate().rebind(name, obj);
+                return null;
+            }
+        }.perform();
+    }
+
+    /**
+     * @see javax.naming.Context#rebind(java.lang.String, java.lang.Object)
+     */
+    @Override
+    public void rebind(final String name, final Object obj) throws NamingException {
+        new LoggingRetryHandler(DEFAULT_EXCEPTION_CLASSES, this, _schedule, _maxRetries, 
+                _logger) {
+
+            @Override
+            public Object operation() throws NamingException {
+                getDelegate().rebind(name, obj);
+                return null;
+            }
+        }.perform();
+    }
+
+    /**
+     * @see javax.naming.Context#removeFromEnvironment(java.lang.String)
+     */
+    @Override
+    public Object removeFromEnvironment(final String propName) throws NamingException {
+        return new LoggingRetryHandler(DEFAULT_EXCEPTION_CLASSES, this, _schedule, _maxRetries,
+                 _logger) {
+
+            @Override
+            public Object operation() throws NamingException {
+                return getDelegate().removeFromEnvironment(propName);
+            }
+        }.perform();
+    }
+
+    /**
+     * @see javax.naming.Context#rename(javax.naming.Name, javax.naming.Name)
+     */
+    @Override
+    public void rename(final Name oldName, final Name newName) throws NamingException {
+        new LoggingRetryHandler(DEFAULT_EXCEPTION_CLASSES, this, _schedule, _maxRetries, 
+                _logger) {
+
+            @Override
+            public Object operation() throws NamingException {
+                getDelegate().rename(oldName, newName);
+                return null;
+            }
+        }.perform();
+    }
+
+    /**
+     * @see javax.naming.Context#rename(java.lang.String, java.lang.String)
+     */
+    @Override
+    public void rename(final String oldName, final String newName) throws NamingException {
+        new LoggingRetryHandler(DEFAULT_EXCEPTION_CLASSES, this, _schedule, _maxRetries, 
+                _logger) {
+
+            @Override
+            public Object operation() throws NamingException {
+                getDelegate().rename(oldName, newName);
+                return null;
+            }
+        }.perform();
+    }
+
+    /**
+     * @see javax.naming.Context#unbind(javax.naming.Name)
+     */
+    @Override
+    public void unbind(final Name name) throws NamingException {
+        new LoggingRetryHandler(DEFAULT_EXCEPTION_CLASSES, this, _schedule, _maxRetries, 
+                _logger) {
+
+            @Override
+            public Object operation() throws NamingException {
+                getDelegate().unbind(name);
+                return null;
+            }
+        }.perform();
+    }
+
+    /**
+     * @see javax.naming.Context#unbind(java.lang.String)
+     */
+    @Override
+    public void unbind(final String name) throws NamingException {
+        new LoggingRetryHandler(DEFAULT_EXCEPTION_CLASSES, this, _schedule, _maxRetries, 
+                _logger) {
+
+            @Override
+            public Object operation() throws NamingException {
+                getDelegate().unbind(name);
+                return null;
+            }
+        }.perform();
+    }
+
+    /**
+     * @see org.apache.james.user.ldap.api.ExceptionRetryingProxy#getDelegate()
+     */
+    public Context getDelegate() {
+        return _delegate;
+    }
+    
+    
+    /**
+     * @see org.apache.james.user.ldap.api.ExceptionRetryingProxy#resetDelegate()
+     */
+    @Override
+    public void resetDelegate() throws Exception {
+        if (null != _delegate) {
+            _delegate.close();
+        }
+        _delegate = (Context)newDelegate();
+    }
+   
+    /**
+     * @return the schedule
+     */
+    public RetrySchedule getSchedule() {
+        return _schedule;
+    }
+    
+    /**
+     * @return the maxRetries
+     */
+    public int getMaxRetries() {
+        return _maxRetries;
+    }
+
+    /**
+     * @return the logger
+     */
+    public Logger getLogger() {
+        return _logger;
+    }
+
+}

Propchange: james/server/trunk/util/src/main/java/org/apache/james/util/retry/naming/RetryingContext.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: james/server/trunk/util/src/main/java/org/apache/james/util/retry/naming/RetryingContext.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: james/server/trunk/util/src/main/java/org/apache/james/util/retry/naming/directory/RetryingDirContext.java
URL: http://svn.apache.org/viewvc/james/server/trunk/util/src/main/java/org/apache/james/util/retry/naming/directory/RetryingDirContext.java?rev=1213196&view=auto
==============================================================================
--- james/server/trunk/util/src/main/java/org/apache/james/util/retry/naming/directory/RetryingDirContext.java (added)
+++ james/server/trunk/util/src/main/java/org/apache/james/util/retry/naming/directory/RetryingDirContext.java Mon Dec 12 11:55:01 2011
@@ -0,0 +1,516 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+
+package org.apache.james.util.retry.naming.directory;
+
+import javax.naming.Context;
+import javax.naming.Name;
+import javax.naming.NamingEnumeration;
+import javax.naming.NamingException;
+import javax.naming.directory.Attributes;
+import javax.naming.directory.DirContext;
+import javax.naming.directory.ModificationItem;
+import javax.naming.directory.SearchControls;
+import javax.naming.directory.SearchResult;
+
+import org.apache.james.util.retry.api.RetrySchedule;
+import org.apache.james.util.retry.naming.LoggingRetryHandler;
+import org.apache.james.util.retry.naming.RetryingContext;
+import org.slf4j.Logger;
+
+/**
+ * <code>RetryingDirContext</code> retries the methods defined by <code>javax.naming.directory.DirContext</code>
+ * according to the specified schedule. 
+ * 
+ * @see org.apache.james.util.retry.ExceptionRetryHandler
+ * @see org.apache.james.util.retry.api.ExceptionRetryingProxy
+ * @see javax.naming.directory.DirContext
+ */
+abstract public class RetryingDirContext extends RetryingContext implements DirContext {
+
+
+    /**
+     * Creates a new instance of RetryingDirContext.
+     *
+     * @param schedule
+     * @param maxRetries
+     * @param logger
+     * @throws NamingException
+     */
+    public RetryingDirContext(RetrySchedule schedule, int maxRetries, Logger logger)
+            throws NamingException {
+        super(schedule, maxRetries, logger);
+    }
+
+    /**
+     * @see javax.naming.directory.DirContext#bind(javax.naming.Name,
+     *      java.lang.Object, javax.naming.directory.Attributes)
+     */
+    @Override
+    public void bind(final Name name, final Object obj, final Attributes attrs)
+            throws NamingException {
+        new LoggingRetryHandler(DEFAULT_EXCEPTION_CLASSES, this, getSchedule(), getMaxRetries(),
+                getLogger()) {
+
+            @Override
+            public Object operation() throws NamingException {
+                ((DirContext) getDelegate()).bind(name, obj, attrs);
+                return null;
+            }
+        }.perform();
+    }
+
+    /**
+     * @see javax.naming.directory.DirContext#bind(java.lang.String,
+     *      java.lang.Object, javax.naming.directory.Attributes)
+     */
+    @Override
+    public void bind(final String name, final Object obj, final Attributes attrs)
+            throws NamingException {
+        new LoggingRetryHandler(DEFAULT_EXCEPTION_CLASSES, this, getSchedule(), getMaxRetries(),
+                getLogger()) {
+
+            @Override
+            public Object operation() throws NamingException {
+                ((DirContext) getDelegate()).bind(name, obj, attrs);
+                return null;
+            }
+        }.perform();
+    }
+
+    /**
+     * @see javax.naming.directory.DirContext#createSubcontext(javax.naming.Name,
+     *      javax.naming.directory.Attributes)
+     */
+    @Override
+    public DirContext createSubcontext(final Name name, final Attributes attrs)
+            throws NamingException {
+        return (DirContext) new LoggingRetryHandler(DEFAULT_EXCEPTION_CLASSES, this,
+                getSchedule(), getMaxRetries(), getLogger()) {
+
+            @Override
+            public Object operation() throws NamingException {
+                return ((DirContext) getDelegate()).createSubcontext(name, attrs);
+            }
+        }.perform();
+    }
+
+    /**
+     * @see javax.naming.directory.DirContext#createSubcontext(java.lang.String,
+     *      javax.naming.directory.Attributes)
+     */
+    @Override
+    public DirContext createSubcontext(final String name, final Attributes attrs)
+            throws NamingException {
+        return (DirContext) new LoggingRetryHandler(DEFAULT_EXCEPTION_CLASSES, this,
+                getSchedule(), getMaxRetries(), getLogger()) {
+
+            @Override
+            public Object operation() throws NamingException {
+                return ((DirContext) getDelegate()).createSubcontext(name, attrs);
+            }
+        }.perform();
+    }
+
+    /**
+     * @see javax.naming.directory.DirContext#getAttributes(javax.naming.Name)
+     */
+    @Override
+    public Attributes getAttributes(final Name name) throws NamingException {
+        return (Attributes) new LoggingRetryHandler(DEFAULT_EXCEPTION_CLASSES, this,
+                getSchedule(), getMaxRetries(), getLogger()) {
+
+            @Override
+            public Object operation() throws NamingException {
+                return ((DirContext) getDelegate()).getAttributes(name);
+            }
+        }.perform();
+    }
+
+    /**
+     * @see javax.naming.directory.DirContext#getAttributes(java.lang.String)
+     */
+    @Override
+    public Attributes getAttributes(final String name) throws NamingException {
+        return (Attributes) new LoggingRetryHandler(DEFAULT_EXCEPTION_CLASSES, this,
+                getSchedule(), getMaxRetries(), getLogger()) {
+
+            @Override
+            public Object operation() throws NamingException {
+                return ((DirContext) getDelegate()).getAttributes(name);
+            }
+        }.perform();
+    }
+
+    /**
+     * @see javax.naming.directory.DirContext#getAttributes(javax.naming.Name,
+     *      java.lang.String[])
+     */
+    @Override
+    public Attributes getAttributes(final Name name, final String[] attrIds) throws NamingException {
+        return (Attributes) new LoggingRetryHandler(DEFAULT_EXCEPTION_CLASSES, this,
+                getSchedule(), getMaxRetries(), getLogger()) {
+
+            @Override
+            public Object operation() throws NamingException {
+                return ((DirContext) getDelegate()).getAttributes(name, attrIds);
+            }
+        }.perform();
+    }
+
+    /**
+     * @see javax.naming.directory.DirContext#getAttributes(java.lang.String,
+     *      java.lang.String[])
+     */
+    @Override
+    public Attributes getAttributes(final String name, final String[] attrIds)
+            throws NamingException {
+        return (Attributes) new LoggingRetryHandler(DEFAULT_EXCEPTION_CLASSES, this,
+                getSchedule(), getMaxRetries(), getLogger()) {
+
+            @Override
+            public Object operation() throws NamingException {
+                return ((DirContext) getDelegate()).getAttributes(name, attrIds);
+            }
+        }.perform();
+    }
+
+    /**
+     * @see javax.naming.directory.DirContext#getSchema(javax.naming.Name)
+     */
+    @Override
+    public DirContext getSchema(final Name name) throws NamingException {
+        final Context context = getDelegate();
+        return new RetryingDirContext(getSchedule(), getMaxRetries(), getLogger()) {
+
+            @Override
+            public DirContext newDelegate() throws NamingException {
+                return ((DirContext) context).getSchema(name);
+            }
+        };
+    }
+
+    /**
+     * @see javax.naming.directory.DirContext#getSchema(java.lang.String)
+     */
+    @Override
+    public DirContext getSchema(final String name) throws NamingException {
+        final Context context = getDelegate();
+        return new RetryingDirContext(getSchedule(), getMaxRetries(), getLogger()) {
+
+            @Override
+            public DirContext newDelegate() throws NamingException {
+                return ((DirContext) context).getSchema(name);
+            }
+        };
+    }
+
+    /**
+     * @see javax.naming.directory.DirContext#getSchemaClassDefinition(javax.naming.Name)
+     */
+    @Override
+    public DirContext getSchemaClassDefinition(final Name name) throws NamingException {
+        final Context context = getDelegate();
+        return new RetryingDirContext(getSchedule(), getMaxRetries(), getLogger()) {
+
+            @Override
+            public DirContext newDelegate() throws NamingException {
+                return ((DirContext) context).getSchemaClassDefinition(name);
+            }
+        };
+    }
+
+    /**
+     * @see javax.naming.directory.DirContext#getSchemaClassDefinition(java.lang.String)
+     */
+    @Override
+    public DirContext getSchemaClassDefinition(final String name) throws NamingException {
+        final Context context = getDelegate();
+        return new RetryingDirContext(getSchedule(), getMaxRetries(), getLogger()) {
+
+            @Override
+            public DirContext newDelegate() throws NamingException {
+                return ((DirContext) context).getSchemaClassDefinition(name);
+            }
+        };
+    }
+
+    /**
+     * @see javax.naming.directory.DirContext#modifyAttributes(javax.naming.Name,
+     *      javax.naming.directory.ModificationItem[])
+     */
+    @Override
+    public void modifyAttributes(final Name name, final ModificationItem[] mods)
+            throws NamingException {
+        new LoggingRetryHandler(DEFAULT_EXCEPTION_CLASSES, this, getSchedule(), getMaxRetries(),
+                getLogger()) {
+
+            @Override
+            public Object operation() throws NamingException {
+                ((DirContext) getDelegate()).modifyAttributes(name, mods);
+                return null;
+            }
+        }.perform();
+    }
+
+    /**
+     * @see javax.naming.directory.DirContext#modifyAttributes(java.lang.String,
+     *      javax.naming.directory.ModificationItem[])
+     */
+    @Override
+    public void modifyAttributes(final String name, final ModificationItem[] mods)
+            throws NamingException {
+        new LoggingRetryHandler(DEFAULT_EXCEPTION_CLASSES, this, getSchedule(), getMaxRetries(),
+                getLogger()) {
+
+            @Override
+            public Object operation() throws NamingException {
+                ((DirContext) getDelegate()).modifyAttributes(name, mods);
+                return null;
+            }
+        }.perform();
+    }
+
+    /**
+     * @see javax.naming.directory.DirContext#modifyAttributes(javax.naming.Name,
+     *      int, javax.naming.directory.Attributes)
+     */
+    @Override
+    public void modifyAttributes(final Name name, final int modOp, final Attributes attrs)
+            throws NamingException {
+        new LoggingRetryHandler(DEFAULT_EXCEPTION_CLASSES, this, getSchedule(), getMaxRetries(),
+                getLogger()) {
+
+            @Override
+            public Object operation() throws NamingException {
+                ((DirContext) getDelegate()).modifyAttributes(name, modOp, attrs);
+                return null;
+            }
+        }.perform();
+    }
+
+    /**
+     * @see javax.naming.directory.DirContext#modifyAttributes(java.lang.String,
+     *      int, javax.naming.directory.Attributes)
+     */
+    @Override
+    public void modifyAttributes(final String name, final int modOp, final Attributes attrs)
+            throws NamingException {
+        new LoggingRetryHandler(DEFAULT_EXCEPTION_CLASSES, this, getSchedule(), getMaxRetries(),
+                getLogger()) {
+
+            @Override
+            public Object operation() throws NamingException {
+                ((DirContext) getDelegate()).modifyAttributes(name, modOp, attrs);
+                return null;
+            }
+        }.perform();
+    }
+
+    /**
+     * @see javax.naming.directory.DirContext#rebind(javax.naming.Name,
+     *      java.lang.Object, javax.naming.directory.Attributes)
+     */
+    @Override
+    public void rebind(final Name name, final Object obj, final Attributes attrs)
+            throws NamingException {
+        new LoggingRetryHandler(DEFAULT_EXCEPTION_CLASSES, this, getSchedule(), getMaxRetries(),
+                getLogger()) {
+
+            @Override
+            public Object operation() throws NamingException {
+                ((DirContext) getDelegate()).rebind(name, obj, attrs);
+                return null;
+            }
+        }.perform();
+    }
+
+    /**
+     * @see javax.naming.directory.DirContext#rebind(java.lang.String,
+     *      java.lang.Object, javax.naming.directory.Attributes)
+     */
+    @Override
+    public void rebind(final String name, final Object obj, final Attributes attrs)
+            throws NamingException {
+        new LoggingRetryHandler(DEFAULT_EXCEPTION_CLASSES, this, getSchedule(), getMaxRetries(),
+                getLogger()) {
+
+            @Override
+            public Object operation() throws NamingException {
+                ((DirContext) getDelegate()).rebind(name, obj, attrs);
+                return null;
+            }
+        }.perform();
+    }
+
+    /**
+     * @see javax.naming.directory.DirContext#search(javax.naming.Name,
+     *      javax.naming.directory.Attributes)
+     */
+    @SuppressWarnings("unchecked")
+    @Override
+    public NamingEnumeration<SearchResult> search(final Name name,
+            final Attributes matchingAttributes)
+            throws NamingException {
+        return (NamingEnumeration<SearchResult>) new LoggingRetryHandler(
+                DEFAULT_EXCEPTION_CLASSES, this, getSchedule(), getMaxRetries(), getLogger()) {
+
+            @Override
+            public Object operation() throws NamingException {
+                return ((DirContext) getDelegate()).search(name, matchingAttributes);
+            }
+        }.perform();
+    }
+
+    /**
+     * @see javax.naming.directory.DirContext#search(java.lang.String,
+     *      javax.naming.directory.Attributes)
+     */
+    @SuppressWarnings("unchecked")
+    @Override
+    public NamingEnumeration<SearchResult> search(final String name,
+            final Attributes matchingAttributes)
+            throws NamingException {
+        return (NamingEnumeration<SearchResult>) new LoggingRetryHandler(
+                DEFAULT_EXCEPTION_CLASSES, this, getSchedule(), getMaxRetries(), getLogger()) {
+
+            @Override
+            public Object operation() throws NamingException {
+                return ((DirContext) getDelegate()).search(name, matchingAttributes);
+            }
+        }.perform();
+    }
+
+    /**
+     * @see javax.naming.directory.DirContext#search(javax.naming.Name,
+     *      javax.naming.directory.Attributes, java.lang.String[])
+     */
+    @SuppressWarnings("unchecked")
+    @Override
+    public NamingEnumeration<SearchResult> search(final Name name,
+            final Attributes matchingAttributes,
+            String[] attributesToReturn) throws NamingException {
+        return (NamingEnumeration<SearchResult>) new LoggingRetryHandler(
+                DEFAULT_EXCEPTION_CLASSES, this, getSchedule(), getMaxRetries(), getLogger()) {
+
+            @Override
+            public Object operation() throws NamingException {
+                return ((DirContext) getDelegate()).search(name, matchingAttributes);
+            }
+        }.perform();
+    }
+
+    /**
+     * @see javax.naming.directory.DirContext#search(java.lang.String,
+     *      javax.naming.directory.Attributes, java.lang.String[])
+     */
+    @SuppressWarnings("unchecked")
+    @Override
+    public NamingEnumeration<SearchResult> search(final String name,
+            final Attributes matchingAttributes,
+            final String[] attributesToReturn) throws NamingException {
+        return (NamingEnumeration<SearchResult>) new LoggingRetryHandler(
+                DEFAULT_EXCEPTION_CLASSES, this, getSchedule(), getMaxRetries(), getLogger()) {
+
+            @Override
+            public Object operation() throws NamingException {
+                return ((DirContext) getDelegate()).search(name, matchingAttributes,
+                        attributesToReturn);
+            }
+        }.perform();
+    }
+
+    /**
+     * @see javax.naming.directory.DirContext#search(javax.naming.Name,
+     *      java.lang.String, javax.naming.directory.SearchControls)
+     */
+    @SuppressWarnings("unchecked")
+    @Override
+    public NamingEnumeration<SearchResult> search(final Name name, final String filter,
+            final SearchControls cons)
+            throws NamingException {
+        return (NamingEnumeration<SearchResult>) new LoggingRetryHandler(
+                DEFAULT_EXCEPTION_CLASSES, this, getSchedule(), getMaxRetries(), getLogger()) {
+
+            @Override
+            public Object operation() throws NamingException {
+                return ((DirContext) getDelegate()).search(name, filter, cons);
+            }
+        }.perform();
+    }
+
+    /**
+     * @see javax.naming.directory.DirContext#search(java.lang.String,
+     *      java.lang.String, javax.naming.directory.SearchControls)
+     */
+    @SuppressWarnings("unchecked")
+    @Override
+    public NamingEnumeration<SearchResult> search(final String name, final String filter,
+            final SearchControls cons)
+            throws NamingException {
+        return (NamingEnumeration<SearchResult>) new LoggingRetryHandler(
+                DEFAULT_EXCEPTION_CLASSES, this, getSchedule(), getMaxRetries(), getLogger()) {
+
+            @Override
+            public Object operation() throws NamingException {
+                return ((DirContext) getDelegate()).search(name, filter, cons);
+            }
+        }.perform();
+    }
+
+    /**
+     * @see javax.naming.directory.DirContext#search(javax.naming.Name,
+     *      java.lang.String, java.lang.Object[],
+     *      javax.naming.directory.SearchControls)
+     */
+    @SuppressWarnings("unchecked")
+    @Override
+    public NamingEnumeration<SearchResult> search(final Name name, final String filterExpr,
+            final Object[] filterArgs, final SearchControls cons) throws NamingException {
+        return (NamingEnumeration<SearchResult>) new LoggingRetryHandler(
+                DEFAULT_EXCEPTION_CLASSES, this, getSchedule(), getMaxRetries(), getLogger()) {
+
+            @Override
+            public Object operation() throws NamingException {
+                return ((DirContext) getDelegate()).search(name, filterExpr, filterArgs, cons);
+            }
+        }.perform();
+    }
+
+    /**
+     * @see javax.naming.directory.DirContext#search(java.lang.String,
+     *      java.lang.String, java.lang.Object[],
+     *      javax.naming.directory.SearchControls)
+     */
+    @SuppressWarnings("unchecked")
+    @Override
+    public NamingEnumeration<SearchResult> search(final String name, final String filterExpr,
+            final Object[] filterArgs, final SearchControls cons) throws NamingException {
+        return (NamingEnumeration<SearchResult>) new LoggingRetryHandler(
+                DEFAULT_EXCEPTION_CLASSES, this, getSchedule(), getMaxRetries(), getLogger()) {
+
+            @Override
+            public Object operation() throws NamingException {
+                return ((DirContext) getDelegate()).search(name, filterExpr, filterArgs, cons);
+            }
+        }.perform();
+    }
+
+}

Propchange: james/server/trunk/util/src/main/java/org/apache/james/util/retry/naming/directory/RetryingDirContext.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: james/server/trunk/util/src/main/java/org/apache/james/util/retry/naming/directory/RetryingDirContext.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: james/server/trunk/util/src/main/java/org/apache/james/util/retry/naming/ldap/RetryingLdapContext.java
URL: http://svn.apache.org/viewvc/james/server/trunk/util/src/main/java/org/apache/james/util/retry/naming/ldap/RetryingLdapContext.java?rev=1213196&view=auto
==============================================================================
--- james/server/trunk/util/src/main/java/org/apache/james/util/retry/naming/ldap/RetryingLdapContext.java (added)
+++ james/server/trunk/util/src/main/java/org/apache/james/util/retry/naming/ldap/RetryingLdapContext.java Mon Dec 12 11:55:01 2011
@@ -0,0 +1,151 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+
+package org.apache.james.util.retry.naming.ldap;
+
+import javax.naming.Context;
+import javax.naming.NamingException;
+import javax.naming.ldap.Control;
+import javax.naming.ldap.ExtendedRequest;
+import javax.naming.ldap.ExtendedResponse;
+import javax.naming.ldap.LdapContext;
+
+import org.apache.james.util.retry.api.RetrySchedule;
+import org.apache.james.util.retry.naming.LoggingRetryHandler;
+import org.apache.james.util.retry.naming.directory.RetryingDirContext;
+import org.slf4j.Logger;
+
+/**
+ * <code>RetryingLdapContext</code> retries the methods defined by <code>javax.naming.ldap.LdapContext</code>
+ * according to the specified schedule. 
+ * 
+ * @see org.apache.james.util.retry.ExceptionRetryHandler
+ * @see org.apache.james.util.retry.api.ExceptionRetryingProxy
+ * @see javax.naming.ldap.LdapContext
+ */
+abstract public class RetryingLdapContext extends RetryingDirContext implements LdapContext {
+   
+    /**
+     * Creates a new instance of RetryingLdapContext.
+     *
+     * @param maxRetries
+     * @param retryInterval
+     * @throws NamingException
+     */
+    public RetryingLdapContext(RetrySchedule schedule, int maxRetries, Logger logger) throws NamingException {
+        super(schedule, maxRetries, logger);
+    }
+
+    /**
+     * @see javax.naming.ldap.LdapContext#extendedOperation(javax.naming.ldap.ExtendedRequest)
+     */
+    @Override
+    public ExtendedResponse extendedOperation(final ExtendedRequest request) throws NamingException {
+        return (ExtendedResponse) new LoggingRetryHandler(DEFAULT_EXCEPTION_CLASSES, this, getSchedule(), getMaxRetries(), getLogger()){
+
+            @Override
+            public Object operation() throws NamingException {
+                return ((LdapContext) getDelegate()).extendedOperation(request);
+            }}.perform();
+    }
+
+    /**
+     * @see javax.naming.ldap.LdapContext#getConnectControls()
+     */
+    @Override
+    public Control[] getConnectControls() throws NamingException {
+        return (Control[]) new LoggingRetryHandler(DEFAULT_EXCEPTION_CLASSES, this, getSchedule(), getMaxRetries(), getLogger()){
+
+            @Override
+            public Object operation() throws NamingException {
+                return ((LdapContext) getDelegate()).getConnectControls();
+            }}.perform();
+    }
+
+    /**
+     * @see javax.naming.ldap.LdapContext#getRequestControls()
+     */
+    @Override
+    public Control[] getRequestControls() throws NamingException {
+        return (Control[]) new LoggingRetryHandler(DEFAULT_EXCEPTION_CLASSES, this, getSchedule(), getMaxRetries(), getLogger()){
+
+            @Override
+            public Object operation() throws NamingException {
+                return ((LdapContext) getDelegate()).getRequestControls();
+            }}.perform();
+    }
+
+    /**
+     * @see javax.naming.ldap.LdapContext#getResponseControls()
+     */
+    @Override
+    public Control[] getResponseControls() throws NamingException {
+        return (Control[]) new LoggingRetryHandler(DEFAULT_EXCEPTION_CLASSES, this, getSchedule(), getMaxRetries(), getLogger()){
+
+            @Override
+            public Object operation() throws NamingException {
+                return ((LdapContext) getDelegate()).getResponseControls();
+            }}.perform();
+    }
+
+    /**
+     * @see javax.naming.ldap.LdapContext#newInstance(javax.naming.ldap.Control[])
+     */
+    @Override
+    public LdapContext newInstance(final Control[] requestControls) throws NamingException {
+        final Context context = getDelegate();
+        return new RetryingLdapContext(getSchedule(), getMaxRetries(), getLogger()) {
+
+            @Override
+            public Context newDelegate() throws NamingException {
+                return ((LdapContext) context).newInstance(requestControls);
+            }
+        };
+    }
+
+    /**
+     * @see javax.naming.ldap.LdapContext#reconnect(javax.naming.ldap.Control[])
+     */
+    @Override
+    public void reconnect(final Control[] connCtls) throws NamingException {
+        new LoggingRetryHandler(DEFAULT_EXCEPTION_CLASSES, this, getSchedule(), getMaxRetries(), getLogger()){
+
+            @Override
+            public Object operation() throws NamingException {
+                ((LdapContext) getDelegate()).reconnect(connCtls);
+                return null;
+            }}.perform();
+    }
+
+    /**
+     * @see javax.naming.ldap.LdapContext#setRequestControls(javax.naming.ldap.Control[])
+     */
+    @Override
+    public void setRequestControls(final Control[] requestControls) throws NamingException {
+        new LoggingRetryHandler(DEFAULT_EXCEPTION_CLASSES, this, getSchedule(), getMaxRetries(), getLogger()){
+
+            @Override
+            public Object operation() throws NamingException {
+                ((LdapContext) getDelegate()).setRequestControls(requestControls);
+                return null;
+            }}.perform();
+    }
+
+}

Propchange: james/server/trunk/util/src/main/java/org/apache/james/util/retry/naming/ldap/RetryingLdapContext.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: james/server/trunk/util/src/main/java/org/apache/james/util/retry/naming/ldap/RetryingLdapContext.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: james/server/trunk/util/src/test/java/org/apache/james/util/retry/DoublingRetryScheduleTest.java
URL: http://svn.apache.org/viewvc/james/server/trunk/util/src/test/java/org/apache/james/util/retry/DoublingRetryScheduleTest.java?rev=1213196&view=auto
==============================================================================
--- james/server/trunk/util/src/test/java/org/apache/james/util/retry/DoublingRetryScheduleTest.java (added)
+++ james/server/trunk/util/src/test/java/org/apache/james/util/retry/DoublingRetryScheduleTest.java Mon Dec 12 11:55:01 2011
@@ -0,0 +1,81 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+
+package org.apache.james.util.retry;
+
+
+import org.apache.james.util.retry.api.RetrySchedule;
+
+import junit.framework.TestCase;
+
+/**
+ * <code>DoublingRetryScheduleTest</code>
+ */
+public class DoublingRetryScheduleTest extends TestCase {
+
+    /**
+     * Test method for {@link org.apache.james.user.ldap.DoublingRetrySchedule#DoublingRetrySchedule(long, long)}.
+     */
+    public final void testDoublingRetrySchedule() {
+        assertTrue(RetrySchedule.class.isAssignableFrom(new DoublingRetrySchedule(0,0).getClass()));
+        assertEquals(0, new DoublingRetrySchedule(0, 0).getInterval(0));
+        assertEquals(0, new DoublingRetrySchedule(-1, -1).getInterval(0));
+        assertEquals(0, new DoublingRetrySchedule(-1, 0).getInterval(0));
+        assertEquals(0, new DoublingRetrySchedule(0, -1).getInterval(0));
+    }
+
+    /**
+     * Test method for {@link org.apache.james.user.ldap.DoublingRetrySchedule#getInterval(int)}.
+     */
+    public final void testGetInterval() {
+        assertEquals(0, new DoublingRetrySchedule(0, 8).getInterval(0));
+        assertEquals(1, new DoublingRetrySchedule(0, 8).getInterval(1));
+        assertEquals(2, new DoublingRetrySchedule(0, 8).getInterval(2));
+        assertEquals(4, new DoublingRetrySchedule(0, 8).getInterval(3));
+        assertEquals(8, new DoublingRetrySchedule(0, 8).getInterval(4));
+        assertEquals(8, new DoublingRetrySchedule(0, 8).getInterval(5));
+        
+        assertEquals(1, new DoublingRetrySchedule(1, 8).getInterval(0));
+        assertEquals(2, new DoublingRetrySchedule(1, 8).getInterval(1));
+        assertEquals(4, new DoublingRetrySchedule(1, 8).getInterval(2));
+        assertEquals(8, new DoublingRetrySchedule(1, 8).getInterval(3));
+        assertEquals(8, new DoublingRetrySchedule(1, 8).getInterval(4));
+        
+        assertEquals(3, new DoublingRetrySchedule(3, 12).getInterval(0));
+        assertEquals(6, new DoublingRetrySchedule(3, 12).getInterval(1));
+        assertEquals(12, new DoublingRetrySchedule(3, 12).getInterval(2));
+        assertEquals(12, new DoublingRetrySchedule(3, 12).getInterval(3));
+        
+        assertEquals(0, new DoublingRetrySchedule(0, 8, 1000).getInterval(0));
+        assertEquals(1000, new DoublingRetrySchedule(0, 8, 1000).getInterval(1));
+        assertEquals(2000, new DoublingRetrySchedule(0, 8, 1000).getInterval(2));
+        assertEquals(4000, new DoublingRetrySchedule(0, 8, 1000).getInterval(3));
+        assertEquals(8000, new DoublingRetrySchedule(0, 8, 1000).getInterval(4));
+        assertEquals(8000, new DoublingRetrySchedule(0, 8, 1000).getInterval(5));
+    }
+
+    /**
+     * Test method for {@link org.apache.james.user.ldap.DoublingRetrySchedule#toString()}.
+     */
+    public final void testToString() {
+        assertEquals("DoublingRetrySchedule [startInterval=0, maxInterval=1, multiplier=1]", new DoublingRetrySchedule(0, 1).toString());
+    }
+
+}

Propchange: james/server/trunk/util/src/test/java/org/apache/james/util/retry/DoublingRetryScheduleTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: james/server/trunk/util/src/test/java/org/apache/james/util/retry/DoublingRetryScheduleTest.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: james/server/trunk/util/src/test/java/org/apache/james/util/retry/ExceptionRetryHandlerTest.java
URL: http://svn.apache.org/viewvc/james/server/trunk/util/src/test/java/org/apache/james/util/retry/ExceptionRetryHandlerTest.java?rev=1213196&view=auto
==============================================================================
--- james/server/trunk/util/src/test/java/org/apache/james/util/retry/ExceptionRetryHandlerTest.java (added)
+++ james/server/trunk/util/src/test/java/org/apache/james/util/retry/ExceptionRetryHandlerTest.java Mon Dec 12 11:55:01 2011
@@ -0,0 +1,198 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+
+package org.apache.james.util.retry;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.naming.Context;
+
+import org.apache.james.util.retry.api.ExceptionRetryingProxy;
+import org.apache.james.util.retry.api.RetryHandler;
+import org.apache.james.util.retry.api.RetrySchedule;
+
+import junit.framework.TestCase;
+
+/**
+ * <code>ExceptionRetryHandlerTest</code>
+ */
+public class ExceptionRetryHandlerTest extends TestCase {
+    
+    private Class<?>[] _exceptionClasses = null;
+    private ExceptionRetryingProxy _proxy = null;
+    private RetrySchedule _schedule = null;
+    
+    /**
+     * @see junit.framework.TestCase#setUp()
+     */
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        _exceptionClasses = new Class<?>[]{Exception.class};
+        _proxy = new TestRetryingProxy();
+        _schedule = new TestRetrySchedule();
+    }
+    
+    private class TestRetryingProxy implements ExceptionRetryingProxy
+    {
+
+        /**
+         * @see org.apache.james.user.ldap.api.ExceptionRetryingProxy#getDelegate()
+         */
+        @Override
+        public Context getDelegate() throws Exception {
+            return null;
+        }
+
+        /**
+         * @see org.apache.james.user.ldap.api.ExceptionRetryingProxy#newDelegate()
+         */
+        @Override
+        public Context newDelegate() throws Exception {
+            return null;
+        }
+
+        /**
+         * @see org.apache.james.user.ldap.api.ExceptionRetryingProxy#resetDelegate()
+         */
+        @Override
+        public void resetDelegate() throws Exception {
+            
+        }
+        
+    }
+    
+    private class TestRetrySchedule implements RetrySchedule
+    {
+        /**
+         * @see org.apache.james.user.ldap.api.RetrySchedule#getInterval(int)
+         */
+        @Override
+        public long getInterval(int index) {
+            return index;
+        }
+        
+    }
+
+    /**
+     * Test method for {@link org.apache.james.user.ldap.ExceptionRetryHandler#ExceptionRetryHandler(java.lang.Class<?>[], org.apache.james.user.ldap.api.ExceptionRetryingProxy, org.apache.james.user.ldap.api.RetrySchedule, int)}.
+     */
+    public final void testExceptionRetryHandler() {
+        assertTrue(RetryHandler.class.isAssignableFrom(new ExceptionRetryHandler(
+                _exceptionClasses, _proxy, _schedule, 0) {
+
+            @Override
+            public Object operation() throws Exception {
+                return null;
+            }
+        }.getClass()));
+    }
+
+    /**
+     * Test method for {@link org.apache.james.user.ldap.ExceptionRetryHandler#perform()}.
+     * @throws Exception 
+     */
+    public final void testPerform() throws Exception {
+        Object result = new ExceptionRetryHandler(
+                _exceptionClasses, _proxy, _schedule, 0) {
+
+            @Override
+            public Object operation() throws Exception {
+                return "Hi!";
+            }
+        }.perform();
+        assertEquals("Hi!", result);
+
+        try {
+            new ExceptionRetryHandler(
+                    _exceptionClasses, _proxy, _schedule, 0) {
+
+                @Override
+                public Object operation() throws Exception {
+                    throw new Exception();
+                }
+            }.perform();
+        } catch (Exception ex) {
+            // no-op
+        }
+        assertEquals("Hi!", result);
+    }
+
+    /**
+     * Test method for {@link org.apache.james.user.ldap.ExceptionRetryHandler#postFailure(java.lang.Exception, int)}.
+     */
+    public final void testPostFailure() {
+        final List<Exception> results = new ArrayList<Exception>();
+        RetryHandler handler = new ExceptionRetryHandler(
+                _exceptionClasses, _proxy, _schedule, 7) {
+
+            @Override
+            public void postFailure(Exception ex, int retryCount) {
+                super.postFailure(ex, retryCount);
+                results.add(ex);
+            }
+
+            @Override
+            public Object operation() throws Exception {
+                throw new Exception();
+            }
+        };
+        try {
+            handler.perform();
+        } catch (Exception ex)
+        {
+            // no-op
+        }
+        assertEquals(7, results.size());
+    }
+
+    /**
+     * Test method for {@link org.apache.james.user.ldap.ExceptionRetryHandler#operation()}.
+     * @throws Exception 
+     */
+    public final void testOperation() throws Exception {
+        RetryHandler handler = new ExceptionRetryHandler(
+                _exceptionClasses, _proxy, _schedule, 0) {
+
+            @Override
+            public Object operation() throws Exception {
+                return "Hi!";
+            }
+        };
+        assertEquals("Hi!", handler.operation());
+    }
+
+    /**
+     * Test method for {@link org.apache.james.user.ldap.ExceptionRetryHandler#getRetryInterval(int)}.
+     */
+    public final void testGetRetryInterval() {
+        ExceptionRetryHandler handler = new ExceptionRetryHandler(
+                _exceptionClasses, _proxy, _schedule, 0) {
+
+            @Override
+            public Object operation() throws Exception {
+                return null;
+            }
+        };
+        assertEquals(8, handler.getRetryInterval(8));
+    }
+
+}

Propchange: james/server/trunk/util/src/test/java/org/apache/james/util/retry/ExceptionRetryHandlerTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: james/server/trunk/util/src/test/java/org/apache/james/util/retry/ExceptionRetryHandlerTest.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain



---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org