RE: [picocontainer-dev] Visitor Work

"Michael Rimov" <[email protected]> Fri, 20 Jun 2008 21:48:41 -0700
Newsgroups gmane.comp.java.picocontainer.devel
Organization Centerline Computers, Inc
Message-ID <004601c8d35a$16163290$424297b0$@com>
Ok, here you go.  I ultimately only modified one signature:   boolean
visitContainer(Pico).

 

What this allows me to do is pseudo lifecycles that are implemented via
Visitors, and most importantly, when I have a stack of 5-6 containers deep, I
can make sure I only apply the visitor to one container.  

 

It isn't the most efficient implementation, but it does cover what I need, and
is much less invasive than allowing "abort points" for every visitor callback.
(Which would result in modification of the accept() methods as well)

 

Let me know if this works.

 

 
-Mike

 

From: Paul Hammant [mailto:[email protected]] 
Sent: Friday, June 20, 2008 3:40 PM
To: dev-qxt/[email protected]
Subject: Re: [picocontainer-dev] Visitor Work

 

In change 4330 I added a method to PicoVisitor (corresponding to a JIRA issue)

 

Make your change and show us the patch ..

---------------------------------------------------------------------
To unsubscribe from this list, please visit:

    http://xircles.codehaus.org/manage_email
visitorpatch.diff (application/octet-stream, 15.8 KB)
Index: pico/container/src/java/org/picocontainer/DefaultPicoContainer.java
===================================================================
--- pico/container/src/java/org/picocontainer/DefaultPicoContainer.java	(revision 4677)
+++ pico/container/src/java/org/picocontainer/DefaultPicoContainer.java	(working copy)
@@ -811,7 +811,14 @@
     }
 
     public void accept(final PicoVisitor visitor) {
-        visitor.visitContainer(this);
+    	
+    	//Pico 3 todo, change accept signatures to allow abort at any point in the traversal.
+        boolean shouldContinue = visitor.visitContainer(this);
+        if (!shouldContinue) {
+        	return;
+        }
+        
+        
         componentFactory.accept(visitor); // will cascade through behaviors
         final List<ComponentAdapter<?>> componentAdapters = new ArrayList<ComponentAdapter<?>>(getComponentAdapters());
         for (ComponentAdapter<?> componentAdapter : componentAdapters) {
Index: pico/container/src/java/org/picocontainer/PicoVisitor.java
===================================================================
--- pico/container/src/java/org/picocontainer/PicoVisitor.java	(revision 4677)
+++ pico/container/src/java/org/picocontainer/PicoVisitor.java	(working copy)
@@ -16,6 +16,20 @@
  * @author J&ouml;rg Schaible
  */
 public interface PicoVisitor {
+	
+	
+	/**
+	 * Constant that indicates that the traversal should continue after the 
+	 * visit*() method has been called.
+	 */
+	boolean CONTINUE_TRAVERSAL = true;
+	
+	/**
+	 * Constant that indicates that the traversal should abort after the 
+	 * visit*() method has been called.
+	 */
+	boolean ABORT_TRAVERSAL = false;
+	
     /**
      * Entry point for the PicoVisitor traversal. The given node is the first object, that is 
      * asked for acceptance. Only objects of type {@link PicoContainer}, {@link ComponentAdapter},
@@ -31,16 +45,18 @@
      * Visit a {@link PicoContainer} that has to accept the visitor.
      * 
      * @param pico the visited container.
+     * @return CONTINUE_TRAVERSAL if the traversal should continue.  
+     * Any visitor callback that returns ABORT_TRAVERSAL indicates
+     * the desire to abort any further traversal.
      */
+    boolean visitContainer(PicoContainer pico);
 
-    void visitContainer(PicoContainer pico);
-
     /**
      * Visit a {@link ComponentAdapter} that has to accept the visitor.
      * 
      * @param componentAdapter the visited ComponentAdapter.
      */
-    void visitComponentAdapter(ComponentAdapter componentAdapter);
+    void visitComponentAdapter(ComponentAdapter<?> componentAdapter);
 
     /**
      * Visit a {@link ComponentAdapter} that has to accept the visitor.
Index: pico/container/src/java/org/picocontainer/visitors/AbstractPicoVisitor.java
===================================================================
--- pico/container/src/java/org/picocontainer/visitors/AbstractPicoVisitor.java	(revision 4677)
+++ pico/container/src/java/org/picocontainer/visitors/AbstractPicoVisitor.java	(working copy)
@@ -30,7 +30,7 @@
     public Object traverse(final Object node) {
         traversal = true;
         Object retval =
-                AccessController.doPrivileged(new PrivilegedAction() {
+                AccessController.doPrivileged(new PrivilegedAction<Object>() {
                     public Object run() {
                         try {
                             return node.getClass().getMethod("accept", PicoVisitor.class);
Index: pico/container/src/java/org/picocontainer/visitors/MethodCallingVisitor.java
===================================================================
--- pico/container/src/java/org/picocontainer/visitors/MethodCallingVisitor.java	(revision 4677)
+++ pico/container/src/java/org/picocontainer/visitors/MethodCallingVisitor.java	(working copy)
@@ -29,7 +29,7 @@
     // TODO: we must serialize method with read/writeObject ... and are our parent serializable ???
     private transient Method method;
     private final Object[] arguments;
-    private final Class type;
+    private final Class<?> type;
     private final boolean visitInInstantiationOrder;
     private final List componentInstances;
     private static final long serialVersionUID = 2988472264483878674L;
@@ -43,7 +43,7 @@
      * @param arguments the arguments for the method invocation (may be <code>null</code>)
      * @throws NullPointerException if <tt>method</tt>, or <tt>ofType</tt> is <code>null</code>
      */
-    public MethodCallingVisitor(Method method, Class ofType, Object[] arguments, boolean visitInInstantiationOrder) {
+    public MethodCallingVisitor(Method method, Class<?> ofType, Object[] arguments, boolean visitInInstantiationOrder) {
         if (method == null) {
             throw new NullPointerException();
         }
@@ -82,9 +82,10 @@
         return Void.TYPE;
     }
 
-    public void visitContainer(PicoContainer pico) {
+    public boolean visitContainer(PicoContainer pico) {
         super.visitContainer(pico);
         componentInstances.addAll(pico.getComponents(type));
+        return CONTINUE_TRAVERSAL;
     }
 
     protected Method getMethod() {
Index: pico/container/src/java/org/picocontainer/visitors/TraversalCheckingVisitor.java
===================================================================
--- pico/container/src/java/org/picocontainer/visitors/TraversalCheckingVisitor.java	(revision 4677)
+++ pico/container/src/java/org/picocontainer/visitors/TraversalCheckingVisitor.java	(working copy)
@@ -27,30 +27,36 @@
  * final List allContainers = new ArrayList();
  *
  * PicoVisitor visitor = new TraversalCheckingVisitor() {
- *     public void visitContainer(PicoContainer pico) {
+ *     public boolean visitContainer(PicoContainer pico) {
  *         super.visitContainer(pico);  //Calls checkTraversal for us.
  *         allContainers.add(pico);
+ *         return true;
  *     }
  * }
  * </pre>
  *
- * @author Micheal Rimov
+ * @author Michael Rimov
  */
 public class TraversalCheckingVisitor
         extends AbstractPicoVisitor {
 
-    public void visitContainer(PicoContainer pico) {
+	/** {@inheritDoc} **/
+    public boolean visitContainer(PicoContainer pico) {
         checkTraversal();
+        return CONTINUE_TRAVERSAL;
     }
 
-    public void visitComponentAdapter(ComponentAdapter componentAdapter) {
+	/** {@inheritDoc} **/
+    public void visitComponentAdapter(ComponentAdapter<?> componentAdapter) {
         checkTraversal();
     }
 
+	/** {@inheritDoc} **/
     public void visitComponentFactory(ComponentFactory componentFactory) {
         checkTraversal();
     }
 
+	/** {@inheritDoc} **/
     public void visitParameter(Parameter parameter) {
         checkTraversal();
     }
Index: pico/container/src/java/org/picocontainer/visitors/VerifyingVisitor.java
===================================================================
--- pico/container/src/java/org/picocontainer/visitors/VerifyingVisitor.java	(revision 4677)
+++ pico/container/src/java/org/picocontainer/visitors/VerifyingVisitor.java	(working copy)
@@ -27,7 +27,7 @@
  */
 public class VerifyingVisitor extends TraversalCheckingVisitor {
 
-    private final List nestedVerificationExceptions;
+    private final List<RuntimeException> nestedVerificationExceptions;
     private final Set<ComponentAdapter> verifiedComponentAdapters;
     private final Set<ComponentFactory> verifiedComponentFactories;
     private final PicoVisitor componentAdapterCollector;
@@ -37,7 +37,7 @@
      * Construct a VerifyingVisitor.
      */
     public VerifyingVisitor() {
-        nestedVerificationExceptions = new ArrayList();
+        nestedVerificationExceptions = new ArrayList<RuntimeException>();
         verifiedComponentAdapters = new HashSet<ComponentAdapter>();
         verifiedComponentFactories = new HashSet<ComponentFactory>();
         componentAdapterCollector = new ComponentAdapterCollector();
@@ -55,7 +55,7 @@
         try {
             super.traverse(node);
             if (!nestedVerificationExceptions.isEmpty()) {
-                throw new PicoVerificationException(new ArrayList(nestedVerificationExceptions));
+                throw new PicoVerificationException(new ArrayList<RuntimeException>(nestedVerificationExceptions));
             }
         } finally {
             nestedVerificationExceptions.clear();
@@ -64,12 +64,13 @@
         return Void.TYPE;
     }
 
-    public void visitContainer(PicoContainer pico) {
+    public boolean visitContainer(PicoContainer pico) {
         super.visitContainer(pico);
         currentPico = pico;
+        return CONTINUE_TRAVERSAL;
     }
 
-    public void visitComponentAdapter(ComponentAdapter componentAdapter) {
+    public void visitComponentAdapter(ComponentAdapter<?> componentAdapter) {
         super.visitComponentAdapter(componentAdapter);
         if (!verifiedComponentAdapters.contains(componentAdapter)) {
             try {
@@ -79,6 +80,7 @@
             }
             componentAdapter.accept(componentAdapterCollector);
         }
+
     }
 
     public void visitComponentFactory(ComponentFactory componentFactory) {
@@ -92,6 +94,7 @@
             }
             componentFactory.accept(componentAdapterCollector);
         }
+
     }
 
 
@@ -102,7 +105,8 @@
             return null;
         }
 
-        public void visitContainer(PicoContainer pico) {
+        public boolean visitContainer(PicoContainer pico) {
+            return CONTINUE_TRAVERSAL;
         }
 
         // /CLOVER:ON
@@ -116,6 +120,7 @@
         }
 
         public void visitParameter(Parameter parameter) {
+
         }
     }
 }
Index: pico/container/src/test/org/picocontainer/tck/AbstractComponentAdapterTest.java
===================================================================
--- pico/container/src/test/org/picocontainer/tck/AbstractComponentAdapterTest.java	(revision 4677)
+++ pico/container/src/test/org/picocontainer/tck/AbstractComponentAdapterTest.java	(working copy)
@@ -519,8 +519,9 @@
     static class RecordingVisitor extends AbstractPicoVisitor {
         private final List visitedElements = new LinkedList();
 
-        public void visitContainer(PicoContainer pico) {
+        public boolean visitContainer(PicoContainer pico) {
             visitedElements.add(pico);
+            return CONTINUE_TRAVERSAL;
         }
 
         public void visitComponentAdapter(ComponentAdapter componentAdapter) {
Index: pico/container/src/test/org/picocontainer/tck/AbstractPicoContainerTest.java
===================================================================
--- pico/container/src/test/org/picocontainer/tck/AbstractPicoContainerTest.java	(revision 4677)
+++ pico/container/src/test/org/picocontainer/tck/AbstractPicoContainerTest.java	(working copy)
@@ -66,6 +66,7 @@
 import org.picocontainer.testmodel.Washable;
 import org.picocontainer.testmodel.WashableTouchable;
 import org.picocontainer.visitors.AbstractPicoVisitor;
+import org.picocontainer.visitors.TraversalCheckingVisitor;
 import org.picocontainer.visitors.VerifyingVisitor;
 
 /** This test tests (at least it should) all the methods in MutablePicoContainer. */
@@ -719,8 +720,9 @@
             this.list = list;
         }
 
-        public void visitContainer(PicoContainer pico) {
+        public boolean visitContainer(PicoContainer pico) {
             list.add(pico.getClass());
+            return CONTINUE_TRAVERSAL;
         }
 
         public void visitComponentAdapter(ComponentAdapter componentAdapter) {
@@ -783,7 +785,42 @@
         }
         assertEquals(0, visitedList.size());
     }
+    
+    /**
+     * Verifies that you can halt a container traversal.
+     */
+    @Test
+    public void testAcceptIsAbortable() {
+        final MutablePicoContainer parent = createPicoContainer(null);
+        final MutablePicoContainer child = parent.makeChildContainer();
+        child.addComponent("This is a test");
+        
+        TraversalCheckingVisitor visitor = new TraversalCheckingVisitor() {
+        	private int containerCount = 0;
+        	
+			@Override
+			public void visitComponentAdapter(ComponentAdapter<?> componentAdapter) {
+				if (containerCount == 0) {
+					fail("Should have visited a container first");
+				}
+				fail("Should never have visited an adapter.");
+			}
 
+			@Override
+			public boolean visitContainer(PicoContainer pico) {
+				containerCount++;
+				if (containerCount > 1) {
+					return ABORT_TRAVERSAL;
+				}
+				
+				return CONTINUE_TRAVERSAL;
+			}
+        	
+        };
+    	
+        visitor.traverse(parent);        
+    }
+
     protected void addContainers(List expectedList) {
         expectedList.add(DefaultPicoContainer.class);
     }
Index: pico/container/src/test/org/picocontainer/visitors/TraversalCheckingVisitorTest.java
===================================================================
--- pico/container/src/test/org/picocontainer/visitors/TraversalCheckingVisitorTest.java	(revision 4677)
+++ pico/container/src/test/org/picocontainer/visitors/TraversalCheckingVisitorTest.java	(working copy)
@@ -120,9 +120,10 @@
         final int expectedNumberOfContainers = 2;
 
         PicoVisitor containerCollector = new TraversalCheckingVisitor() {
-            public void visitContainer(PicoContainer pico) {
+            public boolean visitContainer(PicoContainer pico) {
                 super.visitContainer(pico); //Calls checkTraversal for us.
                 allContainers.add(pico);
+                return CONTINUE_TRAVERSAL;
             }
         };
 
Index: pico/gems/src/java/org/picocontainer/gems/jmx/JMXVisitor.java
===================================================================
--- pico/gems/src/java/org/picocontainer/gems/jmx/JMXVisitor.java	(revision 4677)
+++ pico/gems/src/java/org/picocontainer/gems/jmx/JMXVisitor.java	(working copy)
@@ -86,10 +86,11 @@
      * Provides the PicoContainer, that can resolve the components to register as MBean.
      * @see org.picocontainer.PicoVisitor#visitContainer(org.picocontainer.PicoContainer)
      */
-    public void visitContainer(final PicoContainer pico) {
+    public boolean visitContainer(final PicoContainer pico) {
         super.visitContainer(pico);
         picoContainer = pico;
         visited.clear();
+        return CONTINUE_TRAVERSAL;
     }
 
     /**
@@ -112,6 +113,7 @@
                 }
             }
         }
+
     }
 
     /**
Index: pico/gems/src/java/org/picocontainer/gems/jndi/JNDIContainerVisitor.java
===================================================================
--- pico/gems/src/java/org/picocontainer/gems/jndi/JNDIContainerVisitor.java	(revision 4677)
+++ pico/gems/src/java/org/picocontainer/gems/jndi/JNDIContainerVisitor.java	(working copy)
@@ -15,7 +15,6 @@
 
 import org.picocontainer.ComponentAdapter;
 import org.picocontainer.PicoContainer;
-import org.picocontainer.PicoException;
 import org.picocontainer.visitors.TraversalCheckingVisitor;
 
 /**
@@ -40,15 +39,17 @@
 		if(componentAdapter instanceof JNDIExposed) {
 			componentAdapter.getComponentInstance(container);
 		}
+
 	}
 
 	/**
      * Provides the PicoContainer, that can resolve the components to register as MBean.
      * @see org.picocontainer.PicoVisitor#visitContainer(org.picocontainer.PicoContainer)
      */
-    public void visitContainer(final PicoContainer pico) {
+    public boolean visitContainer(final PicoContainer pico) {
         super.visitContainer(pico);
         container = pico;
+        return CONTINUE_TRAVERSAL;
     }
 
     /**
Index: pico/gems/src/test/org/picocontainer/gems/containers/AbstractTracingContainerDecoratorTest.java
===================================================================
--- pico/gems/src/test/org/picocontainer/gems/containers/AbstractTracingContainerDecoratorTest.java	(revision 4677)
+++ pico/gems/src/test/org/picocontainer/gems/containers/AbstractTracingContainerDecoratorTest.java	(working copy)
@@ -124,7 +124,7 @@
                 throw new UnsupportedOperationException();
             }
 
-            public void visitContainer(PicoContainer pico) {
+            public boolean visitContainer(PicoContainer pico) {
 				throw new UnsupportedOperationException();
 			}