Am 03.03.2015 um 08:35 schrieb Benedikt Ritter:
> 2015-03-02 21:34 GMT+01:00 Oliver Heger <oliver.he...@oliver-heger.de>:
> 
>>
>>
>> Am 02.03.2015 um 07:23 schrieb Benedikt Ritter:
>>> 2015-03-01 22:20 GMT+01:00 Oliver Heger <oliver.he...@oliver-heger.de>:
>>>
>>>>
>>>>
>>>> Am 01.03.2015 um 17:52 schrieb Benedikt Ritter:
>>>>> 2015-02-26 21:29 GMT+01:00 Oliver Heger <oliver.he...@oliver-heger.de
>>> :
>>>>>
>>>>>> Hi Arthur,
>>>>>>
>>>>>> I don't have any principle objections against your implementation.
>>>>>>
>>>>>> I just don't want it as a replacement for the AtomicSafeInitializer
>>>>>> class. The latter was designed and announces itself to use only atomic
>>>>>> variables for its synchronization and no other types of locks. This
>>>>>> premise no longer holds. If the implementation is broken and does not
>>>>>> work as expected, we should deprecate and later remove it.
>>>>>>
>>>>>
>>>>> Just deprecating the class if it has a bug (hanging threads when an
>>>>> exception is thrown) doesn't seem right to me.
>>>>>
>>>>> How about we apply the patch and make it very clear in the release
>> notes
>>>>> and JavaDoc, that it's behavior has been changed?
>>>>
>>>> But then the name of the class is completely wrong. It is a bit like
>>>>
>>>> public class ClassWithoutSynchronization {
>>>>     public void doSomething() {
>>>>         *synchronized*(this) {
>>>>             ...
>>>>         }
>>>>     }
>>>> }
>>>>
>>>> For me the name AtomicSafeInitializer indicates that only atomic
>>>> variables are used to ensure thread-safety. Everything else would be
>>>> surprising, even if it was mentioned in JavaDoc.
>>>>
>>>
>>> We have several issues here:
>>>
>>> 1. Find a name for the proposed initializer implementation. How about
>>> BlockingInitizalizer?
>>> 2. Fix the bug in AtomicSafeInitializer (hanging threads on exception).
>> My
>>> opinion is, that BusyWaitInitializer would be a much better name for this
>>> class :o)
>>> 3. Compare the new implementation and LazyInitializer. Is the
>>> BlockingInitializer a replacement for LazyInitializer?
>> Who said that the new initializer is a replacement for LazyInitializer?
>>
> 
> Nobody, I was asking a question ;-)

Okay, so I hope I have answered it.

Oliver

