You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by bs...@apache.org on 2010/02/09 19:34:07 UTC

svn commit: r908149 [1/2] - in /myfaces/trinidad/branches/1.2.12.2-branch: trinidad-api/src/main/java-templates/org/apache/myfaces/trinidad/component/ trinidad-api/src/main/java/org/apache/myfaces/trinidad/component/ trinidad-api/src/main/java/org/apac...

Author: bsullivan
Date: Tue Feb  9 18:34:05 2010
New Revision: 908149

URL: http://svn.apache.org/viewvc?rev=908149&view=rev
Log:
The first problem we have had is that components need to separate the context setup and teardown needed to process their children from the context setup and tear down of the components themselves.  For example, consider a composite component that establishes an EL context for its children--that context should only be setup when the children are being processed, not when the component is processing its own attributes.

In the case of encoding, we want to delegate to the Renderer to ensure that the setup and teardown of context for child processing is consistent between optimized rendering using tree visiting and full rendering traversals.

The second problem was that UIXComponent.setUpEncodingContext was named differently than all of the other set up methods.  I've made the spelling consistent (which after a quick check of the dictionary is consitently wrong through out Trinidad setup as a compound word is a noun and as a verb is two words, so it should have been setUp.  Drat!) and temporarily left a final deprecated version in that I will whack shortly.

The third issue is that iterating components often want to modify only the manner in which their data is iterated over.  To simplify this, we add a hook visitData() to UIXCollection.

UIXComponent:

/**
 * Hook for subclasses to override the manner in which the component's children are visited.  The default
 * implementation visits all of the children and facets of the Component.
 * <code>setupChildrenVisitingContext</code> will have been called before this method is
 * invoked and <code>tearDownChildrenVisitingContext</code> will be called after.
 * respectively.  If the purpose of this visit was to encode the component and the
 * component uses a CoreRenderer, the CoreRenderer's
 * <code>setupChildrenEncodingContext</code> and <code>tearDownChildrenEncodingContext</code>
 * will be called before and after this method is invoked, respectively.
 * @param visitContext the <code>VisitContext</code> for this visit
 * @param callback the <code>VisitCallback</code> instance
 * @return <code>true</code> if the visit is complete.
 * @see #setupChildrenVisitingContext
 * @see #tearDownChildrenVisitingContext
 * @see org.apache.myfaces.trinidad.render.CoreRenderer#setupChildrenEncodingContext
 * @see org.apache.myfaces.trinidad.render.CoreRenderer#tearDownChildrenEncodingContext
 */
 protected boolean visitChildren(
   VisitContext visitContext,
   VisitCallback callback)

 /**
  * <p>Sets up the context necessary to visit or invoke the children of a component for all phases.
  * </p>
  * <p>The default implementation does nothing.</p>
  * <p>If a subclass overrides this method, it should override
  * <code>tearDownChildrenVisitingContext</code> as well.</p>
  * <p>It is guaranteed that if <code>setupChildrenVisitingContext</code> completes
  * <code>tearDownChildrenVisitingContext</code> will be called for this component</p>
  * @param context FacesContext
  * @see #visitChildren
  * @see #tearDownChildrenVisitingContext
  */
 protected void setupChildrenVisitingContext(@SuppressWarnings("unused") FacesContext context)

 /**
  * <p>Tears down context created in order to visit or invoke the children of a component
  * for all phases.</p>
  * <p>The default implementation does nothing.</p>
  * <p>A subclass should only override this method if it overrode
  * <code>setupChildrenVisitingContext</code> as well</p>
  * <p>It is guaranteed that <code>tearDownChildrenVisitingContext</code> will be called only after
  * <code>setupChildrenVisitingContext</code> has been called for this component</p>
  * @param context FacesContext
  * @see #setupChildrenVisitingContext
  * @see #visitChildren
  */
 protected void tearDownChildrenVisitingContext(@SuppressWarnings("unused") FacesContext context)

CoreRenderer

  * <p>
  * Called before rendering the current component's children in order to set
  * up any special context.
  * </p>
  * <p>If <code>setupChildrenEncodingContext</code> succeeds then
  * <code>tearDownChildrenEncodingContext</code> will be called for the same component.
  * </p>
  * <p>The default implementation does nothing</p>
  * @param context FacesContext for this request
  * @param rc RenderingContext for this encoding pass
  * @param component Component to encode using this Renderer
  * @see #tearDownChildrenEncodingContext
  */
 public void setupChildrenEncodingContext(
   @SuppressWarnings("unused") FacesContext context,
   @SuppressWarnings("unused") RenderingContext rc,
   @SuppressWarnings("unused") UIComponent component)

 /**
  * <p>
  * Called after rendering the current component's children in order to tear
  * down any special context.
  * </p>
  * <p>
  * <code>tearDownChildrenEncodingContext</code> will be called on the component if
  * <code>setupChildrenEncodingContext</code> succeeded.
  * </p>
  * <p>The default implementation does nothing</p>
  * @param context FacesContext for this request
  * @param rc RenderingContext for this encoding pass
  * @param component Component to encode using this Renderer
  * @see #setupChildrenEncodingContext
  */
 public void tearDownChildrenEncodingContext(
   @SuppressWarnings("unused") FacesContext context,
   @SuppressWarnings("unused") RenderingContext rc,
   @SuppressWarnings("unused") UIComponent component)

UIXCollection:

 /**
  * Visit the rows and children of the columns of the collection per row-index. This should
  * not visit row index -1 (it will be perfomed in the visitTree method). The columns
  * themselves should not be visited, only their children in this function.
  *
  * @param visitContext The visiting context
  * @param callback The visit callback
  * @return true if the visiting should stop
  * @see #visitChildren(VisitContext, VisitCallback)
  */
 protected abstract boolean visitData(
   VisitContext  visitContext,
   VisitCallback callback);

Modified:
    myfaces/trinidad/branches/1.2.12.2-branch/trinidad-api/src/main/java-templates/org/apache/myfaces/trinidad/component/UIXIteratorTemplate.java
    myfaces/trinidad/branches/1.2.12.2-branch/trinidad-api/src/main/java-templates/org/apache/myfaces/trinidad/component/UIXNavigationLevelTemplate.java
    myfaces/trinidad/branches/1.2.12.2-branch/trinidad-api/src/main/java-templates/org/apache/myfaces/trinidad/component/UIXNavigationPathTemplate.java
    myfaces/trinidad/branches/1.2.12.2-branch/trinidad-api/src/main/java-templates/org/apache/myfaces/trinidad/component/UIXNavigationTreeTemplate.java
    myfaces/trinidad/branches/1.2.12.2-branch/trinidad-api/src/main/java-templates/org/apache/myfaces/trinidad/component/UIXPageTemplate.java
    myfaces/trinidad/branches/1.2.12.2-branch/trinidad-api/src/main/java-templates/org/apache/myfaces/trinidad/component/UIXProcessTemplate.java
    myfaces/trinidad/branches/1.2.12.2-branch/trinidad-api/src/main/java-templates/org/apache/myfaces/trinidad/component/UIXTableTemplate.java
    myfaces/trinidad/branches/1.2.12.2-branch/trinidad-api/src/main/java-templates/org/apache/myfaces/trinidad/component/UIXTreeTableTemplate.java
    myfaces/trinidad/branches/1.2.12.2-branch/trinidad-api/src/main/java-templates/org/apache/myfaces/trinidad/component/UIXTreeTemplate.java
    myfaces/trinidad/branches/1.2.12.2-branch/trinidad-api/src/main/java/org/apache/myfaces/trinidad/component/HierarchyUtils.java
    myfaces/trinidad/branches/1.2.12.2-branch/trinidad-api/src/main/java/org/apache/myfaces/trinidad/component/StampState.java
    myfaces/trinidad/branches/1.2.12.2-branch/trinidad-api/src/main/java/org/apache/myfaces/trinidad/component/TableUtils.java
    myfaces/trinidad/branches/1.2.12.2-branch/trinidad-api/src/main/java/org/apache/myfaces/trinidad/component/UIXCollection.java
    myfaces/trinidad/branches/1.2.12.2-branch/trinidad-api/src/main/java/org/apache/myfaces/trinidad/component/UIXComponent.java
    myfaces/trinidad/branches/1.2.12.2-branch/trinidad-api/src/main/java/org/apache/myfaces/trinidad/component/UIXComponentBase.java
    myfaces/trinidad/branches/1.2.12.2-branch/trinidad-api/src/main/java/org/apache/myfaces/trinidad/component/UIXHierarchy.java
    myfaces/trinidad/branches/1.2.12.2-branch/trinidad-api/src/main/java/org/apache/myfaces/trinidad/component/visit/VisitCallback.java
    myfaces/trinidad/branches/1.2.12.2-branch/trinidad-api/src/main/java/org/apache/myfaces/trinidad/component/visit/VisitContext.java
    myfaces/trinidad/branches/1.2.12.2-branch/trinidad-api/src/main/java/org/apache/myfaces/trinidad/render/CoreRenderer.java
    myfaces/trinidad/branches/1.2.12.2-branch/trinidad-api/src/main/java/org/apache/myfaces/trinidad/util/CollectionUtils.java
    myfaces/trinidad/branches/1.2.12.2-branch/trinidad-api/src/test/java/org/apache/myfaces/trinidad/component/UIComponentTestCase.java
    myfaces/trinidad/branches/1.2.12.2-branch/trinidad-api/src/test/java/org/apache/myfaces/trinidad/component/UIXProcessTest.java
    myfaces/trinidad/branches/1.2.12.2-branch/trinidad-api/src/test/java/org/apache/myfaces/trinidad/component/core/nav/CoreBreadCrumbsTest.java
    myfaces/trinidad/branches/1.2.12.2-branch/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/context/FullVisitContext.java
    myfaces/trinidad/branches/1.2.12.2-branch/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/context/PartialVisitContext.java
    myfaces/trinidad/branches/1.2.12.2-branch/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/renderkit/core/ppr/PartialPageContextImpl.java
    myfaces/trinidad/branches/1.2.12.2-branch/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/renderkit/core/xhtml/FormRenderer.java

Modified: myfaces/trinidad/branches/1.2.12.2-branch/trinidad-api/src/main/java-templates/org/apache/myfaces/trinidad/component/UIXIteratorTemplate.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/branches/1.2.12.2-branch/trinidad-api/src/main/java-templates/org/apache/myfaces/trinidad/component/UIXIteratorTemplate.java?rev=908149&r1=908148&r2=908149&view=diff
==============================================================================
--- myfaces/trinidad/branches/1.2.12.2-branch/trinidad-api/src/main/java-templates/org/apache/myfaces/trinidad/component/UIXIteratorTemplate.java (original)
+++ myfaces/trinidad/branches/1.2.12.2-branch/trinidad-api/src/main/java-templates/org/apache/myfaces/trinidad/component/UIXIteratorTemplate.java Tue Feb  9 18:34:05 2010
@@ -6,9 +6,9 @@
  *  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
