restrict access to TrainingContext; rework method names; permit interrupt-then-resume stubbing

git-svn-id: https://svn.apache.org/repos/asf/commons/proper/proxy/branches/version-2.0-work@1555237 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/core/src/main/java/org/apache/commons/proxy2/stub/BaseTrainer.java b/core/src/main/java/org/apache/commons/proxy2/stub/BaseTrainer.java
index f053875..8c386da 100644
--- a/core/src/main/java/org/apache/commons/proxy2/stub/BaseTrainer.java
+++ b/core/src/main/java/org/apache/commons/proxy2/stub/BaseTrainer.java
@@ -110,7 +110,7 @@
 
     protected TrainingContext trainingContext()
     {
-        return TrainingContext.getCurrent();
+        return TrainingContext.current();
     }
 
     public <R> WhenObject<R> when(R expression)
diff --git a/core/src/main/java/org/apache/commons/proxy2/stub/StubBuilder.java b/core/src/main/java/org/apache/commons/proxy2/stub/StubBuilder.java
index 6d7e25d..8b3b261 100644
--- a/core/src/main/java/org/apache/commons/proxy2/stub/StubBuilder.java
+++ b/core/src/main/java/org/apache/commons/proxy2/stub/StubBuilder.java
@@ -84,16 +84,16 @@
 
     public <O> StubBuilder<T> train(BaseTrainer<?, O> trainer)
     {
+        final TrainingContext trainingContext = TrainingContext.join(proxyFactory);
         try
         {
-            TrainingContext trainingContext = TrainingContext.set(proxyFactory);
             final O trainee = trainingContext.push(trainer.traineeType, switchInterceptor);
             trainer.train(trainee);
             proxyTypes.add(trainer.traineeType);
         }
         finally
         {
-            TrainingContext.clear();
+            trainingContext.part();
         }
         return this;
     }
diff --git a/core/src/main/java/org/apache/commons/proxy2/stub/StubInterceptorBuilder.java b/core/src/main/java/org/apache/commons/proxy2/stub/StubInterceptorBuilder.java
index 0902c95..dff59f9 100644
--- a/core/src/main/java/org/apache/commons/proxy2/stub/StubInterceptorBuilder.java
+++ b/core/src/main/java/org/apache/commons/proxy2/stub/StubInterceptorBuilder.java
@@ -50,15 +50,15 @@
 
     public <T> StubInterceptorBuilder train(Trainer<T> trainer)
     {
+        final TrainingContext trainingContext = TrainingContext.join(proxyFactory);
         try
         {
-            final TrainingContext trainingContext = TrainingContext.set(proxyFactory);
             final T stub = trainingContext.push(trainer.traineeType, interceptor);
             trainer.train(stub);
         }
         finally
         {
-            TrainingContext.clear();
+            trainingContext.part();
         }
         return this;
     }
diff --git a/core/src/main/java/org/apache/commons/proxy2/stub/TrainingContext.java b/core/src/main/java/org/apache/commons/proxy2/stub/TrainingContext.java
index e7d5f93..dc964d2 100644
--- a/core/src/main/java/org/apache/commons/proxy2/stub/TrainingContext.java
+++ b/core/src/main/java/org/apache/commons/proxy2/stub/TrainingContext.java
@@ -12,7 +12,7 @@
 import java.lang.reflect.Method;
 import java.util.*;
 
-public class TrainingContext
+class TrainingContext
 {
 //----------------------------------------------------------------------------------------------------------------------
 // Fields
@@ -24,23 +24,20 @@
 
     private Deque<TrainingContextFrame<?>> frameDeque = new LinkedList<TrainingContextFrame<?>>();
 
+    private final TrainingContext resume;
+
 //----------------------------------------------------------------------------------------------------------------------
 // Static Methods
 //----------------------------------------------------------------------------------------------------------------------
 
-    public static void clear()
-    {
-        TRAINING_CONTEXT.remove();
-    }
-
-    public static TrainingContext getCurrent()
+    static TrainingContext current()
     {
         return TRAINING_CONTEXT.get();
     }
 
-    public static TrainingContext set(ProxyFactory proxyFactory)
+    static TrainingContext join(ProxyFactory proxyFactory)
     {
-        TrainingContext context = new TrainingContext(proxyFactory);
+        final TrainingContext context = new TrainingContext(proxyFactory);
         TRAINING_CONTEXT.set(context);
         return context;
     }
@@ -49,15 +46,28 @@
 // Constructors
 //----------------------------------------------------------------------------------------------------------------------
 
-    public TrainingContext(ProxyFactory proxyFactory)
+    private TrainingContext(ProxyFactory proxyFactory)
     {
         this.proxyFactory = proxyFactory;
+        this.resume = current();
     }
 
 //----------------------------------------------------------------------------------------------------------------------
 // Other Methods
 //----------------------------------------------------------------------------------------------------------------------
 
+    void part()
+    {
+        if (resume == null)
+        {
+            TRAINING_CONTEXT.remove();
+        }
+        else
+        {
+            TRAINING_CONTEXT.set(resume);
+        }
+    }
+
     private TrainingContextFrame<?> peek()
     {
         return frameDeque.peek();
@@ -90,12 +100,12 @@
         return proxyFactory.createInvokerProxy(invoker, type);
     }
 
-    public void record(ArgumentMatcher<?> argumentMatcher)
+    void record(ArgumentMatcher<?> argumentMatcher)
     {
         peek().argumentMatchers.add(argumentMatcher);
     }
 
-    public void then(Interceptor interceptor)
+    void then(Interceptor interceptor)
     {
         peek().then(interceptor);
     }
@@ -222,7 +232,7 @@
         @Override
         public Object invoke(Object proxy, Method method, Object[] arguments) throws Throwable
         {
-            final TrainingContextFrame<?> frame = getCurrent().peek();
+            final TrainingContextFrame<?> frame = current().peek();
             if (!frame.getId().equals(id))
             {
                 throw new IllegalStateException("Wrong stub!");
diff --git a/test/src/test/java/org/apache/commons/proxy2/stub/AbstractStubTestCase.java b/test/src/test/java/org/apache/commons/proxy2/stub/AbstractStubTestCase.java
index 3908793..534a26d 100644
--- a/test/src/test/java/org/apache/commons/proxy2/stub/AbstractStubTestCase.java
+++ b/test/src/test/java/org/apache/commons/proxy2/stub/AbstractStubTestCase.java
@@ -413,4 +413,29 @@
         });
         assertArrayEquals(new String[] { "One", "Two" }, proxy.stringArray());
     }
+
+    /*
+     * This test replicates #thenStub() functionality in a more "ignorant" (ergo versatile) manner.
+     */
+    @Test
+    public void testInterruptResume()
+    {
+        final StubInterface proxy = createProxy(new Trainer<StubInterface>()
+        {
+            @Override
+            protected void train(StubInterface trainee)
+            {
+                when(trainee.stub()).thenReturn(createProxy(new Trainer<StubInterface>()
+                {
+                    @Override
+                    protected void train(StubInterface trainee)
+                    {
+                        when(trainee.one("Hello")).thenReturn("World");
+                    }
+                }));
+            }
+        });
+        assertNotNull(proxy.stub());
+        assertEquals("World", proxy.stub().one("Hello"));
+    }
 }