> 
> 
>>
>> LazyInitializer is a direct implementation of the double-check idiom
>> for an instance field (refer to Bloch's Effective Java). It is pretty
>> lean and elegant.
>>
>> I assume that the new initializer behaves similar to this class: It uses
>> fields with volatile semantics in the first level and synchronization if
>> a conflict occurs. But it is more complex. So the question is do these
>> two classes have different properties and behavior so that it makes
>> sense to include both of them?
>>
>> Oliver
>>
>>>
>>> Benedikt
>>>
>>>
>>>>
>>>> Oliver
>>>>>
>>>>> Benedikt
>>>>>
>>>>>
>>>>>>
>>>>>> What I would be interested in is a comparison between your
>>>>>> implementation and LazyInitializer. How do these classes behave in
>>>>>> typical scenarios and which one is the preferred option under which
>>>>>> conditions?
>>>>>>
>>>>>> If we add your proposal as an additional initializer implementation,
>> we
>>>>>> will also have to update the user's guide and give our users
>> appropriate
>>>>>> recommendations when they should use which class.
>>>>>>
>>>>>> And, we will have to pick a meaningful name for your class.
>>>>>>
>>>>>> Oliver
>>>>>>
>>>>>> Am 26.02.2015 um 20:51 schrieb Arthur Naseef:
>>>>>>> A few questions coming to mind here:
>>>>>>>
>>>>>>>    - First off, how do we move this forward?
>>>>>>>       - What do we do with the new implementation?
>>>>>>>       - What is a good way to address the busy-wait in the original
>>>> code?
>>>>>>>       - What is a good way to address the fact that all threads will
>>>>>>>       busy-wait in the original code if the initialize() method
>> throws
>>>> an
>>>>>>>       exception?
>>>>>>>       - What is a good way to address the original comments which
>>>>>> indicate
>>>>>>>       this class will perform better when, in fact, the busy waiting
>>>> may
>>>>>> have a
>>>>>>>       significant impact on performance?
>>>>>>>    - How can we address the fears?  Honestly, I think the comment is
>>>>>> less a
>>>>>>>    "fear" than a belief, so how do we prove/disprove?
>>>>>>>       - What is this other initializer implementation?
>>>>>>>       - What are the differences in operation between the two?
>>>>>>>
>>>>>>> Oliver - I'm reading a lot of concerns here, but not seeing how you
>>>> would
>>>>>>> like to address those concerns.  Please help me on that front.
>>>>>>>
>>>>>>> Note, by the way, that the new implementation operates the same as
>> the
>>>>>>> original code, to the application using it, except in the case of an
>>>>>>> exception thrown on the initialize() call, which is problematic now.
>>>>>> That
>>>>>>> is, this new implementation guarantees initialize() will only ever be
>>>>>>> called one time, and it ensures all callers receive the result of
>> that
>>>>>>> initialize() method.
>>>>>>>
>>>>>>> Art
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> On Mon, Feb 23, 2015 at 1:47 PM, Oliver Heger <
>>>>>> oliver.he...@oliver-heger.de>
>>>>>>> wrote:
>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>> Am 23.02.2015 um 21:35 schrieb Benedikt Ritter:
>>>>>>>>> Oliver Heger has raised concerns about this commit in JIRA [1]:
>>>>>>>>>
>>>>>>>>>> This is a strong change in the behavior of this class. The main
>>>>>> property
>>>>>>>>> of atomic initializers was that they are non
>>>>>>>>>> blocking. Now a blocking wait has been introduced. When there is
>> so
>>>>>> much
>>>>>>>>> contention that the busy wait is
>>>>>>>>>> actually a problem, wouln't it then be better to directly use a
>>>>>> blocking
>>>>>>>>> variant like lazy initializer?
>>>>>>>>>
>>>>>>>>> I've looked through the JavaDoc of AtomicInitializer once more. It
>>>>>> says:
>>>>>>>>> "Because {@code AtomicSafeInitializer} does not use synchronization
>>>> at
>>>>>>>> all
>>>>>>>>> it probably outruns {@link LazyInitializer}, at least under low or
>>>>>>>> moderate
>>>>>>>>> concurrent access."
>>>>>>>>>
>>>>>>>>> This is the only thing I can find regarding concurrency properties
>> of
>>>>>>>>> AtomicInitializer. I think this still holds, doesn't it?
>>>>>>>>
>>>>>>>> No, the CountDownLatch is synchronized.
>>>>>>>>
>>>>>>>> There are multiple initializer implementations with different
>>>> properties
>>>>>>>> which are suitable for different use cases and scenarios. The atomic
>>>>>>>> initializers are useful if you want to avoid blocking calls, but
>> they
>>>>>>>> might be an inferior solution under high contention.
>>>>>>>>
>>>>>>>> My fear is that this commit optimizes the class for a use case which
>>>> can
>>>>>>>> be served better by another initializer implementation which is
>>>> already
>>>>>>>> blocking; and this optimization has negative impact on the original
>>>>>>>> intention of AtomicSafeInitializer.
>>>>>>>>
>>>>>>>> Oliver
>>>>>>>>
>>>>>>>>>
>>>>>>>>> Benedikt
>>>>>>>>>
>>>>>>>>> [1] https://issues.apache.org/jira/browse/LANG-1086
>>>>>>>>>
>>>>>>>>> 2015-02-23 21:15 GMT+01:00 <brit...@apache.org>:
>>>>>>>>>
>>>>>>>>>> Author: britter
>>>>>>>>>> Date: Mon Feb 23 20:15:49 2015
>>>>>>>>>> New Revision: 1661762
>>>>>>>>>>
>>>>>>>>>> URL: http://svn.apache.org/r1661762
>>>>>>>>>> Log:
>>>>>>>>>> LANG-1086: Remove busy wait from AtomicSafeInitializer.get(). This
>>>>>> also
>>>>>>>>>> fixes #46 from github. Thanks to github user artnaseef.
>>>>>>>>>>
>>>>>>>>>> Modified:
>>>>>>>>>>     commons/proper/lang/trunk/src/changes/changes.xml
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>
>>>>>>
>>>>
>> commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/concurrent/AtomicSafeInitializer.java
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>
>>>>>>
>>>>
>> commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/concurrent/AbstractConcurrentInitializerTest.java
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>
>>>>>>
>>>>
>> commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/concurrent/AtomicInitializerTest.java
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>
>>>>>>
>>>>
>> commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/concurrent/AtomicSafeInitializerTest.java
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>
>>>>>>
>>>>
>> commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/concurrent/LazyInitializerTest.java
>>>>>>>>>>
>>>>>>>>>> Modified: commons/proper/lang/trunk/src/changes/changes.xml
>>>>>>>>>> URL:
>>>>>>>>>>
>>>>>>>>
>>>>>>
>>>>
>> http://svn.apache.org/viewvc/commons/proper/lang/trunk/src/changes/changes.xml?rev=1661762&r1=1661761&r2=1661762&view=diff
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>
>>>>>>
>>>>
>> ==============================================================================
>>>>>>>>>> --- commons/proper/lang/trunk/src/changes/changes.xml [utf-8]
>>>>>> (original)
>>>>>>>>>> +++ commons/proper/lang/trunk/src/changes/changes.xml [utf-8] Mon
>>>> Feb
>>>>>> 23
>>>>>>>>>> 20:15:49 2015
>>>>>>>>>> @@ -22,6 +22,7 @@
>>>>>>>>>>    <body>
>>>>>>>>>>
>>>>>>>>>>    <release version="3.4" date="tba" description="tba">
>>>>>>>>>> +    <action issue="LANG-1086" type="update" dev="britter">Remove
>>>> busy
>>>>>>>>>> wait from AtomicSafeInitializer.get()</action>
>>>>>>>>>>      <action issue="LANG-1081" type="fix" dev="britter"
>>>>>> due-to="Jonathan
>>>>>>>>>> Baker">DiffBuilder.append(String, Object left, Object right) does
>>>> not
>>>>>>>> do a
>>>>>>>>>> left.equals(right) check</action>
>>>>>>>>>>      <action issue="LANG-1055" type="fix" dev="britter"
>>>>>> due-to="Jonathan
>>>>>>>>>> Baker">StrSubstitutor.replaceSystemProperties does not work
>>>>>>>>>> consistently</action>
>>>>>>>>>>      <action issue="LANG-1082" type="add" dev="britter"
>>>>>> due-to="Jonathan
>>>>>>>>>> Baker">Add option to disable the "objectsTriviallyEqual" test in
>>>>>>>>>> DiffBuilder</action>
>>>>>>>>>>
>>>>>>>>>> Modified:
>>>>>>>>>>
>>>>>>>>
>>>>>>
>>>>
>> commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/concurrent/AtomicSafeInitializer.java
>>>>>>>>>> URL:
>>>>>>>>>>
>>>>>>>>
>>>>>>
>>>>
>> http://svn.apache.org/viewvc/commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/concurrent/AtomicSafeInitializer.java?rev=1661762&r1=1661761&r2=1661762&view=diff
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>
>>>>>>
>>>>
>> ==============================================================================
>>>>>>>>>> ---
>>>>>>>>>>
>>>>>>>>
>>>>>>
>>>>
>> commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/concurrent/AtomicSafeInitializer.java
>>>>>>>>>> (original)
>>>>>>>>>> +++
>>>>>>>>>>
>>>>>>>>
>>>>>>
>>>>
>> commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/concurrent/AtomicSafeInitializer.java
>>>>>>>>>> Mon Feb 23 20:15:49 2015
>>>>>>>>>> @@ -16,6 +16,7 @@
>>>>>>>>>>   */
>>>>>>>>>>  package org.apache.commons.lang3.concurrent;
>>>>>>>>>>
>>>>>>>>>> +import java.util.concurrent.CountDownLatch;
>>>>>>>>>>  import java.util.concurrent.atomic.AtomicReference;
>>>>>>>>>>
>>>>>>>>>>  /**
>>>>>>>>>> @@ -62,20 +63,44 @@ public abstract class AtomicSafeInitiali
>>>>>>>>>>      /** Holds the reference to the managed object. */
>>>>>>>>>>      private final AtomicReference<T> reference = new
>>>>>>>> AtomicReference<T>();
>>>>>>>>>>
>>>>>>>>>> +    /** Holds the exception that terminated the initialize()
>>>> method,
>>>>>> if
>>>>>>>>>> an exception was thrown */
>>>>>>>>>> +    private final AtomicReference<ConcurrentException>
>>>> referenceExc =
>>>>>>>> new
>>>>>>>>>> AtomicReference<ConcurrentException>();
>>>>>>>>>> +
>>>>>>>>>> +    /** Latch for those threads waiting for initialization to
>>>>>>>> complete. */
>>>>>>>>>> +    private final CountDownLatch latch = new CountDownLatch(1);
>>>>>>>>>> +
>>>>>>>>>>      /**
>>>>>>>>>>       * Get (and initialize, if not initialized yet) the required
>>>>>> object
>>>>>>>>>>       *
>>>>>>>>>>       * @return lazily initialized object
>>>>>>>>>>       * @throws ConcurrentException if the initialization of the
>>>>>> object
>>>>>>>>>> causes an
>>>>>>>>>> -     * exception
>>>>>>>>>> +     * exception or the thread is interrupted waiting for another
>>>>>>>> thread
>>>>>>>>>> to
>>>>>>>>>> +     * complete the initialization
>>>>>>>>>>       */
>>>>>>>>>>      @Override
>>>>>>>>>>      public final T get() throws ConcurrentException {
>>>>>>>>>>          T result;
>>>>>>>>>>
>>>>>>>>>> -        while ((result = reference.get()) == null) {
>>>>>>>>>> +        if ((result = reference.get()) == null) {
>>>>>>>>>>              if (factory.compareAndSet(null, this)) {
>>>>>>>>>> -                reference.set(initialize());
>>>>>>>>>> +                try {
>>>>>>>>>> +                    reference.set(result = initialize());
>>>>>>>>>> +                } catch ( ConcurrentException exc ) {
>>>>>>>>>> +                    referenceExc.set(exc);
>>>>>>>>>> +                    throw exc;
>>>>>>>>>> +                } finally {
>>>>>>>>>> +                    latch.countDown();
>>>>>>>>>> +                }
>>>>>>>>>> +            } else {
>>>>>>>>>> +                try {
>>>>>>>>>> +                    latch.await();
>>>>>>>>>> +                    if ( referenceExc.get() != null ) {
>>>>>>>>>> +                        throw new
>>>>>>>>>> ConcurrentException(referenceExc.get().getMessage(),
>>>>>>>>>> referenceExc.get().getCause());
>>>>>>>>>> +                    }
>>>>>>>>>> +                    result = reference.get();
>>>>>>>>>> +                } catch (InterruptedException intExc) {
>>>>>>>>>> +                    throw new ConcurrentException("interrupted
>>>>>> waiting
>>>>>>>>>> for initialization to complete", intExc);
>>>>>>>>>> +                }
>>>>>>>>>>              }
>>>>>>>>>>          }
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>> Modified:
>>>>>>>>>>
>>>>>>>>
>>>>>>
>>>>
>> commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/concurrent/AbstractConcurrentInitializerTest.java
>>>>>>>>>> URL:
>>>>>>>>>>
>>>>>>>>
>>>>>>
>>>>
>> http://svn.apache.org/viewvc/commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/concurrent/AbstractConcurrentInitializerTest.java?rev=1661762&r1=1661761&r2=1661762&view=diff
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>
>>>>>>
>>>>
>> ==============================================================================
>>>>>>>>>> ---
>>>>>>>>>>
>>>>>>>>
>>>>>>
>>>>
>> commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/concurrent/AbstractConcurrentInitializerTest.java
>>>>>>>>>> (original)
>>>>>>>>>> +++
>>>>>>>>>>
>>>>>>>>
>>>>>>
>>>>
>> commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/concurrent/AbstractConcurrentInitializerTest.java
>>>>>>>>>> Mon Feb 23 20:15:49 2015
>>>>>>>>>> @@ -18,6 +18,8 @@ package org.apache.commons.lang3.concurr
>>>>>>>>>>
>>>>>>>>>>  import static org.junit.Assert.assertEquals;
>>>>>>>>>>  import static org.junit.Assert.assertNotNull;
>>>>>>>>>> +import static org.junit.Assert.assertSame;
>>>>>>>>>> +import static org.junit.Assert.assertTrue;
>>>>>>>>>>
>>>>>>>>>>  import java.util.concurrent.CountDownLatch;
>>>>>>>>>>
>>>>>>>>>> @@ -72,7 +74,41 @@ public abstract class AbstractConcurrent
>>>>>>>>>>      @Test
>>>>>>>>>>      public void testGetConcurrent() throws ConcurrentException,
>>>>>>>>>>              InterruptedException {
>>>>>>>>>> -        final ConcurrentInitializer<Object> initializer =
>>>>>>>>>> createInitializer();
>>>>>>>>>> +
>>>>>>>>>> +        this.testGetConcurrentOptionallyWithException(false,
>> null,
>>>>>>>> null);
>>>>>>>>>> +    }
>>>>>>>>>> +
>>>>>>>>>> +    /**
>>>>>>>>>> +     * Tests the handling of exceptions thrown on the initialized
>>>>>> when
>>>>>>>>>> multiple threads execute concurrently.
>>>>>>>>>> +     * Always an exception with the same message and cause should
>>>> be
>>>>>>>>>> thrown.
>>>>>>>>>> +     *
>>>>>>>>>> +     * @throws
>>>>>> org.apache.commons.lang3.concurrent.ConcurrentException
>>>>>>>>>> because the object under test may throw it
>>>>>>>>>> +     * @throws java.lang.InterruptedException because the
>> threading
>>>>>> API
>>>>>>>>>> my throw it
>>>>>>>>>> +     */
>>>>>>>>>> +    public void testGetConcurrentWithException(String
>>>>>> expectedMessage,
>>>>>>>>>> +                                               Exception
>>>>>> expectedCause)
>>>>>>>>>> +            throws ConcurrentException, InterruptedException {
>>>>>>>>>> +
>>>>>>>>>> +        this.testGetConcurrentOptionallyWithException(true,
>>>>>>>>>> expectedMessage, expectedCause);
>>>>>>>>>> +    }
>>>>>>>>>> +
>>>>>>>>>> +    /**
>>>>>>>>>> +     * Tests whether get() can be invoked from multiple threads
>>>>>>>>>> concurrently.  Supports the exception-handling case
>>>>>>>>>> +     * and the normal, non-exception case.
>>>>>>>>>> +     *
>>>>>>>>>> +     * Always the same object should be returned, or an exception
>>>>>> with
>>>>>>>>>> the same message and cause should be thrown.
>>>>>>>>>> +     *
>>>>>>>>>> +     * @throws
>>>>>> org.apache.commons.lang3.concurrent.ConcurrentException
>>>>>>>>>> because the object under test may throw it
>>>>>>>>>> +     * @throws java.lang.InterruptedException because the
>> threading
>>>>>> API
>>>>>>>>>> my throw it
>>>>>>>>>> +     */
>>>>>>>>>> +    protected void
>> testGetConcurrentOptionallyWithException(boolean
>>>>>>>>>> expectExceptions, String expectedMessage,
>>>>>>>>>> +
>>>> Exception
>>>>>>>>>> expectedCause)
>>>>>>>>>> +            throws ConcurrentException, InterruptedException {
>>>>>>>>>> +
>>>>>>>>>> +        final ConcurrentInitializer<Object> initializer =
>>>>>>>>>> expectExceptions ?
>>>>>>>>>> +                createExceptionThrowingInitializer() :
>>>>>>>>>> +                createInitializer();
>>>>>>>>>> +
>>>>>>>>>>          final int threadCount = 20;
>>>>>>>>>>          final CountDownLatch startLatch = new CountDownLatch(1);
>>>>>>>>>>          class GetThread extends Thread {
>>>>>>>>>> @@ -106,9 +142,18 @@ public abstract class AbstractConcurrent
>>>>>>>>>>          }
>>>>>>>>>>
>>>>>>>>>>          // check results
>>>>>>>>>> -        final Object managedObject = initializer.get();
>>>>>>>>>> -        for (final GetThread t : threads) {
>>>>>>>>>> -            assertEquals("Wrong object", managedObject,
>> t.object);
>>>>>>>>>> +        if ( expectExceptions ) {
>>>>>>>>>> +            for (GetThread t : threads) {
>>>>>>>>>> +                assertTrue(t.object instanceof Exception);
>>>>>>>>>> +                Exception exc = (Exception) t.object;
>>>>>>>>>> +                assertEquals(expectedMessage, exc.getMessage());
>>>>>>>>>> +                assertSame(expectedCause, exc.getCause());
>>>>>>>>>> +            }
>>>>>>>>>> +        } else {
>>>>>>>>>> +            final Object managedObject = initializer.get();
>>>>>>>>>> +            for (final GetThread t : threads) {
>>>>>>>>>> +                assertEquals("Wrong object", managedObject,
>>>>>> t.object);
>>>>>>>>>> +            }
>>>>>>>>>>          }
>>>>>>>>>>      }
>>>>>>>>>>
>>>>>>>>>> @@ -119,4 +164,12 @@ public abstract class AbstractConcurrent
>>>>>>>>>>       * @return the initializer object to be tested
>>>>>>>>>>       */
>>>>>>>>>>      protected abstract ConcurrentInitializer<Object>
>>>>>>>> createInitializer();
>>>>>>>>>> +
>>>>>>>>>> +    /**
>>>>>>>>>> +     * Creates a {@link ConcurrentInitializer} object that always
>>>>>>>> throws
>>>>>>>>>> +     * exceptions.
>>>>>>>>>> +     *
>>>>>>>>>> +     * @return
>>>>>>>>>> +     */
>>>>>>>>>> +    protected abstract ConcurrentInitializer<Object>
>>>>>>>>>> createExceptionThrowingInitializer();
>>>>>>>>>>  }
>>>>>>>>>>
>>>>>>>>>> Modified:
>>>>>>>>>>
>>>>>>>>
>>>>>>
>>>>
>> commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/concurrent/AtomicInitializerTest.java
>>>>>>>>>> URL:
>>>>>>>>>>
>>>>>>>>
>>>>>>
>>>>
>> http://svn.apache.org/viewvc/commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/concurrent/AtomicInitializerTest.java?rev=1661762&r1=1661761&r2=1661762&view=diff
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>
>>>>>>
>>>>
>> ==============================================================================
>>>>>>>>>> ---
>>>>>>>>>>
>>>>>>>>
>>>>>>
>>>>
>> commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/concurrent/AtomicInitializerTest.java
>>>>>>>>>> (original)
>>>>>>>>>> +++
>>>>>>>>>>
>>>>>>>>
>>>>>>
>>>>
>> commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/concurrent/AtomicInitializerTest.java
>>>>>>>>>> Mon Feb 23 20:15:49 2015
>>>>>>>>>> @@ -16,12 +16,29 @@
>>>>>>>>>>   */
>>>>>>>>>>  package org.apache.commons.lang3.concurrent;
>>>>>>>>>>
>>>>>>>>>> +import org.junit.Test;
>>>>>>>>>> +
>>>>>>>>>>  /**
>>>>>>>>>>   * Test class for {@code AtomicInitializer}.
>>>>>>>>>>   *
>>>>>>>>>>   * @version $Id$
>>>>>>>>>>   */
>>>>>>>>>>  public class AtomicInitializerTest extends
>>>>>>>>>> AbstractConcurrentInitializerTest {
>>>>>>>>>> +    private Exception testCauseException;
>>>>>>>>>> +    private String testExceptionMessage;
>>>>>>>>>> +
>>>>>>>>>> +    public AtomicInitializerTest() {
>>>>>>>>>> +        testExceptionMessage = "x-test-exception-message-x";
>>>>>>>>>> +        testCauseException = new Exception(testExceptionMessage);
>>>>>>>>>> +    }
>>>>>>>>>> +
>>>>>>>>>> +    @Test
>>>>>>>>>> +    public void testGetConcurrentWithException ()
>>>>>>>>>> +            throws ConcurrentException, InterruptedException {
>>>>>>>>>> +
>>>>>>>>>> +
>> super.testGetConcurrentWithException(testExceptionMessage,
>>>>>>>>>> testCauseException);
>>>>>>>>>> +    }
>>>>>>>>>> +
>>>>>>>>>>      /**
>>>>>>>>>>       * Returns the initializer to be tested.
>>>>>>>>>>       *
>>>>>>>>>> @@ -36,4 +53,20 @@ public class AtomicInitializerTest exten
>>>>>>>>>>              }
>>>>>>>>>>          };
>>>>>>>>>>      }
>>>>>>>>>> +
>>>>>>>>>> +    @Override
>>>>>>>>>> +    protected ConcurrentInitializer<Object>
>>>>>>>>>> createExceptionThrowingInitializer() {
>>>>>>>>>> +        return new
>>>> ExceptionThrowingAtomicSafeInitializerTestImpl();
>>>>>>>>>> +    }
>>>>>>>>>> +
>>>>>>>>>> +    /**
>>>>>>>>>> +     * A concrete test implementation of {@code
>>>>>> AtomicSafeInitializer}.
>>>>>>>>>> This
>>>>>>>>>> +     * implementation always throws an exception.
>>>>>>>>>> +     */
>>>>>>>>>> +    private class ExceptionThrowingAtomicSafeInitializerTestImpl
>>>>>>>> extends
>>>>>>>>>> AtomicSafeInitializer<Object> {
>>>>>>>>>> +        @Override
>>>>>>>>>> +        protected Object initialize() throws ConcurrentException
>> {
>>>>>>>>>> +            throw new ConcurrentException(testExceptionMessage,
>>>>>>>>>> testCauseException);
>>>>>>>>>> +        }
>>>>>>>>>> +    }
>>>>>>>>>>  }
>>>>>>>>>>
>>>>>>>>>> Modified:
>>>>>>>>>>
>>>>>>>>
>>>>>>
>>>>
>> commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/concurrent/AtomicSafeInitializerTest.java
>>>>>>>>>> URL:
>>>>>>>>>>
>>>>>>>>
>>>>>>
>>>>
>> http://svn.apache.org/viewvc/commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/concurrent/AtomicSafeInitializerTest.java?rev=1661762&r1=1661761&r2=1661762&view=diff
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>
>>>>>>
>>>>
>> ==============================================================================
>>>>>>>>>> ---
>>>>>>>>>>
>>>>>>>>
>>>>>>
>>>>
>> commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/concurrent/AtomicSafeInitializerTest.java
>>>>>>>>>> (original)
>>>>>>>>>> +++
>>>>>>>>>>
>>>>>>>>
>>>>>>
>>>>
>> commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/concurrent/AtomicSafeInitializerTest.java
>>>>>>>>>> Mon Feb 23 20:15:49 2015
>>>>>>>>>> @@ -17,7 +17,11 @@
>>>>>>>>>>  package org.apache.commons.lang3.concurrent;
>>>>>>>>>>
>>>>>>>>>>  import static org.junit.Assert.assertEquals;
>>>>>>>>>> +import static org.junit.Assert.assertFalse;
>>>>>>>>>> +import static org.junit.Assert.assertSame;
>>>>>>>>>> +import static org.junit.Assert.assertTrue;
>>>>>>>>>>
>>>>>>>>>> +import java.util.concurrent.CountDownLatch;
>>>>>>>>>>  import java.util.concurrent.atomic.AtomicInteger;
>>>>>>>>>>
>>>>>>>>>>  import org.junit.Before;
>>>>>>>>>> @@ -30,12 +34,19 @@ import org.junit.Test;
>>>>>>>>>>   */
>>>>>>>>>>  public class AtomicSafeInitializerTest extends
>>>>>>>>>>          AbstractConcurrentInitializerTest {
>>>>>>>>>> +
>>>>>>>>>>      /** The instance to be tested. */
>>>>>>>>>>      private AtomicSafeInitializerTestImpl initializer;
>>>>>>>>>> +    private ExceptionThrowingAtomicSafeInitializerTestImpl
>>>>>>>>>> exceptionThrowingInitializer;
>>>>>>>>>> +    private Exception testCauseException;
>>>>>>>>>> +    private String testExceptionMessage;
>>>>>>>>>>
>>>>>>>>>>      @Before
>>>>>>>>>>      public void setUp() throws Exception {
>>>>>>>>>>          initializer = new AtomicSafeInitializerTestImpl();
>>>>>>>>>> +        exceptionThrowingInitializer = new
>>>>>>>>>> ExceptionThrowingAtomicSafeInitializerTestImpl();
>>>>>>>>>> +        testExceptionMessage = "x-test-exception-message-x";
>>>>>>>>>> +        testCauseException = new Exception(testExceptionMessage);
>>>>>>>>>>      }
>>>>>>>>>>
>>>>>>>>>>      /**
>>>>>>>>>> @@ -49,6 +60,17 @@ public class AtomicSafeInitializerTest e
>>>>>>>>>>      }
>>>>>>>>>>
>>>>>>>>>>      /**
>>>>>>>>>> +     * Returns the exception-throwing initializer to be tested.
>>>>>>>>>> +     *
>>>>>>>>>> +     * @return the {@code AtomicSafeInitializer} under test when
>>>>>>>>>> validating
>>>>>>>>>> +     * exception handling
>>>>>>>>>> +     */
>>>>>>>>>> +    @Override
>>>>>>>>>> +    protected ConcurrentInitializer<Object>
>>>>>>>>>> createExceptionThrowingInitializer() {
>>>>>>>>>> +        return exceptionThrowingInitializer;
>>>>>>>>>> +    }
>>>>>>>>>> +
>>>>>>>>>> +    /**
>>>>>>>>>>       * Tests that initialize() is called only once.
>>>>>>>>>>       *
>>>>>>>>>>       * @throws
>>>>>> org.apache.commons.lang3.concurrent.ConcurrentException
>>>>>>>>>> because {@link #testGetConcurrent()} may throw it
>>>>>>>>>> @@ -62,6 +84,92 @@ public class AtomicSafeInitializerTest e
>>>>>>>>>>                  initializer.initCounter.get());
>>>>>>>>>>      }
>>>>>>>>>>
>>>>>>>>>> +    @Test
>>>>>>>>>> +    public void testExceptionOnInitialize() throws
>>>>>> ConcurrentException,
>>>>>>>>>> +            InterruptedException {
>>>>>>>>>> +
>>>>>>>>>> +        testGetConcurrentWithException(testExceptionMessage,
>>>>>>>>>> testCauseException);
>>>>>>>>>> +    }
>>>>>>>>>> +
>>>>>>>>>> +    /**
>>>>>>>>>> +     * Validate the handling of an interrupted exception on a
>>>> thread
>>>>>>>>>> waiting for another thread to finish calling the
>>>>>>>>>> +     * initialize() method.
>>>>>>>>>> +     *
>>>>>>>>>> +     * @throws Exception
>>>>>>>>>> +     */
>>>>>>>>>> +    @Test(timeout = 3000)
>>>>>>>>>> +    public void testInterruptedWaitingOnInitialize() throws
>>>>>> Exception {
>>>>>>>>>> +        this.execTestWithWaitingOnInitialize(true);
>>>>>>>>>> +    }
>>>>>>>>>> +
>>>>>>>>>> +    /**
>>>>>>>>>> +     * Test the success path of two threads reaching the
>>>>>> initialization
>>>>>>>>>> point at the same time.
>>>>>>>>>> +     */
>>>>>>>>>> +    @Test(timeout = 3000)
>>>>>>>>>> +    public void testOneThreadWaitingForAnotherToInitialize ()
>>>> throws
>>>>>>>>>> Exception {
>>>>>>>>>> +        execTestWithWaitingOnInitialize(false);
>>>>>>>>>> +    }
>>>>>>>>>> +
>>>>>>>>>> +
>>>>>>>>>> +    /**
>>>>>>>>>> +     * Execute a test that requires one thread to be waiting on
>> the
>>>>>>>>>> initialize() method of another thread.  This test
>>>>>>>>>> +     * uses latches to guarantee the code path being tested.
>>>>>>>>>> +     *
>>>>>>>>>> +     * @throws Exception
>>>>>>>>>> +     */
>>>>>>>>>> +    protected void execTestWithWaitingOnInitialize(boolean
>>>>>>>> interruptInd)
>>>>>>>>>> throws Exception {
>>>>>>>>>> +        final CountDownLatch startLatch = new CountDownLatch(1);
>>>>>>>>>> +        final CountDownLatch finishLatch = new CountDownLatch(1);
>>>>>>>>>> +        final WaitingInitializerTestImpl initializer = new
>>>>>>>>>> WaitingInitializerTestImpl(startLatch, finishLatch);
>>>>>>>>>> +
>>>>>>>>>> +        InitializerTestThread execThread1 = new
>>>>>>>>>> InitializerTestThread(initializer);
>>>>>>>>>> +        InitializerTestThread execThread2 = new
>>>>>>>>>> InitializerTestThread(initializer);
>>>>>>>>>> +
>>>>>>>>>> +        // Start the first thread and wait for it to get into the
>>>>>>>>>> initialize method so we are sure it is the thread
>>>>>>>>>> +        //  executing initialize().
>>>>>>>>>> +        execThread1.start();
>>>>>>>>>> +        startLatch.await();
>>>>>>>>>> +
>>>>>>>>>> +        // Start the second thread and interrupt it to force the
>>>>>>>>>> InterruptedException.  There is no need to make sure
>>>>>>>>>> +        //  the thread reaches the await() call before
>> interrupting
>>>>>> it.
>>>>>>>>>> +        execThread2.start();
>>>>>>>>>> +
>>>>>>>>>> +        if ( interruptInd ) {
>>>>>>>>>> +            // Interrupt the second thread now and wait for it to
>>>>>>>>>> complete to ensure it reaches the wait inside the
>>>>>>>>>> +            //  get() method.
>>>>>>>>>> +            execThread2.interrupt();
>>>>>>>>>> +            execThread2.join();
>>>>>>>>>> +        }
>>>>>>>>>> +
>>>>>>>>>> +        // Signal the completion of the initialize method now.
>>>>>>>>>> +        finishLatch.countDown();
>>>>>>>>>> +
>>>>>>>>>> +        // Wait for the initialize() to finish.
>>>>>>>>>> +        execThread1.join();
>>>>>>>>>> +
>>>>>>>>>> +        // Wait for thread2 to finish, if it was not already done
>>>>>>>>>> +        if ( ! interruptInd ) {
>>>>>>>>>> +            execThread2.join();
>>>>>>>>>> +        }
>>>>>>>>>> +
>>>>>>>>>> +        //
>>>>>>>>>> +        // Validate: thread1 should have the valid result;
>> thread2
>>>>>>>> should
>>>>>>>>>> have caught an interrupted exception, if
>>>>>>>>>> +        //  interrupted, or should have the same result
>> otherwise.
>>>>>>>>>> +        //
>>>>>>>>>> +        assertFalse(execThread1.isCaughtException());
>>>>>>>>>> +        assertSame(initializer.getAnswer(),
>>>> execThread1.getResult());
>>>>>>>>>> +
>>>>>>>>>> +        if ( interruptInd ) {
>>>>>>>>>> +            assertTrue(execThread2.isCaughtException());
>>>>>>>>>> +            Exception exc = (Exception) execThread2.getResult();
>>>>>>>>>> +            assertTrue(exc.getCause() instanceof
>>>>>> InterruptedException);
>>>>>>>>>> +            assertEquals("interrupted waiting for initialization
>> to
>>>>>>>>>> complete", exc.getMessage());
>>>>>>>>>> +        } else {
>>>>>>>>>> +            assertFalse(execThread2.isCaughtException());
>>>>>>>>>> +            assertSame(initializer.getAnswer(),
>>>>>>>> execThread2.getResult());
>>>>>>>>>> +        }
>>>>>>>>>> +    }
>>>>>>>>>> +
>>>>>>>>>>      /**
>>>>>>>>>>       * A concrete test implementation of {@code
>>>>>> AtomicSafeInitializer}.
>>>>>>>>>> This
>>>>>>>>>>       * implementation also counts the number of invocations of
>> the
>>>>>>>>>> initialize()
>>>>>>>>>> @@ -78,4 +186,90 @@ public class AtomicSafeInitializerTest e
>>>>>>>>>>              return new Object();
>>>>>>>>>>          }
>>>>>>>>>>      }
>>>>>>>>>> +
>>>>>>>>>> +    /**
>>>>>>>>>> +     * A concrete test implementation of {@code
>>>>>> AtomicSafeInitializer}.
>>>>>>>>>> This
>>>>>>>>>> +     * implementation always throws an exception.
>>>>>>>>>> +     */
>>>>>>>>>> +    private class ExceptionThrowingAtomicSafeInitializerTestImpl
>>>>>>>> extends
>>>>>>>>>> AtomicSafeInitializer<Object> {
>>>>>>>>>> +        @Override
>>>>>>>>>> +        protected Object initialize() throws ConcurrentException
>> {
>>>>>>>>>> +            throw new ConcurrentException(testExceptionMessage,
>>>>>>>>>> testCauseException);
>>>>>>>>>> +        }
>>>>>>>>>> +    }
>>>>>>>>>> +
>>>>>>>>>> +    /**
>>>>>>>>>> +     * Initializer that signals it has started and waits to
>>>> complete
>>>>>>>>>> until signalled in order to enable a guaranteed
>>>>>>>>>> +     * order-of-operations.  This allows the test code to peg one
>>>>>>>> thread
>>>>>>>>>> to the initialize method for a period of time
>>>>>>>>>> +     * that the test can dictate.
>>>>>>>>>> +     */
>>>>>>>>>> +    private class WaitingInitializerTestImpl extends
>>>>>>>>>> AtomicSafeInitializer<Object> {
>>>>>>>>>> +        private final CountDownLatch startedLatch;
>>>>>>>>>> +        private final CountDownLatch finishLatch;
>>>>>>>>>> +        private final Object answer = new Object();
>>>>>>>>>> +
>>>>>>>>>> +        public WaitingInitializerTestImpl(CountDownLatch
>>>>>> startedLatch,
>>>>>>>>>> CountDownLatch finishLatch) {
>>>>>>>>>> +            this.startedLatch = startedLatch;
>>>>>>>>>> +            this.finishLatch = finishLatch;
>>>>>>>>>> +        }
>>>>>>>>>> +
>>>>>>>>>> +        @Override
>>>>>>>>>> +        protected Object initialize() throws ConcurrentException
>> {
>>>>>>>>>> +            this.startedLatch.countDown();
>>>>>>>>>> +            try {
>>>>>>>>>> +                this.finishLatch.await();
>>>>>>>>>> +            } catch (InterruptedException intExc) {
>>>>>>>>>> +                throw new ConcurrentException(intExc);
>>>>>>>>>> +            }
>>>>>>>>>> +
>>>>>>>>>> +            return  answer;
>>>>>>>>>> +        }
>>>>>>>>>> +
>>>>>>>>>> +        public Object getAnswer () {
>>>>>>>>>> +            return answer;
>>>>>>>>>> +        }
>>>>>>>>>> +    }
>>>>>>>>>> +
>>>>>>>>>> +    /**
>>>>>>>>>> +     * Test executor of the initializer get() operation that
>>>> captures
>>>>>>>> the
>>>>>>>>>> result.
>>>>>>>>>> +     */
>>>>>>>>>> +    private class InitializerTestThread extends Thread {
>>>>>>>>>> +        private AtomicSafeInitializer<Object>   initializer;
>>>>>>>>>> +        private Object result;
>>>>>>>>>> +        private boolean caughtException;
>>>>>>>>>> +
>>>>>>>>>> +        public
>> InitializerTestThread(AtomicSafeInitializer<Object>
>>>>>>>>>> initializer) {
>>>>>>>>>> +            super("AtomicSafeInitializer test thread");
>>>>>>>>>> +            this.initializer = initializer;
>>>>>>>>>> +        }
>>>>>>>>>> +
>>>>>>>>>> +        @Override
>>>>>>>>>> +        public void run() {
>>>>>>>>>> +            try {
>>>>>>>>>> +                this.result = initializer.get();
>>>>>>>>>> +            } catch ( ConcurrentException concurrentExc ) {
>>>>>>>>>> +                this.caughtException = true;
>>>>>>>>>> +                this.result = concurrentExc;
>>>>>>>>>> +            }
>>>>>>>>>> +        }
>>>>>>>>>> +
>>>>>>>>>> +        /**
>>>>>>>>>> +         * Resulting object, if the get() method returned
>>>>>> successfully,
>>>>>>>>>> or exception if an exception was thrown.
>>>>>>>>>> +         *
>>>>>>>>>> +         * @return resulting object or exception from the get()
>>>>>> method
>>>>>>>>>> call.
>>>>>>>>>> +         */
>>>>>>>>>> +        public Object getResult () {
>>>>>>>>>> +            return  this.result;
>>>>>>>>>> +        }
>>>>>>>>>> +
>>>>>>>>>> +        /**
>>>>>>>>>> +         * Determine whether an exception was caught on the get()
>>>>>> call.
>>>>>>>>>> Does not guarantee that the get() method was
>>>>>>>>>> +         * called or completed.
>>>>>>>>>> +         *
>>>>>>>>>> +         * @return true => exception was caught; false =>
>> exception
>>>>>> was
>>>>>>>>>> not caught.
>>>>>>>>>> +         */
>>>>>>>>>> +        public boolean  isCaughtException () {
>>>>>>>>>> +            return  this.caughtException;
>>>>>>>>>> +        }
>>>>>>>>>> +    }
>>>>>>>>>>  }
>>>>>>>>>>
>>>>>>>>>> Modified:
>>>>>>>>>>
>>>>>>>>
>>>>>>
>>>>
>> commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/concurrent/LazyInitializerTest.java
>>>>>>>>>> URL:
>>>>>>>>>>
>>>>>>>>
>>>>>>
>>>>
>> http://svn.apache.org/viewvc/commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/concurrent/LazyInitializerTest.java?rev=1661762&r1=1661761&r2=1661762&view=diff
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>
>>>>>>
>>>>
>> ==============================================================================
>>>>>>>>>> ---
>>>>>>>>>>
>>>>>>>>
>>>>>>
>>>>
>> commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/concurrent/LazyInitializerTest.java
>>>>>>>>>> (original)
>>>>>>>>>> +++
>>>>>>>>>>
>>>>>>>>
>>>>>>
>>>>
>> commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/concurrent/LazyInitializerTest.java
>>>>>>>>>> Mon Feb 23 20:15:49 2015
>>>>>>>>>> @@ -17,6 +17,7 @@
>>>>>>>>>>  package org.apache.commons.lang3.concurrent;
>>>>>>>>>>
>>>>>>>>>>  import org.junit.Before;
>>>>>>>>>> +import org.junit.Test;
>>>>>>>>>>
>>>>>>>>>>  /**
>>>>>>>>>>   * Test class for {@code LazyInitializer}.
>>>>>>>>>> @@ -26,10 +27,16 @@ import org.junit.Before;
>>>>>>>>>>  public class LazyInitializerTest extends
>>>>>>>>>> AbstractConcurrentInitializerTest {
>>>>>>>>>>      /** The initializer to be tested. */
>>>>>>>>>>      private LazyInitializerTestImpl initializer;
>>>>>>>>>> +    private ExceptionThrowingLazyInitializerTestImpl
>>>>>>>>>> exceptionThrowingInitializer;
>>>>>>>>>> +    private Exception testCauseException;
>>>>>>>>>> +    private String testExceptionMessage;
>>>>>>>>>>
>>>>>>>>>>      @Before
>>>>>>>>>>      public void setUp() throws Exception {
>>>>>>>>>>          initializer = new LazyInitializerTestImpl();
>>>>>>>>>> +        exceptionThrowingInitializer = new
>>>>>>>>>> ExceptionThrowingLazyInitializerTestImpl();
>>>>>>>>>> +        testExceptionMessage = "x-test-exception-message-x";
>>>>>>>>>> +        testCauseException = new Exception(testExceptionMessage);
>>>>>>>>>>      }
>>>>>>>>>>
>>>>>>>>>>      /**
>>>>>>>>>> @@ -43,6 +50,18 @@ public class LazyInitializerTest extends
>>>>>>>>>>          return initializer;
>>>>>>>>>>      }
>>>>>>>>>>
>>>>>>>>>> +    @Override
>>>>>>>>>> +    protected ConcurrentInitializer<Object>
>>>>>>>>>> createExceptionThrowingInitializer() {
>>>>>>>>>> +        return exceptionThrowingInitializer;
>>>>>>>>>> +    }
>>>>>>>>>> +
>>>>>>>>>> +    @Test
>>>>>>>>>> +    public void testGetConcurrentWithException ()
>>>>>>>>>> +            throws ConcurrentException, InterruptedException {
>>>>>>>>>> +
>>>>>>>>>> +
>> super.testGetConcurrentWithException(testExceptionMessage,
>>>>>>>>>> testCauseException);
>>>>>>>>>> +    }
>>>>>>>>>> +
>>>>>>>>>>      /**
>>>>>>>>>>       * A test implementation of LazyInitializer. This class
>>>> creates a
>>>>>>>>>> plain
>>>>>>>>>>       * Object. As Object does not provide a specific equals()
>>>> method,
>>>>>>>> it
>>>>>>>>>> is easy
>>>>>>>>>> @@ -55,4 +74,16 @@ public class LazyInitializerTest extends
>>>>>>>>>>              return new Object();
>>>>>>>>>>          }
>>>>>>>>>>      }
>>>>>>>>>> +
>>>>>>>>>> +
>>>>>>>>>> +    /**
>>>>>>>>>> +     * A concrete test implementation of {@code
>>>>>> AtomicSafeInitializer}.
>>>>>>>>>> This
>>>>>>>>>> +     * implementation always throws an exception.
>>>>>>>>>> +     */
>>>>>>>>>> +    private class ExceptionThrowingLazyInitializerTestImpl
>> extends
>>>>>>>>>> LazyInitializer<Object> {
>>>>>>>>>> +        @Override
>>>>>>>>>> +        protected Object initialize() throws ConcurrentException
>> {
>>>>>>>>>> +            throw new ConcurrentException(testExceptionMessage,
>>>>>>>>>> testCauseException);
>>>>>>>>>> +        }
>>>>>>>>>> +    }
>>>>>>>>>>  }
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>
>>>>>>>>
>> ---------------------------------------------------------------------
>>>>>>>> To unsubscribe, e-mail: dev-unsubscr...@commons.apache.org
>>>>>>>> For additional commands, e-mail: dev-h...@commons.apache.org
>>>>>>>>
>>>>>>>>
>>>>>>>
>>>>>>
>>>>>> ---------------------------------------------------------------------
>>>>>> To unsubscribe, e-mail: dev-unsubscr...@commons.apache.org
>>>>>> For additional commands, e-mail: dev-h...@commons.apache.org
>>>>>>
>>>>>>
>>>>>
>>>>>
>>>>
>>>> ---------------------------------------------------------------------
>>>> To unsubscribe, e-mail: dev-unsubscr...@commons.apache.org
>>>> For additional commands, e-mail: dev-h...@commons.apache.org
>>>>
>>>>
>>>
>>>
>>
>> ---------------------------------------------------------------------
>> To unsubscribe, e-mail: dev-unsubscr...@commons.apache.org
>> For additional commands, e-mail: dev-h...@commons.apache.org
>>
>>
> 
> 

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscr...@commons.apache.org
For additional commands, e-mail: dev-h...@commons.apache.org

Reply via email to