@@ -21,25 +21,34 @@
 import java.io.IOException;
 
 import java.util.AbstractMap;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
 import java.util.List;
-
 import java.util.Map;
 import java.util.Set;
+
 import javax.faces.component.UIComponent;
 import javax.faces.context.FacesContext;
+import javax.faces.event.AbortProcessingException;
 import javax.faces.event.PhaseId;
 
 import javax.faces.render.Renderer;
+
+import org.apache.myfaces.trinidad.component.visit.VisitCallback;
+import org.apache.myfaces.trinidad.component.visit.VisitContext;
 import org.apache.myfaces.trinidad.model.CollectionModel;
 import org.apache.myfaces.trinidad.model.LocalRowKeyIndex;
 import org.apache.myfaces.trinidad.model.ModelUtils;
 
+import org.apache.myfaces.trinidad.render.ClientRowKeyManager;
+
 /**
  * This component iterates over some given data.
  * Each child is repeatedly stamped as many times as necessary.
  * Iteration is done starting at the index given by {@link #getFirst()}
  * for as many indices as specified by {@link #getRows()}.
- * If {@link #getRows()} returns 0, then the iteration continues until 
+ * If {@link #getRows()} returns 0, then the iteration continues until
  * there are no more elements in the underlying data.
  */
 public abstract class UIXIteratorTemplate extends UIXCollection implements FlattenedComponent, LocalRowKeyIndex
@@ -70,7 +79,7 @@
     // Mimic what would normally happen in the non-flattening case for encodeBegin():
     __processFlattenedChildrenBegin();
 
-    Runner runner = new Runner(cpContext)
+    Runner runner = new IndexedRunner(cpContext)
     {
       @Override
       protected void process(UIComponent kid, ComponentProcessingContext cpContext) throws IOException
@@ -79,7 +88,7 @@
       }
     };
     boolean processedChildren = runner.run();
-    Exception exp = runner.exception;
+    Exception exp = runner.getException();
     if (exp != null)
     {
       if (exp instanceof RuntimeException)
@@ -125,7 +134,7 @@
     }
     else // this is not the table. it must be the iterator
     {
-      Runner runner = new Runner()
+      Runner runner = new IndexedRunner()
       {
         @Override
         protected void process(UIComponent kid,
@@ -135,7 +144,7 @@
         }
       };
       runner.run();
-      Exception exp = runner.exception;
+      Exception exp = runner.getException();
       if (exp != null)
       {
         if (exp instanceof RuntimeException)
@@ -167,7 +176,7 @@
       public Object get(Object key)
       {
         // some of these keys are from <c:forEach>, ie:
-        // javax.servlet.jsp.jstl.core.LoopTagStatus 
+        // javax.servlet.jsp.jstl.core.LoopTagStatus
         if ("begin".equals(key)) // from jstl
         {
           return Integer.valueOf(getFirst());
@@ -202,7 +211,7 @@
     CollectionModel current,
     Object value)
   {
-    CollectionModel model = ModelUtils.toCollectionModel(value); 
+    CollectionModel model = ModelUtils.toCollectionModel(value);
     // initialize to -1. we need to do this incase some application logic
     // changed this index. Also, some JSF1.0 RI classes were initially starting
     // with a rowIndex of 0.
@@ -217,7 +226,7 @@
     final FacesContext context,
     final PhaseId phaseId)
   {
-    Runner runner = new Runner()
+    Runner runner = new IndexedRunner()
     {
       @Override
       protected void process(UIComponent kid, ComponentProcessingContext cpContext)
@@ -228,6 +237,109 @@
     runner.run();
   }
   
+  // Extract the current row token from the clientId
+  private String _getClientToken(String clientIdPrefix, String cellClientId)
+  {
+    int tokenStartIndex = clientIdPrefix.length() + 1;
+    int tokenEndIndex = cellClientId.indexOf(':', tokenStartIndex);
+    
+    if (tokenEndIndex != -1)
+    {
+      return cellClientId.substring(tokenStartIndex, tokenEndIndex);
+    }
+    else
+    {
+      return null;
+    }
+  }
+  
+  @Override
+  protected boolean visitData(
+    final VisitContext  visitContext,
+    final VisitCallback visitCallback)
+  {
+    Collection<String> subtreeIds = visitContext.getSubtreeIdsToVisit(this);
+ 
+    String ourClientIdPrefix = getClientId(visitContext.getFacesContext());
+   
+    int subtreeIdCount = subtreeIds.size();
+    
+    // build up a set of the row keys to visit rather than iterating
+    // and visiting every row
+    Set<String> rowsToVisit;
+    
+    if (subtreeIdCount > 1)
+    {
+      rowsToVisit = new HashSet<String>(subtreeIdCount);
+
+      for (String currClientId : subtreeIds)
+      {
+        String clientToken = _getClientToken(ourClientIdPrefix, currClientId);
+        
+        if (clientToken != null)
+        {
+          rowsToVisit.add(clientToken);          
+        }
+      }
+    }
+    else
+    {
+      String clientToken = _getClientToken(ourClientIdPrefix,
+                                           subtreeIds.iterator().next());
+      
+      if (clientToken != null)
+      {
+        rowsToVisit = Collections.singleton(clientToken);
+      }
+      else
+      {
+        rowsToVisit = Collections.emptySet();
+      }
+    }
+    
+    // we didn't visit any data
+    if (rowsToVisit.isEmpty())
+      return false;
+    
+    // create a special VisitContext that doesn't visit the Facets
+    // of column components since they aren't visited on each row
+    final VisitContext noColumnFacetContext = new NoColumnFacetsVisitContext(visitContext);
+    
+    // visit only the rows
+    Runner runner = new KeyedRunner(rowsToVisit)
+    {
+      @Override
+      protected void process(
+        UIComponent                kid,
+        ComponentProcessingContext cpContext
+        ) throws IOException
+      {
+        if (kid.getChildCount() > 0)
+        {
+          for (UIComponent grandKid : kid.getChildren())
+          {
+            if (UIXComponent.visitTree(noColumnFacetContext, grandKid, visitCallback))
+            {
+              throw new AbortProcessingException();
+            }
+          }
+        }
+      }
+    };
+
+    try
+    {
+      runner.run();
+    }
+    finally
+    {
+      return (runner.getException() instanceof AbortProcessingException);
+    }
+  }
+
+  /**
+   * Abstract class for processing rows
+   */
   private abstract class Runner implements ComponentProcessor<Object>
   {
     public Runner()
@@ -240,9 +352,79 @@
       _cpContext = cpContext;
     }
     
+    public abstract boolean run();
+
+    /**
+     * Sets up the context for the child and processes it
+     */
+    public void processComponent(
+      FacesContext context,
+      ComponentProcessingContext cpContext,
+      UIComponent component,
+      Object callbackContext) throws IOException
+    {
+      try
+      {
+        process(component, cpContext);
+      }
+      catch (IOException ioe)
+      {
+        throw ioe;
+      }
+      catch (AbortProcessingException ape)
+      {
+        // we're done, so abort
+        _exception = ape;        
+        throw ape;
+      }
+      catch (Exception e)
+      {
+        _exception = e;
+      }
+    }
+    
+    public Exception getException()
+    {
+      return _exception;
+    }
+
+    protected abstract void process(UIComponent comp, ComponentProcessingContext cpContext)
+      throws Exception;
+
+    protected final ComponentProcessingContext getComponentProcessingContext()
+    {
+      return _cpContext;
+    }
+
+    public final void setException(Exception e)
+    {
+      _exception = e;
+    }
+    
+    private Exception _exception = null;
+
+    private final ComponentProcessingContext _cpContext;
+  }
+
+  /**
+   * Class for visiting getRows() by index rows starting getFirst()
+   */
+  private abstract class IndexedRunner extends Runner
+  {
+    public IndexedRunner()
+    {
+      this(null);
+    }
+
+    public IndexedRunner(ComponentProcessingContext cpContext)
+    {
+      super(cpContext);
+    }
+    
     public final boolean run()
     {
       FacesContext context = FacesContext.getCurrentInstance();
+      ComponentProcessingContext cpContext = getComponentProcessingContext();
       
       List<UIComponent> stamps = getStamps();
       int oldIndex = getRowIndex();
@@ -262,8 +444,8 @@
           if (isRowAvailable())
           {
             // latch processedChild the first time we process a child
-            processedChild |= (_cpContext != null)
-              ? UIXComponent.processFlattenedChildren(context, _cpContext, this, stamps, null)
+            processedChild |= (cpContext != null)
+              ? UIXComponent.processFlattenedChildren(context, cpContext, this, stamps, null)
               : UIXComponent.processFlattenedChildren(context, this, stamps, null);
           }
           else
@@ -272,7 +454,7 @@
       }
       catch (IOException e)
       {
-        exception = e;
+        setException(e);
       }
       finally
       {
@@ -281,38 +463,63 @@
       
       return processedChild;
     }
+  }
 
-    /**
-     * Sets up the context for the child and processes it
-     */
-    public void processComponent(
-      FacesContext context,
-      ComponentProcessingContext cpContext,
-      UIComponent component,
-      Object callbackContext) throws IOException
+  /**
+   * Runner that visits the rows specified by the client row key tokens
+   */
+  private abstract class KeyedRunner extends Runner
+  {
+    public KeyedRunner(Iterable<String> clientKeys)
     {
+      super();
+      _clientKeys = clientKeys;
+    }
+    
+    public final boolean run()
+    {
+      FacesContext context = FacesContext.getCurrentInstance();
+     
+      List<UIComponent> stamps = getStamps();
+      int oldIndex = getRowIndex();
+            
+      boolean processedChild = false;
+            
       try
       {
-        process(component, cpContext);
+        // need to convert row key tokens to row keys
+        ClientRowKeyManager rowKeyManager = getClientRowKeyManager();
+
+        for(String clientKey : _clientKeys)
+        {
+          Object rowKey = rowKeyManager.getRowKey(context, UIXIterator.this, clientKey);
+          
+          if (rowKey != null)
+          {
+            setRowKey(rowKey);
+            if (isRowAvailable())
+            {
+              // latch processedChild the first time we process a child
+              processedChild |= UIXComponent.processFlattenedChildren(context, this, stamps, null);
+            }
+          }
+        }
       }
-      catch (IOException ioe)
+      catch (IOException e)
       {
-        throw ioe;
+        setException(e);
       }
-      catch (Exception e)
+      finally
       {
-        exception = e;
+        setRowIndex(oldIndex);
       }
+      
+      return processedChild;
     }
-
-    protected abstract void process(UIComponent comp, ComponentProcessingContext cpContext)
-      throws Exception;
-
-    public Exception exception = null;
-
-    private final ComponentProcessingContext _cpContext;
+    
+    private final Iterable<String> _clientKeys;
   }
-
+  
   @Override
   void __encodeBegin(FacesContext context) throws IOException
   {
@@ -355,7 +562,7 @@
           first = 0;
         else
         {
-          // scroll to the last page: 
+          // scroll to the last page:
           first = size - rows;
           model.setRowIndex(first);
           // make sure the row is indeed available:
@@ -375,5 +582,4 @@
       model.setRowIndex(oldIndex);
     }
   }
-
 }

Modified: myfaces/trinidad/branches/1.2.12.2-branch/trinidad-api/src/main/java-templates/org/apache/myfaces/trinidad/component/UIXNavigationLevelTemplate.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/branches/1.2.12.2-branch/trinidad-api/src/main/java-templates/org/apache/myfaces/trinidad/component/UIXNavigationLevelTemplate.java?rev=908149&r1=908148&r2=908149&view=diff
==============================================================================
--- myfaces/trinidad/branches/1.2.12.2-branch/trinidad-api/src/main/java-templates/org/apache/myfaces/trinidad/component/UIXNavigationLevelTemplate.java (original)
+++ myfaces/trinidad/branches/1.2.12.2-branch/trinidad-api/src/main/java-templates/org/apache/myfaces/trinidad/component/UIXNavigationLevelTemplate.java Tue Feb  9 18:34:05 2010
@@ -18,9 +18,13 @@
  */
 package org.apache.myfaces.trinidad.component;
 
+import javax.faces.component.UIComponent;
 import javax.faces.context.FacesContext;
 import javax.faces.event.PhaseId;
 
+import org.apache.myfaces.trinidad.component.visit.VisitCallback;
+import org.apache.myfaces.trinidad.component.visit.VisitContext;
+
 
 /**
  * Base class for the NavigationLevel component.
@@ -39,17 +43,61 @@
   {
     Object oldPath = getRowKey();
     HierarchyUtils.__setStartDepthPath(this, getLevel());
+    
     // process stamp for one level
     HierarchyUtils.__processLevel(context, phaseId, this);
     setRowKey(oldPath);
 
-
     // process the children
     TableUtils.__processChildren(context, this, phaseId);
   }
 
+  @Override
+  protected boolean visitChildren(
+    VisitContext  visitContext,
+    VisitCallback callback)
+  {
+    boolean done = visitData(visitContext, callback);
 
+    if (!done)
+    {
+      // process the children
+      int childCount = getChildCount();
+      if (childCount > 0)
+      {
+        for (UIComponent child : getChildren())
+        {
+          done = UIXComponent.visitTree(visitContext, child, callback);
+          
+          if (done)
+            break;
+        }
+      }          
+    }
+    
+    return done;
+  }
+  
+  @Override
+  protected boolean visitData(
+    VisitContext  visitContext,
+    VisitCallback callback)
+  {
+    Object oldKey = getRowKey();
+       
+    boolean done;
 
+    HierarchyUtils.__setStartDepthPath(this, getLevel());
 
-
+    try
+    {
+      done = visitLevel(visitContext, callback, getStamps());
+    }
+    finally
+    {
+      setRowKey(oldKey);
+    }
+    
+    return done;
+  }
 }

Modified: myfaces/trinidad/branches/1.2.12.2-branch/trinidad-api/src/main/java-templates/org/apache/myfaces/trinidad/component/UIXNavigationPathTemplate.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/branches/1.2.12.2-branch/trinidad-api/src/main/java-templates/org/apache/myfaces/trinidad/component/UIXNavigationPathTemplate.java?rev=908149&r1=908148&r2=908149&view=diff
==============================================================================
--- myfaces/trinidad/branches/1.2.12.2-branch/trinidad-api/src/main/java-templates/org/apache/myfaces/trinidad/component/UIXNavigationPathTemplate.java (original)
+++ myfaces/trinidad/branches/1.2.12.2-branch/trinidad-api/src/main/java-templates/org/apache/myfaces/trinidad/component/UIXNavigationPathTemplate.java Tue Feb  9 18:34:05 2010
@@ -25,6 +25,9 @@
 import javax.faces.context.FacesContext;
 import javax.faces.event.PhaseId;
 
+import org.apache.myfaces.trinidad.component.visit.VisitCallback;
+import org.apache.myfaces.trinidad.component.visit.VisitContext;
+
 
 /**
  * Base class for the NavigationPath component.
@@ -68,5 +71,76 @@
     TableUtils.__processChildren(context, this, phaseId);
   }  
 
+  @Override
+  protected boolean visitChildren(
+    VisitContext  visitContext,
+    VisitCallback callback)
+  {
+    boolean done = visitData(visitContext, callback);
+    
+    if (!done)
+    {
+      // process the children
+      int childCount = getChildCount();
+      if (childCount > 0)
+      {
+        for (UIComponent child : getChildren())
+        {
+          done = UIXComponent.visitTree(visitContext, child, callback);
+          
+          if (done)
+            break;
+        }
+      }          
+    }
+    
+    return done;
+  }
+  
+  @Override
+  protected boolean visitData(
+    VisitContext  visitContext,
+    VisitCallback callback)
+  {
+    Object focusPath = getFocusRowKey();
+    Object oldRowKey = null;
+    
+    boolean done = false;
+    
+    // start from the focused area
+    if (focusPath != null)
+    {
+      List<UIComponent> stamps = getStamps();
+      
+      if (!stamps.isEmpty())
+      {
+        List<Object> paths =  new ArrayList<Object>(getAllAncestorContainerRowKeys(focusPath));
+        paths.add(focusPath);
+        
+        int focusPathSize = paths.size();
+        
+        try
+        {
+          for (int i = 0; i < focusPathSize && !done; i++)
+          {
+            setRowKey(paths.get(i));
+            
+            for (UIComponent stamp : stamps)
+            {
+              done = UIXComponent.visitTree(visitContext, stamp, callback);
+              
+              if (done)
+                break;
+            }
+          }
+        }
+        finally
+        {
+          setRowKey(oldRowKey);
+        }
+      }
+    }
     
+    return done;
+  } 
 }

Modified: myfaces/trinidad/branches/1.2.12.2-branch/trinidad-api/src/main/java-templates/org/apache/myfaces/trinidad/component/UIXNavigationTreeTemplate.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/branches/1.2.12.2-branch/trinidad-api/src/main/java-templates/org/apache/myfaces/trinidad/component/UIXNavigationTreeTemplate.java?rev=908149&r1=908148&r2=908149&view=diff
==============================================================================
--- myfaces/trinidad/branches/1.2.12.2-branch/trinidad-api/src/main/java-templates/org/apache/myfaces/trinidad/component/UIXNavigationTreeTemplate.java (original)
+++ myfaces/trinidad/branches/1.2.12.2-branch/trinidad-api/src/main/java-templates/org/apache/myfaces/trinidad/component/UIXNavigationTreeTemplate.java Tue Feb  9 18:34:05 2010
@@ -29,6 +29,9 @@
 
 import org.apache.myfaces.trinidad.bean.FacesBean;
 import org.apache.myfaces.trinidad.bean.PropertyKey;
+import org.apache.myfaces.trinidad.component.visit.VisitCallback;
+import org.apache.myfaces.trinidad.component.visit.VisitContext;
+import org.apache.myfaces.trinidad.component.visit.VisitHint;
 import org.apache.myfaces.trinidad.model.CollectionModel;
 import org.apache.myfaces.trinidad.model.RowKeySet;
 import org.apache.myfaces.trinidad.model.RowKeySetTreeImpl;
@@ -93,7 +96,7 @@
     // this component has no facets that need to be processed once.
     // instead process the "nodeStamp" facet as many times as necessary:
     Object oldPath = getRowKey();
-    HierarchyUtils.__setStartLevelPath(this, getStartLevel());
+    HierarchyUtils.__setStartDepthPath(this, getStartLevel());
     HierarchyUtils.__iterateOverTree(context,
                                       phaseId,
                                       this,
@@ -103,6 +106,43 @@
   }
 
   @Override
+  protected boolean visitChildren(
+    VisitContext  visitContext,
+    VisitCallback callback)
+  {
+    return visitData(visitContext, callback);
+  }
+  
+  @Override
+  protected boolean visitData(
+    VisitContext  visitContext,
+    VisitCallback callback)
+  {
+    Object oldRowKey = getRowKey();
+
+    // if we are only visiting rendered stamps, then pass in the disclosed row keys, otherwise
+    // pass in null, indicating that all row keys should be visited
+    RowKeySet disclosedRowKeys = (visitContext.getHints().contains(VisitHint.SKIP_UNRENDERED))
+                                   ? getDisclosedRowKeys()
+                                   : null;
+    
+    boolean done;
+
+    HierarchyUtils.__setStartDepthPath(this, getStartLevel());
+
+    try
+    {
+      done = visitHierarchy(visitContext, callback, getStamps(), disclosedRowKeys);
+    }
+    finally
+    {
+      setRowKey(oldRowKey);
+    }
+    
+    return done;
+  }
+  
+  @Override
   void __encodeBegin(FacesContext context) throws IOException
   {
     HierarchyUtils.__handleEncodeBegin(this, getDisclosedRowKeys());

Modified: myfaces/trinidad/branches/1.2.12.2-branch/trinidad-api/src/main/java-templates/org/apache/myfaces/trinidad/component/UIXPageTemplate.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/branches/1.2.12.2-branch/trinidad-api/src/main/java-templates/org/apache/myfaces/trinidad/component/UIXPageTemplate.java?rev=908149&r1=908148&r2=908149&view=diff
==============================================================================
--- myfaces/trinidad/branches/1.2.12.2-branch/trinidad-api/src/main/java-templates/org/apache/myfaces/trinidad/component/UIXPageTemplate.java (original)
+++ myfaces/trinidad/branches/1.2.12.2-branch/trinidad-api/src/main/java-templates/org/apache/myfaces/trinidad/component/UIXPageTemplate.java Tue Feb  9 18:34:05 2010
@@ -25,13 +25,15 @@
 
 import javax.faces.component.UIComponent;
 import javax.faces.context.FacesContext;
-import javax.faces.el.MethodBinding;
 import javax.faces.event.AbortProcessingException;
 import javax.faces.event.FacesEvent;
 import javax.faces.event.PhaseId;
 
 import org.apache.myfaces.trinidad.bean.FacesBean;
 import org.apache.myfaces.trinidad.bean.PropertyKey;
+import org.apache.myfaces.trinidad.component.visit.VisitCallback;
+import org.apache.myfaces.trinidad.component.visit.VisitContext;
+import org.apache.myfaces.trinidad.component.visit.VisitHint;
 import org.apache.myfaces.trinidad.model.CollectionModel;
 import org.apache.myfaces.trinidad.model.RowKeySet;
 import org.apache.myfaces.trinidad.model.RowKeySetTreeImpl;
@@ -115,7 +117,90 @@
         processComponent(context, facets.get(facetKey), phaseId);
       }
     }
+  }
+  
+  @Override
+  protected boolean visitChildren(
+    VisitContext  visitContext,
+    VisitCallback callback)
+  {
+    boolean done = visitData(visitContext, callback);
+    
+    if (!done)
+    {
+      // process the children
+      int childCount = getChildCount();
+      if (childCount > 0)
+      {
+        for (UIComponent child : getChildren())
+        {
+          done = UIXComponent.visitTree(visitContext, child, callback);
+          
+          if (done)
+            break;
+        }
+      }
+      
+      // process the non-stamp facet children
+      if (!done)
+      {
+        // Visit the facets except for the node stamp
+        int facetCount = getFacetCount();
+        
+        if (facetCount > 0)
+        {
+          UIComponent nodeStamp = getNodeStamp();
+          
+          // if our only facet is the node stamp, we don't need to do this
+          if ((facetCount > 1) || (nodeStamp == null))
+          {
+            for (UIComponent facet : getFacets().values())
+            {
+              // ignore the nodeStamp facet, since it is stamped
+              if (facet != nodeStamp)
+              {
+                if (UIXComponent.visitTree(visitContext, facet, callback))
+                {
+                  done = true;
+                  break;
+                }
+              }
+            }
+          }
+        }        
+      }
+    }
+    
+    return done;
+  }
+  
+  @Override
+  protected boolean visitData(
+    VisitContext  visitContext,
+    VisitCallback callback)
+  {
+    Object oldPath = getRowKey();
+
+    // if we are only visiting rendered stamps, then pass in the disclosed row keys, otherwise
+    // pass in null, indicating that all row keys should be visited
+    RowKeySet disclosedRowKeys = (visitContext.getHints().contains(VisitHint.SKIP_UNRENDERED))
+                                   ? getDisclosedRowKeys()
+                                   : null;
 
+    setRowKey(null);
+
+    boolean done;
+    
+    try
+    {
+      done = visitHierarchy(visitContext, callback, getStamps(), disclosedRowKeys);
+    }
+    finally
+    {
+      setRowKey(oldPath);
+    }
+    
+    return done;
   }
 
   @Override

Modified: myfaces/trinidad/branches/1.2.12.2-branch/trinidad-api/src/main/java-templates/org/apache/myfaces/trinidad/component/UIXProcessTemplate.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/branches/1.2.12.2-branch/trinidad-api/src/main/java-templates/org/apache/myfaces/trinidad/component/UIXProcessTemplate.java?rev=908149&r1=908148&r2=908149&view=diff
==============================================================================
--- myfaces/trinidad/branches/1.2.12.2-branch/trinidad-api/src/main/java-templates/org/apache/myfaces/trinidad/component/UIXProcessTemplate.java (original)
+++ myfaces/trinidad/branches/1.2.12.2-branch/trinidad-api/src/main/java-templates/org/apache/myfaces/trinidad/component/UIXProcessTemplate.java Tue Feb  9 18:34:05 2010
@@ -18,9 +18,13 @@
  */
 package org.apache.myfaces.trinidad.component;
 
+import javax.faces.component.UIComponent;
 import javax.faces.context.FacesContext;
 import javax.faces.event.PhaseId;
 
+import org.apache.myfaces.trinidad.component.visit.VisitCallback;
+import org.apache.myfaces.trinidad.component.visit.VisitContext;
+
 
 /**
  * Base class for the Process component, which shows the steps of a process.
@@ -44,9 +48,55 @@
     
     // process the children
     TableUtils.__processChildren(context, this, phaseId);
-    
   }  
 
+  @Override
+  protected boolean visitChildren(
+    VisitContext  visitContext,
+    VisitCallback callback)
+  {
+    boolean done = visitData(visitContext, callback);
+    
+    if (!done)
+    {
+      // process the children
+      int childCount = getChildCount();
+      if (childCount > 0)
+      {
+        for (UIComponent child : getChildren())
+        {
+          done = UIXComponent.visitTree(visitContext, child, callback);
+          
+          if (done)
+            break;
+        }
+      }          
+    }
+    
+    return done;
+  }
   
-  
+  @Override
+  protected boolean visitData(
+    VisitContext  visitContext,
+    VisitCallback callback)
+  {
+    Object oldKey = getRowKey();
+       
+    Object focusPath = getFocusRowKey();    
+    setRowKey(focusPath);  
+    
+    boolean done;
+
+    try
+    {
+      done = visitLevel(visitContext, callback, getStamps());
+    }
+    finally
+    {
+      setRowKey(oldKey);
+    }
+        
+    return done;
+  }
 }

Modified: myfaces/trinidad/branches/1.2.12.2-branch/trinidad-api/src/main/java-templates/org/apache/myfaces/trinidad/component/UIXTableTemplate.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/branches/1.2.12.2-branch/trinidad-api/src/main/java-templates/org/apache/myfaces/trinidad/component/UIXTableTemplate.java?rev=908149&r1=908148&r2=908149&view=diff
==============================================================================
--- myfaces/trinidad/branches/1.2.12.2-branch/trinidad-api/src/main/java-templates/org/apache/myfaces/trinidad/component/UIXTableTemplate.java (original)
+++ myfaces/trinidad/branches/1.2.12.2-branch/trinidad-api/src/main/java-templates/org/apache/myfaces/trinidad/component/UIXTableTemplate.java Tue Feb  9 18:34:05 2010
@@ -24,7 +24,6 @@
 import java.util.IdentityHashMap;
 import java.util.Iterator;
 import java.util.List;
-import java.util.Set;
 
 import javax.el.MethodExpression;
 

Modified: myfaces/trinidad/branches/1.2.12.2-branch/trinidad-api/src/main/java-templates/org/apache/myfaces/trinidad/component/UIXTreeTableTemplate.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/branches/1.2.12.2-branch/trinidad-api/src/main/java-templates/org/apache/myfaces/trinidad/component/UIXTreeTableTemplate.java?rev=908149&r1=908148&r2=908149&view=diff
==============================================================================
--- myfaces/trinidad/branches/1.2.12.2-branch/trinidad-api/src/main/java-templates/org/apache/myfaces/trinidad/component/UIXTreeTableTemplate.java (original)
+++ myfaces/trinidad/branches/1.2.12.2-branch/trinidad-api/src/main/java-templates/org/apache/myfaces/trinidad/component/UIXTreeTableTemplate.java Tue Feb  9 18:34:05 2010
@@ -36,11 +36,12 @@
 import javax.faces.event.FacesEvent;
 import javax.faces.event.PhaseId;
 
+import org.apache.myfaces.trinidad.component.visit.VisitCallback;
+import org.apache.myfaces.trinidad.component.visit.VisitContext;
 import org.apache.myfaces.trinidad.event.FocusEvent;
 import org.apache.myfaces.trinidad.event.RangeChangeEvent;
 import org.apache.myfaces.trinidad.event.RangeChangeListener;
 import org.apache.myfaces.trinidad.model.RowKeySet;
-import org.apache.myfaces.trinidad.model.TreeModel;
 
 /**
  * Base class for TreeTable component. The behaviours implemented by the
@@ -274,19 +275,36 @@
    */
   // TODO cache the result.
   @Override
-  @SuppressWarnings("unchecked")
-  protected final List getStamps()
+  protected final List<UIComponent> getStamps()
   {
+    
     List<UIComponent> children = getChildren();
-    UIComponent nodeStamp = getNodeStamp();
-    if (nodeStamp != null)
+    List<UIComponent> stamps;
+    
+    if (children.isEmpty())
+    {
+      // no children, so use Node stamps as the stamp
+      stamps = super.getStamps();
+    }
+    else
     {
-      List<UIComponent> stamps = new ArrayList<UIComponent>(children.size() + 1);
-      stamps.addAll(children);
-      stamps.add(nodeStamp);
-      return stamps;
+      UIComponent nodeStamp = getNodeStamp();
+      
+      if (nodeStamp == null)
+      {
+        // no node stamp, so stamp, is only the children
+        stamps = children;
+      }
+      else
+      {
+        // stamps are the children plus the node stamp
+        stamps = new ArrayList<UIComponent>(children.size() + 1);
+        stamps.addAll(children);
+        stamps.add(nodeStamp);
+      }
     }
-    return children;
+    
+    return stamps;
   }
 
   /**
@@ -383,6 +401,80 @@
     }
   }
 
+  @Override
+  protected boolean visitChildren(
+    VisitContext  visitContext,
+    VisitCallback callback)
+  {
+    // need to override to do the default since our superclass
+    // UIXTree does stuff here we don't want
+    return defaultVisitChildren(visitContext, callback);
+  }
+
+  @Override
+  protected boolean visitUnstampedFacets(
+    VisitContext  visitContext,
+    VisitCallback callback)
+  {
+    // Visit the facets except for the node stamp
+    int facetCount = getFacetCount();
+    
+    if (facetCount > 0)
+    {
+      UIComponent nodeStamp = getNodeStamp();
+      
+      // if our only facet is the node stamp, we don't need to do this
+      if ((facetCount > 1) || (nodeStamp == null))
+      {
+        for (UIComponent facet : getFacets().values())
+        {
+          // ignore the nodeStamp facet, since it is stamped
+          if (facet != nodeStamp)
+          {
+            if (UIXComponent.visitTree(visitContext, facet, callback))
+            {
+              return true;
+            }
+          }
+        }
+      }
+    }
+
+    return false;
+  }
+
+  @Override
+  protected boolean visitData(
+    VisitContext  visitContext,
+    VisitCallback callback)
+  {
+    Object focusedPath = getFocusRowKey();
+    Object oldRowKey = null;
+    
+    // start from the focused area
+    if (focusedPath != null)
+    {
+      oldRowKey = getRowKey();
+      setRowKey(focusedPath);
+    }
+    
+    boolean done;
+    
+    try
+    {
+      done = super.visitData(new NoColumnFacetsVisitContext(visitContext), callback);
+    }
+    finally
+    {
+      if (focusedPath != null)
+      {
+        setRowKey(oldRowKey);
+      }
+    }
+    
+    return done;
+  }
+
   /**
    * Gets the path of the parent
    */

Modified: myfaces/trinidad/branches/1.2.12.2-branch/trinidad-api/src/main/java-templates/org/apache/myfaces/trinidad/component/UIXTreeTemplate.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/branches/1.2.12.2-branch/trinidad-api/src/main/java-templates/org/apache/myfaces/trinidad/component/UIXTreeTemplate.java?rev=908149&r1=908148&r2=908149&view=diff
==============================================================================
--- myfaces/trinidad/branches/1.2.12.2-branch/trinidad-api/src/main/java-templates/org/apache/myfaces/trinidad/component/UIXTreeTemplate.java (original)
+++ myfaces/trinidad/branches/1.2.12.2-branch/trinidad-api/src/main/java-templates/org/apache/myfaces/trinidad/component/UIXTreeTemplate.java Tue Feb  9 18:34:05 2010
@@ -31,6 +31,9 @@
 
 import org.apache.myfaces.trinidad.bean.FacesBean;
 import org.apache.myfaces.trinidad.bean.PropertyKey;
+import org.apache.myfaces.trinidad.component.visit.VisitCallback;
+import org.apache.myfaces.trinidad.component.visit.VisitContext;
+import org.apache.myfaces.trinidad.component.visit.VisitHint;
 import org.apache.myfaces.trinidad.event.RowDisclosureEvent;
 import org.apache.myfaces.trinidad.event.SelectionEvent;
 import org.apache.myfaces.trinidad.model.CollectionModel;
@@ -138,17 +141,36 @@
   {
     // this component has no facets that need to be processed once.
     // instead process the "nodeStamp" facet as many times as necessary:
-    Object oldPath = getRowKey();
-    setRowKey(null);
     HierarchyUtils.__iterateOverTree(context,
                                      phaseId,
                                      this,
                                      getDisclosedRowKeys(),
                                      true);
-    setRowKey(oldPath);
   }
 
   @Override
+  protected boolean visitChildren(
+    VisitContext  visitContext,
+    VisitCallback callback)
+  {
+    return visitData(visitContext, callback);
+  }
+  
+  @Override
+  protected boolean visitData(
+    VisitContext  visitContext,
+    VisitCallback callback)
+  {
+    // if we are only visiting rendered stamps, then pass in the disclosed row keys, otherwise
+    // pass in null, indicating that all row keys should be visited
+    RowKeySet disclosedRowKeys = (visitContext.getHints().contains(VisitHint.SKIP_UNRENDERED))
+                                   ? getDisclosedRowKeys()
+                                   : null;
+    
+    return visitHierarchy(visitContext, callback, getStamps(), disclosedRowKeys);
+  }
+  
+  @Override
   void __init()
   {
     super.__init();

Modified: myfaces/trinidad/branches/1.2.12.2-branch/trinidad-api/src/main/java/org/apache/myfaces/trinidad/component/HierarchyUtils.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/branches/1.2.12.2-branch/trinidad-api/src/main/java/org/apache/myfaces/trinidad/component/HierarchyUtils.java?rev=908149&r1=908148&r2=908149&view=diff
==============================================================================
--- myfaces/trinidad/branches/1.2.12.2-branch/trinidad-api/src/main/java/org/apache/myfaces/trinidad/component/HierarchyUtils.java (original)
+++ myfaces/trinidad/branches/1.2.12.2-branch/trinidad-api/src/main/java/org/apache/myfaces/trinidad/component/HierarchyUtils.java Tue Feb  9 18:34:05 2010
@@ -114,44 +114,47 @@
   {
     UIComponent nodeStamp = comp.getFacet("nodeStamp");
     int oldRow = comp.getRowIndex();
-    int first = comp.getFirst();
-    int last = TableUtils.getLast(comp, first);
-    for(int i=first; i<=last; i++)
+    
+    try
     {
-      comp.setRowIndex(i);
-      if (processChildrenAsStamps)
-        TableUtils.__processStampedChildren(context, comp, phaseId);
-      comp.processComponent(context, nodeStamp, phaseId);
-      if (comp.isContainer() && (state.isContained()))
+      int first = comp.getFirst();
+      int last = TableUtils.getLast(comp, first);
+      for(int i=first; i<=last; i++)
       {
-        comp.enterContainer();
-        __iterateOverTree( context, 
-                           phaseId, 
-                           comp, 
-                           state, 
-                           processChildrenAsStamps);
-        comp.exitContainer();
+        comp.setRowIndex(i);
+        if (processChildrenAsStamps)
+          TableUtils.__processStampedChildren(context, comp, phaseId);
+        comp.processComponent(context, nodeStamp, phaseId);
+        if (comp.isContainer() && (state.isContained()))
+        {
+          comp.enterContainer();
+          
+          try
+          {
+            __iterateOverTree( context, 
+                               phaseId, 
+                               comp, 
+                               state, 
+                               processChildrenAsStamps);
+          }
+          finally
+          {
+            comp.exitContainer();
+          }
+        }
       }
     }
-    comp.setRowIndex(oldRow);
-  }
-
-  // sets the currency to the row or container that we want to start rendering
-  // from:
-  static boolean __setStartLevelPath(
-    UIXHierarchy component,
-    int          startDepth
-  )
-  {
-    return HierarchyUtils.__setStartDepthPath(component, startDepth);
+    finally
+    {
+      comp.setRowIndex(oldRow);
+    }
   }
 
   // sets the currency to the row or container that we want to start rendering
   // from:
   static boolean __setStartDepthPath(
     UIXHierarchy component,
-    int          startDepth
-  )
+    int          startDepth)
   {
     boolean isNewPath = false;
     Object focusKey = component.getFocusRowKey();

Modified: myfaces/trinidad/branches/1.2.12.2-branch/trinidad-api/src/main/java/org/apache/myfaces/trinidad/component/StampState.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/branches/1.2.12.2-branch/trinidad-api/src/main/java/org/apache/myfaces/trinidad/component/StampState.java?rev=908149&r1=908148&r2=908149&view=diff
==============================================================================
--- myfaces/trinidad/branches/1.2.12.2-branch/trinidad-api/src/main/java/org/apache/myfaces/trinidad/component/StampState.java (original)
+++ myfaces/trinidad/branches/1.2.12.2-branch/trinidad-api/src/main/java/org/apache/myfaces/trinidad/component/StampState.java Tue Feb  9 18:34:05 2010
@@ -116,12 +116,6 @@
   public static void restoreStampState(FacesContext context, UIComponent stamp,
                                        Object stampState)
   {
-    String stampId = stamp.getId();
-    // Force the ID to be reset to reset the client identifier (needed
-    // for UIComponentBase implementation which caches clientId too
-    // aggressively)
-    stamp.setId(stampId);
-
     if (stampState != null)
     {
       RowState state = (RowState) stampState;

Modified: myfaces/trinidad/branches/1.2.12.2-branch/trinidad-api/src/main/java/org/apache/myfaces/trinidad/component/TableUtils.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/branches/1.2.12.2-branch/trinidad-api/src/main/java/org/apache/myfaces/trinidad/component/TableUtils.java?rev=908149&r1=908148&r2=908149&view=diff
==============================================================================
--- myfaces/trinidad/branches/1.2.12.2-branch/trinidad-api/src/main/java/org/apache/myfaces/trinidad/component/TableUtils.java (original)
+++ myfaces/trinidad/branches/1.2.12.2-branch/trinidad-api/src/main/java/org/apache/myfaces/trinidad/component/TableUtils.java Tue Feb  9 18:34:05 2010
@@ -18,7 +18,6 @@
  */
 package org.apache.myfaces.trinidad.component;
 
-import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
 
@@ -280,6 +279,9 @@
       @Override
       protected void process(FacesContext context, UIComponent child)
       {
+        // make sure that any cached clientIds are cleared so that
+        // the clientIds are recalculated with the new row index
+        UIXComponent.clearCachedClientIds(child);
         table.processComponent(context, child, phaseId);
       }
     }.runAlways(context, table);
@@ -299,11 +301,11 @@
     int childCount = comp.getChildCount();
     if (childCount != 0)
     {
-      List children = comp.getChildren();
+      List<UIComponent> children = comp.getChildren();
 
       for (int i = 0; i < childCount; i++)
       {
-        UIComponent child = (UIComponent)children.get(i);
+        UIComponent child = children.get(i);
         comp.processComponent(context, child, phaseId);
       }
     }          

Modified: myfaces/trinidad/branches/1.2.12.2-branch/trinidad-api/src/main/java/org/apache/myfaces/trinidad/component/UIXCollection.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/branches/1.2.12.2-branch/trinidad-api/src/main/java/org/apache/myfaces/trinidad/component/UIXCollection.java?rev=908149&r1=908148&r2=908149&view=diff
==============================================================================
--- myfaces/trinidad/branches/1.2.12.2-branch/trinidad-api/src/main/java/org/apache/myfaces/trinidad/component/UIXCollection.java (original)
+++ myfaces/trinidad/branches/1.2.12.2-branch/trinidad-api/src/main/java/org/apache/myfaces/trinidad/component/UIXCollection.java Tue Feb  9 18:34:05 2010
@@ -23,6 +23,7 @@
 import java.io.Serializable;
 
 import java.util.AbstractMap;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
 import java.util.Map;
@@ -40,6 +41,10 @@
 
 import org.apache.myfaces.trinidad.bean.FacesBean;
 import org.apache.myfaces.trinidad.bean.PropertyKey;
+import org.apache.myfaces.trinidad.component.visit.VisitCallback;
+import org.apache.myfaces.trinidad.component.visit.VisitContext;
+import org.apache.myfaces.trinidad.component.visit.VisitHint;
+import org.apache.myfaces.trinidad.component.visit.VisitResult;
 import org.apache.myfaces.trinidad.event.SelectionEvent;
 import org.apache.myfaces.trinidad.logging.TrinidadLogger;
 import org.apache.myfaces.trinidad.model.CollectionModel;
@@ -294,7 +299,9 @@
     }
     else
     {
-      superState = stampState = clientKeyMgr = null;
+      superState = null;
+      stampState = null;
+      clientKeyMgr = null;
     }
     super.restoreState(context, superState);
 
@@ -320,7 +327,7 @@
   /**
    * Checks to see if the current row is available. This is useful when the
    * total number of rows is not known.
-   * @see CollectionModel#isRowAvailable
+   * @see CollectionModel#isRowAvailable()
    * @return true iff the current row is available.
    */
   public final boolean isRowAvailable()
@@ -427,7 +434,7 @@
 
   /**
    * Gets the data for the current row.
-   * @see CollectionModel#getRowData
+   * @see CollectionModel#getRowData(int)
    * @return null if the current row is unavailable
    */
   public final Object getRowData()
@@ -536,7 +543,7 @@
   /**
    * Clear the rowKey-to-currencyString cache.
    * The cache is not cleared immediately; instead it will be cleared
-   * when {@link #encodeBegin} is called.
+   * when {@link #encodeBegin(FacesContext)} is called.
    * @deprecated Have your Renderer implement {@link ClientRowKeyManagerFactory}
    * and create your own {@link ClientRowKeyManager} instances. Then you can
    * manage the lifecycle of each key inside your ClientRowKeyManager.
@@ -800,6 +807,11 @@
     }
 
     _restoreStampState();
+
+    // ensure the client IDs are reset on the component, otherwise they will not get the
+    // proper stamped IDs. This mirrors the behavior in UIData and follows the JSF specification
+    // on when client IDs are allowed to be cached and when they must be reset
+    clearCachedClientIds();
   }
 
   /**
@@ -856,7 +868,7 @@
     // just having stamp state, and having stamp state + child/facet state
     assert(!(stampState instanceof Object[]));
 
-    int facetCount = _getFacetCount(stamp);
+    int facetCount = stamp.getFacetCount();
 
     Object[] state = null;
 
@@ -943,11 +955,6 @@
     // Just a transient component - return
     if ((stampState == Transient.TRUE) || (stampState == null))
     {
-      // ensure the client IDs are reset on the component, otherwise they will not get the
-      // proper stamped IDs. This mirrors the behavior in UIData and follows the JSF specification
-      // on when client IDs are allowed to be cached and when they must be reset
-      String id = stamp.getId();
-      stamp.setId(id);
       return;
     }
 
@@ -997,7 +1004,7 @@
 
   /**
    * Process a component.
-   * This method calls {@link #processDecodes},
+   * This method calls {@link #processDecodes(FacesContext)},
    * {@link #processValidators} or
    * {@link #processUpdates}
    * depending on the {#link PhaseId}.
@@ -1147,6 +1154,268 @@
   }
 
   /**
+   * <p>
+   * Override default children visiting code to visit the facets and facets of the columns
+   * before delegating to the <code>visitData</code> to visit the individual rows of data.
+   * </p><p>
+   * Subclasses should override this method if they wish to change the way in which the non-stamped
+   * children are visited.  If they wish to change the wash the the stamped children are visited,
+   * they should override <code>visitData</code> instead.
+   * </p>
+   * @param visitContext
+   * @param callback
+   * @return <code>true</code> if all of the children to visit have been visited
+   * @see #visitData
+   */
+  @Override
+  protected boolean visitChildren(
+    VisitContext  visitContext,
+    VisitCallback callback)
+  {
+    return defaultVisitChildren(visitContext, callback);
+  }
+  
+  protected final boolean defaultVisitChildren(
+    VisitContext  visitContext,
+    VisitCallback callback)
+  {
+    boolean doneVisiting;
+    
+    // Clear out the row index if one is set so that
+    // we start from a clean slate.
+    int oldRowIndex = getRowIndex();
+    setRowIndex(-1);
+
+    try
+    {
+      // visit the unstamped children
+      doneVisiting = visitUnstampedFacets(visitContext, callback);
+      
+      if (!doneVisiting)
+      {
+        doneVisiting = _visitStampedColumnFacets(visitContext, callback);
+        
+        // visit the stamped children
+        if (!doneVisiting)
+        {
+          doneVisiting = visitData(visitContext, callback);
+        }
+      }
+    }
+    finally
+    {
+      // restore the original rowIndex
+      setRowIndex(oldRowIndex);      
+    }
+    
+    return doneVisiting;    
+  }
+  
+  /**
+   * Hook method for subclasses to override to change the behavior
+   * of how unstamped facets of the UIXCollection are visited.  The
+   * Default implementation visits all of the facets of the
+   * UIXCollection.
+   */
+  protected boolean visitUnstampedFacets(
+    VisitContext  visitContext,
+    VisitCallback callback)
+  {
+    // Visit the facets with no row
+    if (getFacetCount() > 0)
+    {
+      for (UIComponent facet : getFacets().values())
+      {
+        if (UIXComponent.visitTree(visitContext, facet, callback))
+        {
+          return true;
+        }
+      }
+    }
+
+    return false;
+  }
+  
+  /**
+   * Wrapper implementation of VisitContext
+   */
+  private static abstract class VisitContextWrapper extends VisitContext
+  {
+    protected abstract VisitContext getWrapped();
+
+    @Override
+    public FacesContext getFacesContext()
+    {
+      return getWrapped().getFacesContext();
+    }
+    
+    @Override
+    public PhaseId getPhaseId()
+    {
+      return getWrapped().getPhaseId();
+    }
+
+    @Override
+    public Collection<String> getIdsToVisit()
+    {
+      return getWrapped().getIdsToVisit();
+    }
+
+    @Override
+    public Collection<String> getSubtreeIdsToVisit(UIComponent component)
+    {
+      return getWrapped().getSubtreeIdsToVisit(component);
+    }
+
+    @Override
+    public VisitResult invokeVisitCallback(UIComponent component, VisitCallback callback)
+    {
+      return getWrapped().invokeVisitCallback(component, callback);
+    }
+
+    @Override
+    public Set<VisitHint> getHints()
+    {
+      return getWrapped().getHints();
+    }
+  }
+  
+  /**
+   * VistiContext that visits the facets of the UIXColumn children, including
+   * nested UIXColumn childrem
+   */
+  private static class ColumnFacetsOnlyVisitContext extends VisitContextWrapper
+  {
+    public ColumnFacetsOnlyVisitContext(VisitContext wrappedContext)
+    {
+      _wrapped = wrappedContext;
+    }
+    
+    @Override
+    protected VisitContext getWrapped()
+    {
+      return _wrapped;
+    }
+    
+    @Override
+    public VisitResult invokeVisitCallback(UIComponent component, VisitCallback callback)
+    {
+      if (component instanceof UIXColumn)
+      {
+        if (component.getFacetCount() > 0)
+        {
+          // visit the facet children without filtering for just UIXColumn children
+          for (UIComponent facetChild : component.getFacets().values())
+          {
+            if (UIXComponent.visitTree(getWrapped(), facetChild, callback))
+              return VisitResult.COMPLETE;
+          }
+          
+          // visit the indexed children, recursively looking for more columns
+          for (UIComponent child : component.getChildren())
+          {
+            if (UIXComponent.visitTree(this, child, callback))
+              return VisitResult.COMPLETE;
+          }
+        }
+      }
+      
+      // at this point, we either have already manually processed the UIXColumn's children, or
+      // the component wasn't a UIXColumn and shouldn't be processed
+      return VisitResult.REJECT;
+    }
+    
+    private final VisitContext _wrapped;
+  }
+
+  /**
+   * VisitContext implementation that doesn't visit any of the Facets of
+   * UIXColumn children.  This is used when stamping children
+   */
+  protected static final class NoColumnFacetsVisitContext extends VisitContextWrapper
+  {
+    NoColumnFacetsVisitContext(VisitContext wrapped)
+    {
+      _wrapped = wrapped;
+    }
+
+    @Override
+    protected VisitContext getWrapped()
+    {
+      return _wrapped;
+    }
+
+    @Override
+    public VisitResult invokeVisitCallback(UIComponent component, VisitCallback callback)
+    {
+      if (component instanceof UIXColumn)
+      {
+        if (component.getChildCount() > 0)
+        {
+          // visit only the indexed children of the columns
+          for (UIComponent child : component.getChildren())
+          {
+            if (UIXComponent.visitTree(this, child, callback))
+              return VisitResult.COMPLETE;
+          }
+        }
+        
+        return VisitResult.REJECT;
+      }
+      else
+      {
+        if (UIXComponent.visitTree(getWrapped(), component, callback))
+          return VisitResult.COMPLETE;
+        else
+          return VisitResult.REJECT;
+      }
+    }
+    
+    private final VisitContext _wrapped;
+  }
+  
+  /**
+   * Implementation used to visit each stamped row
+   */
+  private boolean _visitStampedColumnFacets(
+    VisitContext      visitContext,
+    VisitCallback     callback)
+  {    
+    // visit the facets of the stamped columns
+    List<UIComponent> stamps = getStamps();
+    
+    if (!stamps.isEmpty())
+    {
+      VisitContext columnVisitingContext = new ColumnFacetsOnlyVisitContext(visitContext);
+      
+      for (UIComponent stamp : stamps)
+      {
+        if (UIXComponent.visitTree(columnVisitingContext, stamp, callback))
+        {
+          return true;
+        }
+      }
+    }
+    
+    return false;
+  }
+
+
+  /**
+   * Visit the rows and children of the columns of the collection per row-index. This should
+   * not visit row index -1 (it will be perfomed in the visitTree method). The columns
+   * themselves should not be visited, only their children in this function.
+   *
+   * @param visitContext The visiting context
+   * @param callback The visit callback
+   * @return true if the visiting should stop
+   * @see #visitChildren(VisitContext, VisitCallback)
+   */
+  protected abstract boolean visitData(
+    VisitContext  visitContext,
+    VisitCallback callback);
+
+  /**
    * Gets the CollectionModel to use with this component.
    *
    * @param createIfNull  creates the collection model if necessary
@@ -1359,7 +1628,7 @@
   
   /**
    * Indicates the caching strategy supported by the model
-   * @see LocalCachingStrategy
+   * @see LocalRowKeyIndex.LocalCachingStrategy
    * @return caching strategy supported by the model
    */
   public LocalRowKeyIndex.LocalCachingStrategy getCachingStrategy()
@@ -1585,21 +1854,8 @@
     return b.equals(a);
   }
 
-  //
-  // Optimized path that avoids creating the Facet map
-  // unless necessary
-  //
-  private int _getFacetCount(UIComponent component)
-  {
-    if (component instanceof UIXComponent)
-      return ((UIXComponent) component).getFacetCount();
-
-    return component.getFacets().size();
-  }
-
   private static final class DefaultClientKeyManager extends ClientRowKeyManager
   {
-
     public void clear()
     {
       _currencyCache.clear();

Modified: myfaces/trinidad/branches/1.2.12.2-branch/trinidad-api/src/main/java/org/apache/myfaces/trinidad/component/UIXComponent.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/branches/1.2.12.2-branch/trinidad-api/src/main/java/org/apache/myfaces/trinidad/component/UIXComponent.java?rev=908149&r1=908148&r2=908149&view=diff
==============================================================================
--- myfaces/trinidad/branches/1.2.12.2-branch/trinidad-api/src/main/java/org/apache/myfaces/trinidad/component/UIXComponent.java (original)
+++ myfaces/trinidad/branches/1.2.12.2-branch/trinidad-api/src/main/java/org/apache/myfaces/trinidad/component/UIXComponent.java Tue Feb  9 18:34:05 2010
@@ -226,9 +226,9 @@
    * <p>
    * If a Renderer needs to
    * collect information about its possibly flattened children before calling
-   * <code>encodeFlattenedChild(FacesContext, ComponentProcessor, Iterable<UIComponent>, Object)</code>,
+   * <code>encodeFlattenedChild(FacesContext, ComponentProcessor, Iterable&lt;UIComponent&gt;, Object)</code>,
    * it should call
-   * <code>processFlattenedChildren(FacesContext, ComponentProcessor, Iterable<UIComponent>, Object)</code>
+   * <code>processFlattenedChildren(FacesContext, ComponentProcessor, Iterable&lt;UIComponent&gt;, Object)</code>
    * to collect the information.
    * <p>
    * For each FlattenedComponent child, the <code>childProcessor</code> will
@@ -239,6 +239,10 @@
    * FlattenedComponents that wish to check whether they are processed for the purpose of
    * encoding can check the ProcessingHints of the ComponentProcessingContext for the
    * presence of <code>PROCESS_FOR_ENCODING hint</code>.
+   * @param context FacesContext
+   * @param childProcessor ComponentProcessor to call on each flattened child
+   * @param children Initial set of children to flatten
+   * @param callbackContext context object to pass to the childProcessor on each invocation
    * @return <code>true</code> If any children were processed
    * @see UIXComponent#processFlattenedChildren(FacesContext, ComponentProcessor, Iterable, Object)
    * @see FlattenedComponent
@@ -326,6 +330,83 @@
     return visitTree(visitContext, this, callback);
   }
 
+ /**
+  * Hook for subclasses to override the manner in which the component's children are visited.  The default
+  * implementation visits all of the children and facets of the Component.
+  * <code>setupChildrenVisitingContext</code> will have been called before this method is
+  * invoked and <code>tearDownChildrenVisitingContext</code> will be called after.
+  * respectively.  If the purpose of this visit was to encode the component and the
+  * component uses a CoreRenderer, the CoreRenderer's
+  * <code>setupChildrenEncodingContext</code> and <code>tearDownChildrenEncodingContext</code>
+  * will be called before and after this method is invoked, respectively.
+  * @param visitContext the <code>VisitContext</code> for this visit
+  * @param callback the <code>VisitCallback</code> instance
+  * @return <code>true</code> if the visit is complete.
+  * @see #setupChildrenVisitingContext
+  * @see #tearDownChildrenVisitingContext
+  * @see org.apache.myfaces.trinidad.render.CoreRenderer#setupChildrenEncodingContext
+  * @see org.apache.myfaces.trinidad.render.CoreRenderer#tearDownChildrenEncodingContext
+  */
+  protected boolean visitChildren(
+    VisitContext visitContext,
+    VisitCallback callback)
+  {
+    return _visitChildrenImpl(visitContext, this, callback);
+  }
+  
+  /**
+   * Visit all of the children of the component
+   */
+  private static boolean _visitChildrenImpl(
+    VisitContext visitContext,
+    UIComponent   component,
+    VisitCallback callback)
+  {
+    // visit the children of the component
+    Iterator<UIComponent> kids = component.getFacetsAndChildren();
+
+    while(kids.hasNext())
+    {
+      boolean done;
+
+      UIComponent currChild = kids.next();
+
+      if (currChild instanceof UIXComponent)
+      {
+        UIXComponent uixChild = (UIXComponent)currChild;
+
+        // delegate to UIXComponent's visitTree implementation to allow
+        // subclassses to modify the behavior
+        done = uixChild.visitTree(visitContext, callback);
+      }
+      else
+      {
+        // use generic visit implementation
+        done = visitTree(visitContext, currChild, callback);
+      }
+
+      // If any kid visit returns true, we are done.
+      if (done)
+      {
+        return true;
+      }
+    }
+    
+    return false;
+  }
+
+  /**
+   * Returns <code>true</code> if the components are being visited
+   * for the purpose of encoding.
+   */
+  private static boolean _isEncodingVisit(VisitContext visitContext)
+  {
+    PhaseId phaseId = visitContext.getPhaseId();
+
+    return((PhaseId.RENDER_RESPONSE == phaseId) &&
+           visitContext.getHints().contains(VisitHint.EXECUTE_LIFECYCLE));
+  }
+  
   /**
   * <p>Perform a tree visit starting at the specified node in the tree.</p>
   *
@@ -350,10 +431,15 @@
   * @see VisitContext#invokeVisitCallback VisitContext.invokeVisitCallback()
   */
   public static boolean visitTree(
-    VisitContext visitContext,
+    VisitContext  visitContext,
     UIComponent   component,
     VisitCallback callback)
   {
+    FacesContext context = visitContext.getFacesContext();
+    RenderingContext rc = (_isEncodingVisit(visitContext))
+                            ? RenderingContext.getCurrentInstance()
+                            : null;
+
     UIXComponent uixComponent;
 
     // determine if we should even visit this component subtree
@@ -364,6 +450,18 @@
       // delegate to the UIXComponent
       if (!uixComponent.isVisitable(visitContext))
         return false;
+
+      // UIXComponents are allowed to set up their context differently for encoding
+      // than normal processing, so behave differently if this is the RenderResponse
+      // phase
+      if (rc != null)
+      {
+        uixComponent.setupEncodingContext(context, rc);
+      }
+      else
+      {
+        uixComponent.setupVisitingContext(context);
+      }
     }
     else
     {
@@ -374,110 +472,108 @@
       uixComponent = null;
     }
 
+    VisitResult visitResult = VisitResult.REJECT;
+    boolean doneVisiting = false;
+    
+    try
+    {
     // invoke the callback for this component
-    VisitResult result = visitContext.invokeVisitCallback(component, callback);
-
-    if (result == VisitResult.COMPLETE)
-      return true;
-    else if (result == VisitResult.ACCEPT)
-    {
-      // now visit the children
-      FacesContext context = visitContext.getFacesContext();
-      PhaseId phaseId = visitContext.getPhaseId();
-      RenderingContext rc = (PhaseId.RENDER_RESPONSE == phaseId)
-                              ? RenderingContext.getCurrentInstance()
-                              : null;
+      visitResult = visitContext.invokeVisitCallback(component, callback);
 
-      if (uixComponent != null)
+      if (visitResult == VisitResult.COMPLETE)
+        doneVisiting = true;
+      else if (visitResult == VisitResult.ACCEPT)
       {
-        // assume that all UIXComponent NamingContainers always act as NamingContainers,
-        // (unlike <h:form>) and this it is OK to put the optimization where we
-        // don't visit the children if we know that we don't have any ids in this
-        // subtree to visit
-        if (uixComponent instanceof NamingContainer)
-        {
-          if (visitContext.getSubtreeIdsToVisit(uixComponent).isEmpty())
-            return false;
-        }
+        // now determine whether we need to visit the children      
+        boolean skipChildren = false;
 
-        // UIXComponents are allowed to set up their context differently for encoding
-        // than normal processing, so behave differently if this is the RenderResponse
-        // phase
-        if (PhaseId.RENDER_RESPONSE == phaseId)
+        if (uixComponent != null)
         {
-          uixComponent.setUpEncodingContext(context, rc);
+          // assume that all UIXComponent NamingContainers always act as NamingContainers,
+          // (unlike <h:form>) and this it is OK to put the optimization where we
+          // don't visit the children if we know that we don't have any ids in this
+          // subtree to visit
+          if (uixComponent instanceof NamingContainer)
+          {
+            if (visitContext.getSubtreeIdsToVisit(uixComponent).isEmpty())
+              skipChildren = true;
+          }
         }
         else
         {
-          uixComponent.setupVisitingContext(context);
-        }
-      }
-      else
-      {
-        // we only optimize walking into non-UIXComponent NamingContainers
-        // if they are UINamingConainer (which is used by <f:subview>
-        if (UINamingContainer.class == component.getClass())
-        {
-          if (visitContext.getSubtreeIdsToVisit(component).isEmpty())
-            return false;
-        }
-      }
-
-      // visit the children of the component
-      try
-      {
-        Iterator<UIComponent> kids = component.getFacetsAndChildren();
-
-        while(kids.hasNext())
-        {
-          boolean done;
-
-          UIComponent currChild = kids.next();
-
-          if (currChild instanceof UIXComponent)
+          // we only optimize walking into non-UIXComponent NamingContainers
+          // if they are UINamingConainer (which is used by <f:subview>
+          if (UINamingContainer.class == component.getClass())
           {
-            UIXComponent uixChild = (UIXComponent)currChild;
-
-            // delegate to UIXComponent's visitTree implementation to allow
-            // subclassses to modify the behavior
-            done = uixChild.visitTree(visitContext, callback);
-          }
-          else
-          {
-            // use generic visit implementation
-            done = visitTree(visitContext, currChild, callback);
-          }
-
-          // If any kid visit returns true, we are done.
-          if (done)
-          {
-            return true;
+            if (visitContext.getSubtreeIdsToVisit(component).isEmpty())
+              skipChildren = true;
           }
         }
-      }
-      finally
-      {
-        // tear down the context we set up in order to visit our children
-        if (uixComponent != null)
+  
+        // visit the children of the component if we aren't supposed to skip them
+        if (!skipChildren)
         {
-          if (PhaseId.RENDER_RESPONSE == phaseId)
+          if (uixComponent != null)
           {
-            uixComponent.tearDownEncodingContext(context, rc);
+            // setup any context needed for visiting the children of the component as opposed
+            // to the component itself
+            if (rc != null)
+            {
+              uixComponent._setupChildrenEncodingContext(context, rc);
+            }
+            else
+            {
+              uixComponent.setupChildrenVisitingContext(context);
+            }
+            
+            
+            try
+            {
+              doneVisiting =  uixComponent.visitChildren(visitContext, callback);
+            }
+            finally
+            {
+              // teardown any context initialized above
+              if (rc != null)
+              {
+                uixComponent._tearDownChildrenEncodingContext(context, rc);
+              }
+              else
+              {
+                uixComponent.tearDownChildrenVisitingContext(context);
+              }
+            }
           }
           else
           {
-            uixComponent.tearDownVisitingContext(context);
+            doneVisiting = _visitChildrenImpl(visitContext, component, callback);
           }
         }
       }
+      else
+      {
+        // don't visit the children
+        assert(visitResult == VisitResult.REJECT);
+      }
     }
-    else
+    finally
     {
-      assert(result == VisitResult.REJECT);
+      // tear down the context we set up in order to visit our component
+      if (uixComponent != null)
+      {
+        if (rc != null)
+        {
+          uixComponent.tearDownEncodingContext(context, rc);
+        }
+        else
+        {
+          uixComponent.tearDownVisitingContext(context);
+        }
+      }
     }
-
+  
     // if we got this far, we're not done
-    return false;
+    return doneVisiting;
   }
 
   /**
@@ -510,6 +606,29 @@
   }
 
   /**
+   * Clears all of the cached clientIds in this component subtree
+   */
+  public final void clearCachedClientIds()
+  {
+    clearCachedClientIds(this);
+  }
+
+  /**
+   * Clears all of the cached clientIds in the component's subtree
+   * @param component Component subtree to clear the cached client ids for
+   */
+  public static void clearCachedClientIds(UIComponent component)
+  {
+    String id = component.getId();
+    component.setId(id);
+    
+    Iterator<UIComponent> allChildren = component.getFacetsAndChildren();
+    
+    while (allChildren.hasNext())
+      clearCachedClientIds(allChildren.next());
+  }
+
+  /**
    * Marks this component as a partial target for this request. Typically called
    * by the {@link org.apache.myfaces.trinidad.context.RequestContext RequestContext}.
    * The component should add the client ID the desired rendered component to the context.
@@ -527,9 +646,9 @@
 
   /**
    * <p>Called by
-   * {@link UIXComponent#visitTree UIXComponent.visitTree()} to determine
+   * {@link UIXComponent#visitTree(VisitContext, VisitCallback) UIXComponent.visitTree()} to determine
    * whether this component is "visitable" - ie. whether this component
-   * satisfies the {@link org.apache.myfaces.trinidad.component.visit.VisitHints} returned by
+   * satisfies the {@link org.apache.myfaces.trinidad.component.visit.VisitHint} returned by
    * {@link VisitContext#getHints VisitContext.getHints()}.</p>
    * <p>If this component is not visitable (ie. if this method returns
    * false), the tree visited is short-circuited such that neither the
@@ -537,7 +656,7 @@
    * <p>Custom {@code treeVisit()} implementations may call this method
    * to determine whether the component is visitable before performing
    * any visit-related processing.</p>
-   *
+   * @param visitContext VisitingContext to use to determine if the component is visitable
    * @return true if this component should be visited, false otherwise.
    */
   protected boolean isVisitable(VisitContext visitContext)
@@ -645,11 +764,29 @@
    * <code>tearDownVisitingContext</code> as well.</p>
    * <p>It is guaranteed that if <code>setupVisitingContext</code> completes
    * <code>tearDownVisitingContext</code> will be called for this component</p>
+   * @param context FacesContext
    * @see #tearDownVisitingContext
-   * @see #setUpEncodingContext
+   * @see #setupEncodingContext
    * @see #tearDownEncodingContext
    */
-  protected void setupVisitingContext(FacesContext context)
+  protected void setupVisitingContext(@SuppressWarnings("unused") FacesContext context)
+  {
+    // do nothing
+  }
+
+  /**
+   * <p>Sets up the context necessary to visit or invoke the children of a component for all phases.
+   * </p>
+   * <p>The default implementation does nothing.</p>
+   * <p>If a subclass overrides this method, it should override
+   * <code>tearDownChildrenVisitingContext</code> as well.</p>
+   * <p>It is guaranteed that if <code>setupChildrenVisitingContext</code> completes
+   * <code>tearDownChildrenVisitingContext</code> will be called for this component</p>
+   * @param context FacesContext
+   * @see #visitChildren
+   * @see #tearDownChildrenVisitingContext
+   */
+  protected void setupChildrenVisitingContext(@SuppressWarnings("unused") FacesContext context)
   {
     // do nothing
   }
@@ -662,16 +799,40 @@
    * <code>setupVisitingContext</code> as well</p>
    * <p>It is guaranteed that <code>tearDownVisitingContext</code> will be called only after
    * <code>setupVisitingContext</code> has been called for this component</p>
+   * @param context FacesContext
    * @see #setupVisitingContext
-   * @see #setUpEncodingContext
+   * @see #setupEncodingContext
    * @see #tearDownEncodingContext
    */
-  protected void tearDownVisitingContext(FacesContext context)
+  protected void tearDownVisitingContext(@SuppressWarnings("unused") FacesContext context)
   {
     // do nothing
   }
 
   /**
+   * <p>Tears down context created in order to visit or invoke the children of a component
+   * for all phases.</p>
+   * <p>The default implementation does nothing.</p>
+   * <p>A subclass should only override this method if it overrode
+   * <code>setupChildrenVisitingContext</code> as well</p>
+   * <p>It is guaranteed that <code>tearDownChildrenVisitingContext</code> will be called only after
+   * <code>setupChildrenVisitingContext</code> has been called for this component</p>
+   * @param context FacesContext
+   * @see #setupChildrenVisitingContext
+   * @see #visitChildren
+   */
+  protected void tearDownChildrenVisitingContext(@SuppressWarnings("unused") FacesContext context)
+  {
+    // do nothing
+  }
+
+  @Deprecated
+  protected final void setUpEncodingContext(FacesContext context, RenderingContext rc)
+  {
+    setupEncodingContext(context, rc);
+  }
+
+  /**
    * <p>Sets up the context necessary to encode the component.</p>
    * <p>The default implementation delegates to
    * <code>CoreRenderer.setupEncodingContext</code> and then calls
@@ -680,12 +841,14 @@
    * <code>tearDownEncodingContext</code> as well.</p>
    * <p>It is guaranteed that if <code>setUpEncodingContext</code> completes
    * <code>tearDownEncodingContext</code> will be called for this component</p>
+   * @param context The FacesContext
+   * @param rc      RenderingContext to use for encoding
    * @see #setupVisitingContext
    * @see #tearDownVisitingContext
    * @see #tearDownEncodingContext
    * @see CoreRenderer#setupEncodingContext
    */
-  protected void setUpEncodingContext(FacesContext context, RenderingContext rc)
+  protected void setupEncodingContext(FacesContext context, RenderingContext rc)
   {
     setupVisitingContext(context);
 
@@ -700,17 +863,41 @@
   }
 
   /**
+   * Sets the context necessary to encode the children of a component.
+   * @param context The FacesContext
+   * @param rc      RenderingContext to use for encoding
+   * @see #setupChildrenVisitingContext
+   * @see #_tearDownChildrenEncodingContext
+   * @see org.apache.myfaces.trinidad.render.CoreRenderer#setupChildrenEncodingContext
+   */
+  private void _setupChildrenEncodingContext(FacesContext context, RenderingContext rc)
+  {
+    setupChildrenVisitingContext(context);
+
+    Renderer renderer = getRenderer(context);
+
+    if (renderer instanceof CoreRenderer)
+    {
+      CoreRenderer coreRenderer = (CoreRenderer)renderer;
+
+      coreRenderer.setupChildrenEncodingContext(context, rc, this);
+    }    
+  }
+
+  /**
    * <p>Tears down the context created in order to encode the component</p>
    * <p>The default implementation delegates to
    * <code>CoreRenderer.tearDownEncodingContext</code> and then calls
    * <code>tearDownVisitingContext</code></p>
    * <p>A subclass should only override this method if it overrode
-   * <code>setUpEncodingContext</code> as well</p>
+   * <code>setupEncodingContext</code> as well</p>
    * <p>It is guaranteed that <code>tearDownEncodingContext</code> will be called only after
-   * <code>setUpEncodingContext</code> has been called for this component</p>
-   * @see #setUpEncodingContext
+   * <code>setupEncodingContext</code> has been called for this component</p>
+   * @param context The FacesContext
+   * @param rc      RenderingContext to use for encoding
+   * @see #setupEncodingContext
    * @see #tearDownVisitingContext
-   * @see #setUpEncodingContext
+   * @see #setupEncodingContext
    * @see CoreRenderer#tearDownEncodingContext
    */
   protected void tearDownEncodingContext(
@@ -735,6 +922,35 @@
   }
 
   /**
+   * Tears down the context necessary to encode the children of a component.
+   * @param context The FacesContext
+   * @param rc      RenderingContext to use for encoding
+   * @see #setupChildrenVisitingContext
+   * @see #_tearDownChildrenEncodingContext
+   * @see org.apache.myfaces.trinidad.render.CoreRenderer#setupChildrenEncodingContext
+   */
+  private void _tearDownChildrenEncodingContext(
+    FacesContext context,
+    RenderingContext rc)
+  {
+    Renderer renderer = getRenderer(context);
+
+    try
+    {
+      if (renderer instanceof CoreRenderer)
+      {
+        CoreRenderer coreRenderer = (CoreRenderer)renderer;
+
+        coreRenderer.tearDownChildrenEncodingContext(context, rc, this);
+      }
+    }
+    finally
+    {
+      tearDownChildrenVisitingContext(context);
+    }
+  }
+
+  /**
    * Returns the FacesBean used for storing the component's state.
    */
   abstract public FacesBean getFacesBean();

Modified: myfaces/trinidad/branches/1.2.12.2-branch/trinidad-api/src/main/java/org/apache/myfaces/trinidad/component/UIXComponentBase.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/branches/1.2.12.2-branch/trinidad-api/src/main/java/org/apache/myfaces/trinidad/component/UIXComponentBase.java?rev=908149&r1=908148&r2=908149&view=diff
==============================================================================
--- myfaces/trinidad/branches/1.2.12.2-branch/trinidad-api/src/main/java/org/apache/myfaces/trinidad/component/UIXComponentBase.java (original)
+++ myfaces/trinidad/branches/1.2.12.2-branch/trinidad-api/src/main/java/org/apache/myfaces/trinidad/component/UIXComponentBase.java Tue Feb  9 18:34:05 2010
@@ -304,10 +304,10 @@
 
   // ------------------------------------------------------------- Properties
 
-
-
-  @Override
-  public String getClientId(FacesContext context)
+  /**
+   * Calculates the clientId for the component
+   */
+  private String _calculateClientId(FacesContext context)
   {
     // the clientId is always at least the id of the current component
     // our implementation of getId() guarantees that this always
@@ -321,27 +321,53 @@
       if (containerComponent instanceof NamingContainer)
       {
         String contClientId;
-
+    
         // Pass additional context information to naming containers which extend UIXComponent:
         if (containerComponent instanceof UIXComponent)
           contClientId = ((UIXComponent)containerComponent).getContainerClientId(context, this);
         else
           contClientId = containerComponent.getContainerClientId(context);
-
+    
         StringBuilder bld = __getSharedStringBuilder();
         bld.append(contClientId).append(NamingContainer.SEPARATOR_CHAR).append(clientId);
         clientId = bld.toString();
         break;
       }
-
+    
       containerComponent = containerComponent.getParent();
     }
-
+    
     Renderer renderer = getRenderer(context);
     if (null != renderer)
       clientId = renderer.convertClientId(context, clientId);
+    
+    return clientId;
+  }
+  
 
+
+  @Override
+  public String getClientId(FacesContext context)
+  {
+    return _calculateClientId(context);
+/* TODO put back in when we fix all of the clientID caching issues
+    String clientId = _clientId;
+    
+    if (clientId == null)
+    {
+      clientId = _calculateClientId(context);
+      
+      if (_usesFacesBeanImpl)
+        _clientId = clientId;
+    }
+    else
+    {
+      assert clientId.equals(_calculateClientId(context)) :
+      "cached client id " + _clientId + " for " + this + " doesn't match client id:" + _calculateClientId(context);
+    }
+    
     return clientId;
+*/
   }
 
 
@@ -397,6 +423,8 @@
   @Override
   public void setId(String id)
   {
+    _clientId = null;
+    
     FacesBean facesBean = getFacesBean();
     
     // if we are using a FacesBeanImpl, then the FacesBean will
@@ -410,6 +438,13 @@
       {
         _validateId(id);
         _id = id;
+        
+        // if we're a NamingContainer then changing our id will invalidate the clientIds of all
+        // of our children
+        if ((_clientId != null) && (this instanceof NamingContainer))
+        {
+          clearCachedClientIds(this);
+        }
       }      
     }
     else
@@ -418,7 +453,7 @@
       facesBean.setProperty(ID_KEY, id);      
     }
   }
-
+  
   @Override
   abstract public String getFamily();
 
@@ -607,7 +642,8 @@
   {
     if (_children == null)
       return 0;
-    return getChildren().size();
+    else
+      return getChildren().size();
   }
 
 
@@ -631,9 +667,11 @@
   {
     if (facetName == null)
       throw new NullPointerException();
+    
     if (_facets == null)
       return null;
-    return getFacets().get(facetName);
+    else
+      return getFacets().get(facetName);
   }
 
 
@@ -648,7 +686,8 @@
   {
     if (_facets == null)
       return _EMPTY_STRING_ITERATOR;
-    return _facets.keySet().iterator();
+    else
+      return _facets.keySet().iterator();
   }
 
   @Override
@@ -1659,6 +1698,7 @@
   private Map<String, UIComponent> _facets;
   private UIComponent              _parent;
   private String                   _id;
+  private String                   _clientId;
   private boolean                  _usesFacesBeanImpl;
   
   // Cached instance of the Renderer for this component.