You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by ma...@apache.org on 2009/01/21 00:18:44 UTC

svn commit: r736165 [1/2] - in /myfaces/trinidad/trunk_1.2.x: 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/apache/myfaces/tr...

Author: matzew
Date: Tue Jan 20 15:18:43 2009
New Revision: 736165

URL: http://svn.apache.org/viewvc?rev=736165&view=rev
Log:
TRINIDAD-1368 - Backport JSF 2.0 Component Tree Visiting and Optimize PPR Rendering

thanks to blake for the patch

Added:
    myfaces/trinidad/trunk_1.2.x/trinidad-api/src/main/java/org/apache/myfaces/trinidad/component/visit/
    myfaces/trinidad/trunk_1.2.x/trinidad-api/src/main/java/org/apache/myfaces/trinidad/component/visit/VisitCallback.java
    myfaces/trinidad/trunk_1.2.x/trinidad-api/src/main/java/org/apache/myfaces/trinidad/component/visit/VisitContext.java
    myfaces/trinidad/trunk_1.2.x/trinidad-api/src/main/java/org/apache/myfaces/trinidad/component/visit/VisitHint.java
    myfaces/trinidad/trunk_1.2.x/trinidad-api/src/main/java/org/apache/myfaces/trinidad/component/visit/VisitResult.java
    myfaces/trinidad/trunk_1.2.x/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/context/FullVisitContext.java
    myfaces/trinidad/trunk_1.2.x/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/context/PartialVisitContext.java
Modified:
    myfaces/trinidad/trunk_1.2.x/trinidad-api/src/main/java-templates/org/apache/myfaces/trinidad/component/UIXComponentRefTemplate.java
    myfaces/trinidad/trunk_1.2.x/trinidad-api/src/main/java-templates/org/apache/myfaces/trinidad/component/UIXDecorateCollectionTemplate.java
    myfaces/trinidad/trunk_1.2.x/trinidad-api/src/main/java-templates/org/apache/myfaces/trinidad/component/UIXMenuTemplate.java
    myfaces/trinidad/trunk_1.2.x/trinidad-api/src/main/java-templates/org/apache/myfaces/trinidad/component/UIXSubformTemplate.java
    myfaces/trinidad/trunk_1.2.x/trinidad-api/src/main/java/org/apache/myfaces/trinidad/component/UIXCollection.java
    myfaces/trinidad/trunk_1.2.x/trinidad-api/src/main/java/org/apache/myfaces/trinidad/component/UIXComponent.java
    myfaces/trinidad/trunk_1.2.x/trinidad-api/src/main/java/org/apache/myfaces/trinidad/component/UIXComponentBase.java
    myfaces/trinidad/trunk_1.2.x/trinidad-api/src/main/java/org/apache/myfaces/trinidad/context/PartialPageContext.java
    myfaces/trinidad/trunk_1.2.x/trinidad-api/src/main/java/org/apache/myfaces/trinidad/context/RequestContext.java
    myfaces/trinidad/trunk_1.2.x/trinidad-api/src/main/java/org/apache/myfaces/trinidad/render/CoreRenderer.java
    myfaces/trinidad/trunk_1.2.x/trinidad-api/src/main/java/org/apache/myfaces/trinidad/util/CollectionUtils.java
    myfaces/trinidad/trunk_1.2.x/trinidad-api/src/test/java/org/apache/myfaces/trinidad/context/MockRequestContext.java
    myfaces/trinidad/trunk_1.2.x/trinidad-examples/trinidad-demo/src/main/java/org/apache/myfaces/trinidaddemo/ComponentEditorHandler.java
    myfaces/trinidad/trunk_1.2.x/trinidad-examples/trinidad-demo/src/main/webapp/WEB-INF/web.xml
    myfaces/trinidad/trunk_1.2.x/trinidad-examples/trinidad-demo/src/main/webapp/components/editor.jspf
    myfaces/trinidad/trunk_1.2.x/trinidad-examples/trinidad-demo/src/main/webapp/components/showDetailItem.jspx
    myfaces/trinidad/trunk_1.2.x/trinidad-examples/trinidad-demo/src/main/webapp/demos/carDemo.jspx
    myfaces/trinidad/trunk_1.2.x/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/context/RequestContextImpl.java
    myfaces/trinidad/trunk_1.2.x/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/renderkit/core/CoreRenderingContext.java
    myfaces/trinidad/trunk_1.2.x/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/renderkit/core/ppr/PartialPageContextImpl.java
    myfaces/trinidad/trunk_1.2.x/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/renderkit/core/xhtml/FormRenderer.java
    myfaces/trinidad/trunk_1.2.x/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/renderkit/core/xhtml/PanelPartialRootRenderer.java
    myfaces/trinidad/trunk_1.2.x/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/renderkit/core/xhtml/PartialPageUtils.java
    myfaces/trinidad/trunk_1.2.x/trinidad-impl/src/test/java/org/apache/myfaces/trinidadinternal/renderkit/MRequestContext.java

Modified: myfaces/trinidad/trunk_1.2.x/trinidad-api/src/main/java-templates/org/apache/myfaces/trinidad/component/UIXComponentRefTemplate.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk_1.2.x/trinidad-api/src/main/java-templates/org/apache/myfaces/trinidad/component/UIXComponentRefTemplate.java?rev=736165&r1=736164&r2=736165&view=diff
==============================================================================
--- myfaces/trinidad/trunk_1.2.x/trinidad-api/src/main/java-templates/org/apache/myfaces/trinidad/component/UIXComponentRefTemplate.java (original)
+++ myfaces/trinidad/trunk_1.2.x/trinidad-api/src/main/java-templates/org/apache/myfaces/trinidad/component/UIXComponentRefTemplate.java Tue Jan 20 15:18:43 2009
@@ -51,27 +51,8 @@
                                    ContextCallback callback)
     throws FacesException
   {
-    String thisClientId = getClientId(context);
-
-    if (clientId.equals(thisClientId))
-    {
-      callback.invokeContextCallback(context, this);
-      return true;
-    }
-
-    // This component is a naming container. If the client id shows it's inside this naming container,
-    // then process further.
-    // Otherwise we know the client id we're looking for is not in this naming container,
-    // so for improved performance short circuit and return false.
-    else if (clientId.startsWith(thisClientId) &&
-             (clientId.charAt(thisClientId.length()) ==
-              NamingContainer.SEPARATOR_CHAR))
-    {
-
-      return super.invokeOnComponent(context, clientId, callback);
-    }
-
-    return false;
+    // optimize case where clientId isn't in NamingContainer
+    return invokeOnNamingContainerComponent(context, clientId, callback);
   }
 
   @Override

Modified: myfaces/trinidad/trunk_1.2.x/trinidad-api/src/main/java-templates/org/apache/myfaces/trinidad/component/UIXDecorateCollectionTemplate.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk_1.2.x/trinidad-api/src/main/java-templates/org/apache/myfaces/trinidad/component/UIXDecorateCollectionTemplate.java?rev=736165&r1=736164&r2=736165&view=diff
==============================================================================
--- myfaces/trinidad/trunk_1.2.x/trinidad-api/src/main/java-templates/org/apache/myfaces/trinidad/component/UIXDecorateCollectionTemplate.java (original)
+++ myfaces/trinidad/trunk_1.2.x/trinidad-api/src/main/java-templates/org/apache/myfaces/trinidad/component/UIXDecorateCollectionTemplate.java Tue Jan 20 15:18:43 2009
@@ -88,27 +88,8 @@
                                    ContextCallback callback)
     throws FacesException
   {
-    String thisClientId = getClientId(context);
-
-    if (clientId.equals(thisClientId))
-    {
-      callback.invokeContextCallback(context, this);
-      return true;
-    }
-
-    // This component is a naming container. If the client id shows it's inside this naming container,
-    // then process further.
-    // Otherwise we know the client id we're looking for is not in this naming container,
-    // so for improved performance short circuit and return false.
-    else if (clientId.startsWith(thisClientId) &&
-             (clientId.charAt(thisClientId.length()) ==
-              NamingContainer.SEPARATOR_CHAR))
-    {
-
-      return super.invokeOnComponent(context, clientId, callback);
-    }
-
-    return false;
+    // optimize case where clientId isn't in NamingContainer
+    return invokeOnNamingContainerComponent(context, clientId, callback);
   }
 
 

Modified: myfaces/trinidad/trunk_1.2.x/trinidad-api/src/main/java-templates/org/apache/myfaces/trinidad/component/UIXMenuTemplate.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk_1.2.x/trinidad-api/src/main/java-templates/org/apache/myfaces/trinidad/component/UIXMenuTemplate.java?rev=736165&r1=736164&r2=736165&view=diff
==============================================================================
--- myfaces/trinidad/trunk_1.2.x/trinidad-api/src/main/java-templates/org/apache/myfaces/trinidad/component/UIXMenuTemplate.java (original)
+++ myfaces/trinidad/trunk_1.2.x/trinidad-api/src/main/java-templates/org/apache/myfaces/trinidad/component/UIXMenuTemplate.java Tue Jan 20 15:18:43 2009
@@ -38,27 +38,7 @@
                                    ContextCallback callback)
     throws FacesException
   {
-    String thisClientId = getClientId(context);
-
-    if (clientId.equals(thisClientId))
-    {
-      callback.invokeContextCallback(context, this);
-      return true;
-    }
-
-    // This component is a naming container. If the client id shows it's inside this naming container,
-    // then process further.
-    // Otherwise we know the client id we're looking for is not in this naming container,
-    // so for improved performance short circuit and return false.
-    else if (clientId.startsWith(thisClientId) &&
-             (clientId.charAt(thisClientId.length()) ==
-              NamingContainer.SEPARATOR_CHAR))
-    {
-
-      return super.invokeOnComponent(context, clientId, callback);
-    }
-
-    return false;
+    // optimize case where clientId isn't in NamingContainer
+    return invokeOnNamingContainerComponent(context, clientId, callback);
   }
-
 }

Modified: myfaces/trinidad/trunk_1.2.x/trinidad-api/src/main/java-templates/org/apache/myfaces/trinidad/component/UIXSubformTemplate.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk_1.2.x/trinidad-api/src/main/java-templates/org/apache/myfaces/trinidad/component/UIXSubformTemplate.java?rev=736165&r1=736164&r2=736165&view=diff
==============================================================================
--- myfaces/trinidad/trunk_1.2.x/trinidad-api/src/main/java-templates/org/apache/myfaces/trinidad/component/UIXSubformTemplate.java (original)
+++ myfaces/trinidad/trunk_1.2.x/trinidad-api/src/main/java-templates/org/apache/myfaces/trinidad/component/UIXSubformTemplate.java Tue Jan 20 15:18:43 2009
@@ -86,27 +86,8 @@
                                    ContextCallback callback)
     throws FacesException
   {
-    String thisClientId = getClientId(context);
-
-    if (clientId.equals(thisClientId))
-    {
-      callback.invokeContextCallback(context, this);
-      return true;
-    }
-
-    // This component is a naming container. If the client id shows it's inside this naming container,
-    // then process further.
-    // Otherwise we know the client id we're looking for is not in this naming container,
-    // so for improved performance short circuit and return false.
-    else if (clientId.startsWith(thisClientId) &&
-             (clientId.charAt(thisClientId.length()) ==
-              NamingContainer.SEPARATOR_CHAR))
-    {
-
-      return super.invokeOnComponent(context, clientId, callback);
-    }
-
-    return false;
+    // optimize case where clientId isn't in NamingContainer
+    return invokeOnNamingContainerComponent(context, clientId, callback);
   }
 
   @SuppressWarnings("unchecked")

Modified: myfaces/trinidad/trunk_1.2.x/trinidad-api/src/main/java/org/apache/myfaces/trinidad/component/UIXCollection.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk_1.2.x/trinidad-api/src/main/java/org/apache/myfaces/trinidad/component/UIXCollection.java?rev=736165&r1=736164&r2=736165&view=diff
==============================================================================
--- myfaces/trinidad/trunk_1.2.x/trinidad-api/src/main/java/org/apache/myfaces/trinidad/component/UIXCollection.java (original)
+++ myfaces/trinidad/trunk_1.2.x/trinidad-api/src/main/java/org/apache/myfaces/trinidad/component/UIXCollection.java Tue Jan 20 15:18:43 2009
@@ -1030,32 +1030,45 @@
     if (clientId.startsWith(thisClientId) &&
         (clientId.charAt(thisClientIdLength) == NamingContainer.SEPARATOR_CHAR))
     {
-      if (!_getAndMarkFirstInvokeForRequest(context, thisClientId))
-      {
-        // Call _init() since _flushCachedModel() assumes that
-        // selectedRowKeys and disclosedRowKeys are initialized to be non-null
-        _init();
-
-        _flushCachedModel();
-      }
-
-      String postId = clientId.substring(thisClientIdLength + 1);
-      int sepIndex = postId.indexOf(NamingContainer.SEPARATOR_CHAR);
-      // If there's no separator character afterwards, then this
-      // isn't a row key
-      if (sepIndex < 0)
-        return super.invokeOnComponent(context, clientId, callback);
-      String currencyString = postId.substring(0, sepIndex);
-      Object oldRowKey = getRowKey();
+      setupVisitingContext(context);
+      
       try
       {
-        setCurrencyString(currencyString);
-        return super.invokeOnComponent(context, clientId, callback);
+        if (!_getAndMarkFirstInvokeForRequest(context, thisClientId))
+        {
+          // Call _init() since _flushCachedModel() assumes that
+          // selectedRowKeys and disclosedRowKeys are initialized to be non-null
+          _init();
+  
+          _flushCachedModel();
+        }
+  
+        String postId = clientId.substring(thisClientIdLength + 1);
+        int sepIndex = postId.indexOf(NamingContainer.SEPARATOR_CHAR);
+        // If there's no separator character afterwards, then this
+        // isn't a row key
+        if (sepIndex < 0)
+          return invokeOnChildrenComponents(context, clientId, callback);
+        else
+        {
+          String currencyString = postId.substring(0, sepIndex);
+          Object oldRowKey = getRowKey();
+          try
+          {
+            setCurrencyString(currencyString);
+            
+            return invokeOnChildrenComponents(context, clientId, callback);
+          }
+          finally
+          {
+            // And restore the currency
+            setRowKey(oldRowKey);
+          }
+        }
       }
       finally
       {
-        // And restore the currency
-        setRowKey(oldRowKey);
+        tearDownVisitingContext(context);
       }
     }
 

Modified: myfaces/trinidad/trunk_1.2.x/trinidad-api/src/main/java/org/apache/myfaces/trinidad/component/UIXComponent.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk_1.2.x/trinidad-api/src/main/java/org/apache/myfaces/trinidad/component/UIXComponent.java?rev=736165&r1=736164&r2=736165&view=diff
==============================================================================
--- myfaces/trinidad/trunk_1.2.x/trinidad-api/src/main/java/org/apache/myfaces/trinidad/component/UIXComponent.java (original)
+++ myfaces/trinidad/trunk_1.2.x/trinidad-api/src/main/java/org/apache/myfaces/trinidad/component/UIXComponent.java Tue Jan 20 15:18:43 2009
@@ -20,14 +20,29 @@
 
 import java.io.IOException;
 
+import java.util.Collection;
+import java.util.Iterator;
+
 import javax.faces.component.UIComponent;
 
 import javax.el.MethodExpression;
 
+import javax.faces.component.NamingContainer;
+import javax.faces.component.UINamingContainer;
 import javax.faces.context.FacesContext;
 
+import javax.faces.event.PhaseId;
+import javax.faces.render.Renderer;
+
 import org.apache.myfaces.trinidad.bean.FacesBean;
+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.context.PartialPageContext;
+import org.apache.myfaces.trinidad.context.RenderingContext;
 import org.apache.myfaces.trinidad.event.AttributeChangeListener;
+import org.apache.myfaces.trinidad.render.CoreRenderer;
 
 /**
  * Pure abstract base class for all UIX components.
@@ -194,6 +209,379 @@
   }
 
   /**
+  * <p>Perform a tree visit starting at
+  * this node in the tree.</p>
+  *
+  * <p>UIXComponent.visitTree() implementations do not invoke the
+  * {@code VisitCallback} directly, but instead call
+  * {@code VisitContext.invokeVisitCallback()} to invoke the
+  * callback.  This allows {@code VisitContext} implementations
+  * to provide optimized tree traversals, for example by only
+  * calling the {@code VisitCallback} for a subset of components.</p>
+  *
+  * @param visitContext the <code>VisitContext</code> for this visit
+  * @param callback the <code>VisitCallback</code> instance
+  * whose <code>visit</code> method will be called
+  * for each node visited.
+  * @return component implementations may return <code>true</code>
+  *   to indicate that the tree visit is complete (eg. all components
+  *   that need to be visited have been visited).  This results in
+  *   the tree visit being short-circuited such that no more components
+  *   are visited.
+  *
+  * @see VisitContext#invokeVisitCallback VisitContext.invokeVisitCallback()
+  */
+  public boolean visitTree(
+    VisitContext visitContext,
+    VisitCallback callback)
+  {
+    return visitTree(visitContext, this, callback);
+  }
+  
+  /**
+  * <p>Perform a tree visit starting at the specified node in the tree.</p>
+  *
+  * <p>UIXComponent.visitTree() implementations do not invoke the
+  * {@code VisitCallback} directly, but instead call
+  * {@code VisitContext.invokeVisitCallback()} to invoke the
+  * callback.  This allows {@code VisitContext} implementations
+  * to provide optimized tree traversals, for example by only
+  * calling the {@code VisitCallback} for a subset of components.</p>
+  *
+  * @param visitContext the <code>VisitContext</code> for this visit
+  * @param component the <code>UIComponent</code> to start the visit from
+  * @param callback the <code>VisitCallback</code> instance
+  * whose <code>visit</code> method will be called
+  * for each node visited.
+  * @return component implementations may return <code>true</code>
+  *   to indicate that the tree visit is complete (eg. all components
+  *   that need to be visited have been visited).  This results in
+  *   the tree visit being short-circuited such that no more components
+  *   are visited.
+  *
+  * @see VisitContext#invokeVisitCallback VisitContext.invokeVisitCallback()
+  */
+  public static boolean visitTree(
+    VisitContext visitContext,
+    UIComponent   component,
+    VisitCallback callback)
+  {
+    UIXComponent uixComponent;
+
+    // determine if we should even visit this component subtree
+    if (component instanceof UIXComponent)
+    {
+      uixComponent = (UIXComponent)component;
+      
+      // delegate to the UIXComponent
+      if (!uixComponent.isVisitable(visitContext))
+        return false;
+    }
+    else
+    {
+      // use generic isVisitable implemetation
+      if (!_isVisitable(visitContext, component))
+        return false;
+      
+      uixComponent = null;
+    }
+    
+    // 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;
+      
+      if (uixComponent != null)
+      {
+        // 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;
+        }
+        
+        // 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)
+        {
+          uixComponent.setUpEncodingContext(context, rc);
+        }
+        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)
+          {
+            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;
+          }
+        }
+      }
+      finally
+      {
+        // tear down the context we set up in order to visit our children
+        if (uixComponent != null)
+        {
+          if (PhaseId.RENDER_RESPONSE == phaseId)
+          {
+            uixComponent.tearDownEncodingContext(context, rc);
+          }
+          else
+          {
+            uixComponent.tearDownVisitingContext(context);
+          }
+        }
+      }
+    }
+    else
+    {
+      assert(result == VisitResult.REJECT);      
+    }
+
+    // if we got this far, we're not done
+    return false;
+  }
+
+  
+  
+  /**
+   * <p>Called by
+   * {@link UIXComponent#visitTree 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
+   * {@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
+   * component nor any of its descendents will be visited></p>
+   * <p>Custom {@code treeVisit()} implementations may call this method
+   * to determine whether the component is visitable before performing
+   * any visit-related processing.</p>
+   *
+   * @return true if this component should be visited, false otherwise.
+   */
+  protected boolean isVisitable(VisitContext visitContext)
+  {
+    return _isVisitable(visitContext, this);
+  }
+  
+  /**
+   * default implementation checking the <code>VisitHint.SKIP_TRANSIENT</code> and
+   * <code>VisitHint.SKIP_UNRENDERED</code> hints.
+   */
+  private static boolean _isVisitable(VisitContext visitContext, UIComponent component)
+  {
+    Collection<VisitHint> hints = visitContext.getHints();
+    
+    if (hints.contains(VisitHint.SKIP_TRANSIENT) && component.isTransient())
+      return false;
+    
+    if (hints.contains(VisitHint.SKIP_UNRENDERED) && !component.isRendered())
+      return false;
+    
+    return true;
+  }
+  
+  /**
+   * <p>
+   * Called when visiting the component during optimized partial page encoding so that the
+   * component can modify what is actually encoded.  For example tab controls often
+   * render the tabs for the ShowDetailItems in the tab bar before delegating to the
+   * disclosed ShowDetailItem to render the tab content.  As a result, the tab control
+   * needs to encode its tab bar if any of its ShowDetailItems are partial targets so that
+   * the tab labels, for example, are up-to-date.
+   * </p>
+   * <p>
+   * The default implementation delegates to the CoreRenderer if this component has one, otherwise
+   * it calls the VisitCallback and returns its result if this UIXComponent is a partial
+   * target of the current encoding.
+   * </p>
+   * @param visitContext VisitContext to pass to the VisitCallback
+   * @param partialContext PartialPageContext for the current partial encoding
+   * @param callback VisitCallback to call if this component is a partial target
+   * @return The VisitResult controlling continued iteration of the visit.
+   */
+  public VisitResult partialEncodeVisit(
+    VisitContext visitContext,
+    PartialPageContext partialContext,
+    VisitCallback callback)
+  {
+    FacesContext context  = visitContext.getFacesContext();
+    Renderer     renderer = getRenderer(context);
+    
+    if (renderer instanceof CoreRenderer)
+    {
+      // delegate to the CoreRenderer
+      return ((CoreRenderer)renderer).partialEncodeVisit(visitContext,
+                                                         partialContext,
+                                                         this,
+                                                         callback);
+    }
+    else
+    {
+      // check that this is a component instance that should be encoded
+      if (partialContext.isPossiblePartialTarget(getId()) &&
+          partialContext.isPartialTarget(getClientId(context)))
+      {
+        // visit the component instance
+        return callback.visit(visitContext, this);
+      }
+      else
+      {
+        // Not visiting this component, but allow visit to
+        // continue into this subtree in case we've got
+        // visit targets there.
+        return VisitResult.ACCEPT;
+      }
+    }
+  }
+
+  /**
+   * <p>Sets up the context necessary to visit or invoke the component for all phases.</p>
+   * <p>The default implementation does nothing.</p>
+   * <p>If a subclass overrides this method, it should override
+   * <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>
+   * @see #tearDownVisitingContext
+   * @see #setUpEncodingContext
+   * @see #tearDownEncodingContext
+   */
+  protected void setupVisitingContext(FacesContext context)
+  {
+    // do nothing
+  }
+  
+  /**
+   * <p>Tears down context created in order to visit or invoke the component
+   * for all phases.</p>
+   * <p>The default implementation does nothing.</p>
+   * <p>A subclass should only override this method if it overrode
+   * <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>
+   * @see #setupVisitingContext
+   * @see #setUpEncodingContext
+   * @see #tearDownEncodingContext
+   */
+  protected void tearDownVisitingContext(FacesContext context) 
+  {
+    // do nothing
+  }
+  
+  /**
+   * <p>Sets up the context necessary to encode the component.</p>
+   * <p>The default implementation delegates to
+   * <code>CoreRenderer.setupEncodingContext</code> and then calls
+   * <code>setupVisitingContext</code></p>
+   * <p>If a subclass overrides this method, it should override
+   * <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>
+   * @see #setupVisitingContext
+   * @see #tearDownVisitingContext
+   * @see #tearDownEncodingContext
+   * @see CoreRenderer#setupEncodingContext
+   */
+  protected void setUpEncodingContext(FacesContext context, RenderingContext rc)
+  {
+    setupVisitingContext(context);
+    
+    Renderer renderer = getRenderer(context);
+    
+    if (renderer instanceof CoreRenderer)
+    {
+      CoreRenderer coreRenderer = (CoreRenderer)renderer;
+      
+      coreRenderer.setupEncodingContext(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>
+   * <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
+   * @see #tearDownVisitingContext
+   * @see #setUpEncodingContext
+   * @see CoreRenderer#tearDownEncodingContext
+   */
+  protected void tearDownEncodingContext(
+    FacesContext context,
+    RenderingContext rc)
+  {
+    Renderer renderer = getRenderer(context);
+    
+    try
+    {
+      if (renderer instanceof CoreRenderer)
+      {
+        CoreRenderer coreRenderer = (CoreRenderer)renderer;
+      
+        coreRenderer.tearDownEncodingContext(context, rc, this);
+      } 
+    }
+    finally
+    {
+      tearDownVisitingContext(context);
+    }
+  }
+
+  /**
    * Returns the FacesBean used for storing the component's state.
    */
   abstract public FacesBean getFacesBean();

Modified: myfaces/trinidad/trunk_1.2.x/trinidad-api/src/main/java/org/apache/myfaces/trinidad/component/UIXComponentBase.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk_1.2.x/trinidad-api/src/main/java/org/apache/myfaces/trinidad/component/UIXComponentBase.java?rev=736165&r1=736164&r2=736165&view=diff
==============================================================================
--- myfaces/trinidad/trunk_1.2.x/trinidad-api/src/main/java/org/apache/myfaces/trinidad/component/UIXComponentBase.java (original)
+++ myfaces/trinidad/trunk_1.2.x/trinidad-api/src/main/java/org/apache/myfaces/trinidad/component/UIXComponentBase.java Tue Jan 20 15:18:43 2009
@@ -35,6 +35,8 @@
 import javax.el.MethodExpression;
 import javax.el.ValueExpression;
 
+import javax.faces.FacesException;
+import javax.faces.component.ContextCallback;
 import javax.faces.component.NamingContainer;
 import javax.faces.component.UIComponent;
 import javax.faces.context.FacesContext;
@@ -1290,6 +1292,130 @@
     }
   }
 
+  /**
+   * Convenience method to call <code>invokeOnComponent</code> on all of the
+   * children of a component.  This is useful when a component sometimes optimizes
+   * away calling <code>invokeOnComponent</code> on its children
+   */
+  protected final boolean invokeOnChildrenComponents(
+    FacesContext context,
+    String clientId,
+    ContextCallback callback)
+    throws FacesException
+  {
+    Iterator<UIComponent> children = getFacetsAndChildren();
+    
+    boolean found = false;
+    
+    while (children.hasNext() && !found)
+    {
+      found = children.next().invokeOnComponent(context, clientId, callback);
+    }
+    
+    return found;
+  }
+
+  /**
+   * <p>
+   * Optimized implementation of <code>invokeOnComponent</code> for NamingContainers.
+   * If the clientId isn't within the NamingContainer, invocation of the
+   * NamingContainer's children is skipped.
+   * </p>
+   * <p>Subclasses implementing NamingContainer should override
+   * <code>invokeOnComponent</code> and delegate to this method.</p>
+   */
+  protected final boolean invokeOnNamingContainerComponent(
+    FacesContext context,
+    String clientId,
+    ContextCallback callback)
+    throws FacesException
+  {
+    assert this instanceof NamingContainer : "Only use invokeOnNamingContainerComponent on NamingContainers";
+    
+    String thisClientId = getClientId(context);
+
+    if (clientId.equals(thisClientId))
+    {
+      // this is the component we want, so invoke the callback
+      callback.invokeContextCallback(context, this);
+      return true;
+    }
+    else
+    {
+      // if this is a NamingContainer, only traverse into it if the clientId we are looking for
+      // is inside of it
+      if ((!clientId.startsWith(thisClientId) ||
+          (clientId.charAt(thisClientId.length()) != NamingContainer.SEPARATOR_CHAR)))
+      {
+        return false;
+      }
+
+      boolean invokedComponent = false;
+      
+      // set up the context for visiting the children
+      setupVisitingContext(context);
+            
+      try
+      {
+        // iterate through children. We inline this code instead of calling super in order
+        // to avoid making an extra call to getClientId().
+        invokedComponent = invokeOnChildrenComponents(context, clientId, callback);
+      }
+      finally
+      {
+        // teardown the context now that we have visited the children
+        tearDownVisitingContext(context);
+      }
+      
+      return invokedComponent;
+    }
+  }
+  
+
+  /**
+   * Override to calls the hooks for setting up and tearing down the
+   * context before the children are visited.
+   * @see #setupVisitingContext
+   * @see #tearDownVisitingContext
+   */
+  @Override
+  public boolean invokeOnComponent(
+    FacesContext context,
+    String clientId,
+    ContextCallback callback)
+    throws FacesException
+  {    
+    String thisClientId = getClientId(context);
+
+    if (clientId.equals(thisClientId))
+    {
+      callback.invokeContextCallback(context, this);
+      return true;
+    }
+    else
+    {
+      boolean invokedComponent = false;
+      
+      // set up the context for visiting the children
+      setupVisitingContext(context);
+            
+      try
+      {
+        // iterate through children. We inline this code instead of calling super in order
+        // to avoid making an extra call to getClientId().
+        invokedComponent = invokeOnChildrenComponents(context, clientId, callback);
+      }
+      finally
+      {
+        // teardown the context now that we have visited the children
+        tearDownVisitingContext(context);
+      }
+      
+      return invokedComponent;
+    }
+  }
+
+
 
   /**
    * <p>

Added: myfaces/trinidad/trunk_1.2.x/trinidad-api/src/main/java/org/apache/myfaces/trinidad/component/visit/VisitCallback.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk_1.2.x/trinidad-api/src/main/java/org/apache/myfaces/trinidad/component/visit/VisitCallback.java?rev=736165&view=auto
==============================================================================
--- myfaces/trinidad/trunk_1.2.x/trinidad-api/src/main/java/org/apache/myfaces/trinidad/component/visit/VisitCallback.java (added)
+++ myfaces/trinidad/trunk_1.2.x/trinidad-api/src/main/java/org/apache/myfaces/trinidad/component/visit/VisitCallback.java Tue Jan 20 15:18:43 2009
@@ -0,0 +1,51 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.myfaces.trinidad.component.visit;
+
+import javax.faces.component.UIComponent;
+
+/**
+ *
+ * <p>A simple callback interface that enables 
+ * taking action on a specific UIComponent (either facet or child) during 
+ * a component tree visit.</p>
+ *
+ * @see org.apache.myfaces.trinidad.component.UIXComponent#visitTree UIComponent.visitTree()
+ */
+public interface VisitCallback
+{
+    /**
+     * <p>This method is called during component tree visits by 
+     * {@link VisitContext#invokeVisitCallback VisitContext.invokeVisitCallback()} 
+     * to visit the specified component.  At the point in time when this 
+     * method is called, the argument {@code target} is guaranteed
+     * to be in the proper state with respect to its ancestors in the
+     * View.</p>
+     *
+     * @param context the {@link VisitContext} for this tree visit.
+     *
+     * @param target the {@link UIComponent} to visit
+     *
+     * @return a {@link VisitResult} that indicates whether to continue
+     *   visiting the component's subtree, skip visiting the component's
+     *   subtree or end the visit.
+     */
+    public VisitResult visit(VisitContext context, UIComponent target);
+}

Added: myfaces/trinidad/trunk_1.2.x/trinidad-api/src/main/java/org/apache/myfaces/trinidad/component/visit/VisitContext.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk_1.2.x/trinidad-api/src/main/java/org/apache/myfaces/trinidad/component/visit/VisitContext.java?rev=736165&view=auto
==============================================================================
--- myfaces/trinidad/trunk_1.2.x/trinidad-api/src/main/java/org/apache/myfaces/trinidad/component/visit/VisitContext.java (added)
+++ myfaces/trinidad/trunk_1.2.x/trinidad-api/src/main/java/org/apache/myfaces/trinidad/component/visit/VisitContext.java Tue Jan 20 15:18:43 2009
@@ -0,0 +1,178 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.myfaces.trinidad.component.visit;
+
+import java.util.AbstractCollection;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.Set;
+
+import javax.faces.component.UIComponent;
+import javax.faces.context.FacesContext;
+import javax.faces.event.PhaseId;
+
+/**
+ *
+ * <p>A context object that is used to hold
+ * state relating to a component tree visit.</p>
+ *
+ * <p>Component tree visits are initiated by calling
+ * {@link org.apache.myfaces.trinidad.component.UIXComponent#visitTree UIComponent.visitTree()},
+ * at which point both a {@link VisitContext} and a {@link VisitCallback}
+ * must be provided.
+ *
+ * @see org.apache.myfaces.trinidad.component.UIXComponent#visitTree UIXComponent.visitTree()
+ * @see VisitCallback
+ *
+ */
+abstract public class VisitContext
+{
+  // Design notes: The VisitContext contract could be defined
+  // as an interface.  However, there is the potential that we
+  // may need to add new methods in the future, so leaving as 
+  // an abstract class in order to have room to grow.
+  // 
+  // Since we are an abstract class rather than an interface,
+  // we could provide implementations of of some of the simpler
+  // methods (eg. getFacesContext() and getHints()) to avoid 
+  // duplicating this code in VisitContext implementations.
+  // However, doing so would mean that "wrapping" VisitContext
+  // implementations would be forced to pick up such implementations,
+  // so going with a pure contract (no implementation).
+
+  /**
+   * <p>This unmodifiable Collection is returned by 
+   * VisitContext.getIdsToVisit() and getSubtreeIdsToVisit( in cases where all ids
+   * should be visited.</p>
+   * <p>To simplify logic for visitTree() implementations, this Collection
+   * always return {@code false} for {@code isEmpty}.  All other methods 
+   * throw {@code UnsupportedOperationException}.</p>
+   */
+  // Note: We cannot use Collections.emptyList() as that returns
+  // a shared instance - we want to unique instance to allow for
+  // identity tests.
+  static public final Collection<String> ALL_IDS = 
+    new AbstractCollection<String>()
+    {
+      @Override
+      public Iterator<String> iterator()
+      {
+        throw new UnsupportedOperationException(
+            "VisitContext.ALL_IDS does not support this operation");
+      }
+
+      @Override
+      public int size()
+      {
+        throw new UnsupportedOperationException(
+                    "VisitContext.ALL_IDS does not support this operation");
+      }
+
+      @Override
+      public boolean isEmpty()
+      {
+        return false;
+      }
+    };
+
+  /**
+   * <p>Returns the FacesContext for the current request.</p>
+   */
+  abstract public FacesContext getFacesContext();
+  
+  /**
+   * <p>Returns the PhaseId, if any that, that this visit is ocurring under
+   * @return the current PhaseId
+   */
+  public abstract PhaseId getPhaseId();
+
+  /**
+   * <p>
+   * Returns the ids of the components to visit.
+   * </p>
+   * <p>
+   * In the case of a full tree visit, this method returns the
+   * ALL_IDS collection.  Otherwise, if a partial visit is being
+   * performed, returns a modifiable collection containing the
+   * client ids of the components that should be visited.
+   * </p>
+   * @return {@code VisitContext.ALL_IDS}, or a modifiable 
+   * Collection of client ids.
+   */
+  abstract public Collection<String> getIdsToVisit();
+
+  /**
+   * <p>
+   * Given a NamingContainer component, returns the client ids of 
+   * any components underneath the NamingContainer that should be
+   * visited.
+   * </p>
+   * <p>
+   * This method is called by NamingContainer visitTree() implementations 
+   * to determine whether the NamingContainer contains components to be 
+   * visited.  In the case where no such components exist, the 
+   * NamingContainer can short-circuit the tree visit and avoid 
+   * descending into child subtrees.
+   * </p>
+   * <p>
+   * In addition, iterating components such as UIData may be able to
+   * use the returned ids to determine which iterated states (ie. rows)
+   * need to be visited.  This allows the visit traversal to be
+   * contstrained such only those rows that contain visit targets
+   * need to be traversed.
+   * </p>
+   * @param component a NamingContainer component
+   * @return an unmodifiable Collection containing the client ids of 
+   *   any components underneath the NamingContainer that are known to be
+   *   targets of the tree visit.  If no such components exist, returns 
+   *   an empty Collection.  If all components underneath the 
+   *   NamingContainer should be visited, returns the
+   *   {@code VisitContext.ALL_IDS} collection.
+   * @throws IllegalArgumentException if {@code component} is not
+   *  an instance of NamingContainer
+   */
+  abstract public Collection<String> getSubtreeIdsToVisit(UIComponent component);
+
+  /**
+   * <p>Called by {@link org.apache.myfaces.trinidad.component.UIXComponent#visitTree UIXComponent.visitTree()}
+   * to visit a single component.</p>
+   *
+   * @param component the component to visit
+   * @param callback the VisitCallback to call
+   * @return a VisitResult value that indicates whether to continue
+   *   visiting the component's subtree, skip visiting the component's
+   *   subtree or abort the visit altogether.
+   */
+  abstract public VisitResult invokeVisitCallback(UIComponent component, 
+                                                  VisitCallback callback); 
+
+  /**
+   * <p>Returns hints that influence the behavior of the tree visit.</p>
+   *
+   * <p>Interested parties, such as 
+   * {@link org.apache.myfaces.trinidad.component.UIXComponent#visitTree UIComponent.visitTree()} implementations,
+   * may check to see whether a particular hint is present by calling
+   * {@code VisitContext.getHints().contains()}, passing in one of the
+   * hints defined by {@link VisitHint}.
+   *   
+   * @return a non-empty, unmodifiable collection of VisitHints
+   */
+  abstract public Set<VisitHint> getHints();
+}

Added: myfaces/trinidad/trunk_1.2.x/trinidad-api/src/main/java/org/apache/myfaces/trinidad/component/visit/VisitHint.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk_1.2.x/trinidad-api/src/main/java/org/apache/myfaces/trinidad/component/visit/VisitHint.java?rev=736165&view=auto
==============================================================================
--- myfaces/trinidad/trunk_1.2.x/trinidad-api/src/main/java/org/apache/myfaces/trinidad/component/visit/VisitHint.java (added)
+++ myfaces/trinidad/trunk_1.2.x/trinidad-api/src/main/java/org/apache/myfaces/trinidad/component/visit/VisitHint.java Tue Jan 20 15:18:43 2009
@@ -0,0 +1,48 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+
+package org.apache.myfaces.trinidad.component.visit;
+
+/**
+ *
+ * <p>An enum that specifies hints that impact
+ * the behavior of a component tree visit.</p>
+ *
+ * @see VisitContext#getHints VisitContext.getHints()
+ */
+public enum VisitHint
+{
+  /** 
+   * Hint that indicates that only the rendered subtree should be visited.
+   */
+  SKIP_UNRENDERED,
+
+  /** 
+   * Hint that indicates that only non-transient subtrees should be visited.
+   */
+  SKIP_TRANSIENT,
+  
+  /**
+   * Hint that indicates that the visit is being performed as part of
+   * lifecycle phase execution and as such phase-specific actions
+   * (initialization) may be taken.
+   */
+  EXECUTE_LIFECYCLE
+}

Added: myfaces/trinidad/trunk_1.2.x/trinidad-api/src/main/java/org/apache/myfaces/trinidad/component/visit/VisitResult.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk_1.2.x/trinidad-api/src/main/java/org/apache/myfaces/trinidad/component/visit/VisitResult.java?rev=736165&view=auto
==============================================================================
--- myfaces/trinidad/trunk_1.2.x/trinidad-api/src/main/java/org/apache/myfaces/trinidad/component/visit/VisitResult.java (added)
+++ myfaces/trinidad/trunk_1.2.x/trinidad-api/src/main/java/org/apache/myfaces/trinidad/component/visit/VisitResult.java Tue Jan 20 15:18:43 2009
@@ -0,0 +1,48 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.myfaces.trinidad.component.visit;
+
+/**
+ *
+ * <p>An enum that specifies the possible 
+ * results of a call to {@link VisitCallback#visit VisitCallback.visit()}.
+ * </p>
+ *
+ * @see VisitCallback#visit VisitCallback.visit()
+ */
+public enum VisitResult
+{
+  /**
+   * This result indicates that the tree visit should descend into
+   * current component's subtree.
+   */ 
+  ACCEPT,
+
+  /**
+   * This result indicates that the tree visit should continue, but
+   * should skip the current component's subtree.
+   */ 
+  REJECT,
+
+  /**
+   * This result indicates that the tree visit should be terminated.
+   */ 
+  COMPLETE
+}

Modified: myfaces/trinidad/trunk_1.2.x/trinidad-api/src/main/java/org/apache/myfaces/trinidad/context/PartialPageContext.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk_1.2.x/trinidad-api/src/main/java/org/apache/myfaces/trinidad/context/PartialPageContext.java?rev=736165&r1=736164&r2=736165&view=diff
==============================================================================
--- myfaces/trinidad/trunk_1.2.x/trinidad-api/src/main/java/org/apache/myfaces/trinidad/context/PartialPageContext.java (original)
+++ myfaces/trinidad/trunk_1.2.x/trinidad-api/src/main/java/org/apache/myfaces/trinidad/context/PartialPageContext.java Tue Jan 20 15:18:43 2009
@@ -20,6 +20,8 @@
 
 import java.util.Iterator;
 
+import org.apache.myfaces.trinidad.component.visit.VisitContext;
+
 
 /**
  * Context object which is used to track the targets of a partial
@@ -43,10 +45,33 @@
   }
 
   /**
-   * Tests whether the specified id is the client id of a UIComponent that
+   * Tests whether the specified client id is the client id of a UIComponent that
    * should be rendered as part of the partial rendering pass.
+   * @return <code>true</code> if a compoennt with this client id should be rendered.
+   * @see #isPossiblePartialTarget
    */
-  abstract public boolean isPartialTarget(String id);
+  abstract public boolean isPartialTarget(String clientId);
+
+  /**
+   * <p>
+   * Tests whether the specified component id is a component id of a UIComponent that
+   * might be rendered in this partial rendering pass.
+   * </p>
+   * <p>
+   * As calculating clientIds is expensive, this method allows a cheap test to reject components
+   * that shouldn't be rendered. If this method returns true, a more
+   * exact test using <code>isPartialTarget</code> with the desired clientId should be performed.
+   * </p>
+   * @return <code>true</code> if a component with this id should be rendered.
+   * @see #isPartialTarget
+   */
+  abstract public boolean isPossiblePartialTarget(String componentId);
+
+  /**
+   * Returns <code>true</code> if all of the partial targets have been rendered.
+   * @return <code>true</code> if all of the partial targets have been rendered.
+   */
+  public abstract boolean areAllTargetsProcessed();
 
   /**
    * Returns the set of partial targets for this rendering pass.
@@ -80,5 +105,15 @@
    */
   abstract public void addRenderedPartialTarget(String id);
 
+  /**
+   * Returns the client ids of the partial targets that have been rendered so far.
+   * @return the client ids of the partial targets that have been rendered so far.
+   */
   abstract public Iterator<String> getRenderedPartialTargets();
+  
+  /**
+   * Returns the VisitContext to use when partial rendering.
+   * @return the VisitContext to use when partial rendering.
+   */
+  abstract public VisitContext getVisitContext();
 }

Modified: myfaces/trinidad/trunk_1.2.x/trinidad-api/src/main/java/org/apache/myfaces/trinidad/context/RequestContext.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk_1.2.x/trinidad-api/src/main/java/org/apache/myfaces/trinidad/context/RequestContext.java?rev=736165&r1=736164&r2=736165&view=diff
==============================================================================
--- myfaces/trinidad/trunk_1.2.x/trinidad-api/src/main/java/org/apache/myfaces/trinidad/context/RequestContext.java (original)
+++ myfaces/trinidad/trunk_1.2.x/trinidad-api/src/main/java/org/apache/myfaces/trinidad/context/RequestContext.java Tue Jan 20 15:18:43 2009
@@ -19,6 +19,8 @@
 package org.apache.myfaces.trinidad.context;
 
 import java.awt.Color;
+
+import java.util.Collection;
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
@@ -32,10 +34,13 @@
 import javax.faces.component.UIViewRoot;
 import javax.faces.context.FacesContext;
 
+import javax.faces.event.PhaseId;
+
 import org.apache.myfaces.trinidad.change.ChangeManager;
+import org.apache.myfaces.trinidad.component.visit.VisitContext;
+import org.apache.myfaces.trinidad.component.visit.VisitHint;
 import org.apache.myfaces.trinidad.config.RegionManager;
 import org.apache.myfaces.trinidad.logging.TrinidadLogger;
-import org.apache.myfaces.trinidad.util.ComponentUtils;
 import org.apache.myfaces.trinidad.webapp.UploadedFileProcessor;
 
 /**
@@ -475,6 +480,25 @@
   // Miscellaneous functionality
   //
 
+  /**
+   * <p>Creates a VisitContext instance for use with 
+   * {@link org.apache.myfaces.trinidad.component.UIXComponent#visitTree UIComponent.visitTree()}.</p>
+   *
+   * @param context the FacesContext for the current request
+   * @param ids the client ids of the components to visit.  If null,
+   *   all components will be visited.
+   * @param hints the VisitHints to apply to the visit
+   * @param phaseId.  PhaseId if any for this visit.  If PhaseId is specified,
+   * hints must contain VisitHint.EXECUTE_LIFECYCLE
+   * @return a VisitContext instance that is initialized with the 
+   *   specified ids and hints.
+   */
+  public abstract VisitContext createVisitContext(
+    FacesContext context,
+    Collection<String> ids,
+    Set<VisitHint> hints,
+    PhaseId phaseId);
+
   public abstract UploadedFileProcessor getUploadedFileProcessor();
 
   /**

Modified: myfaces/trinidad/trunk_1.2.x/trinidad-api/src/main/java/org/apache/myfaces/trinidad/render/CoreRenderer.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk_1.2.x/trinidad-api/src/main/java/org/apache/myfaces/trinidad/render/CoreRenderer.java?rev=736165&r1=736164&r2=736165&view=diff
==============================================================================
--- myfaces/trinidad/trunk_1.2.x/trinidad-api/src/main/java/org/apache/myfaces/trinidad/render/CoreRenderer.java (original)
+++ myfaces/trinidad/trunk_1.2.x/trinidad-api/src/main/java/org/apache/myfaces/trinidad/render/CoreRenderer.java Tue Jan 20 15:18:43 2009
@@ -30,7 +30,11 @@
 
 import org.apache.myfaces.trinidad.bean.FacesBean;
 import org.apache.myfaces.trinidad.component.UIXComponent;
+import org.apache.myfaces.trinidad.component.visit.VisitCallback;
+import org.apache.myfaces.trinidad.component.visit.VisitContext;
+import org.apache.myfaces.trinidad.component.visit.VisitResult;
 import org.apache.myfaces.trinidad.context.Agent;
+import org.apache.myfaces.trinidad.context.PartialPageContext;
 import org.apache.myfaces.trinidad.context.RequestContext;
 
 import org.apache.myfaces.trinidad.context.RenderingContext;
@@ -50,7 +54,89 @@
   {
   }
 
+  /**
+   * <p>
+   * Called when visiting the CoreRenderer's component during optimized partial page encoding so
+   * that the CoreRenderer can modify what is actually encoded.  For example tab controls often
+   * render the tabs for the ShowDetailItems in the tab bar before delegating to the
+   * disclosed ShowDetailItem to render the tab content.  As a result, the tab control
+   * needs to encode its tab bar if any of its ShowDetailItems are partial targets so that
+   * the tab labels, for example, are up-to-date.
+   * </p>
+   * <p>
+   * The default implementation calls the VisitCallback and returns its result if this UIXComponent
+   * is a partial target of the current encoding.
+   * </p>
+   * @param visitContext VisitContext to pass to the VisitCallback
+   * @param partialContext PartialPageContext for the current partial encoding
+   * @param component The component for the CoreRenderer to visit
+   * @param callback VisitCallback to call if this component is a partial target
+   * @return The VisitResult controlling continued iteration of the visit.
+   */
+  public VisitResult partialEncodeVisit(
+    VisitContext visitContext,
+    PartialPageContext partialContext,
+    UIComponent component,
+    VisitCallback callback)
+  {
+    if (partialContext.isPossiblePartialTarget(component.getId()) &&
+        partialContext.isPartialTarget(component.getClientId(visitContext.getFacesContext())))
+    {
+      // visit the component instance
+      return callback.visit(visitContext, component);      
+    }
+    else      
+    {
+      // Not visiting this component, but allow visit to
+      // continue into this subtree in case we've got
+      // visit targets there.
+      return VisitResult.ACCEPT;
+    }
+  }
 
+  /**
+   * <p>
+   * Called before rendering the current component's children in order to set
+   * up any special context.
+   * </p>
+   * <p>If <code>setupEncodingContext</code> succeeds then
+   * <code>tearDownEncodingContext</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 #tearDownEncodingContext
+   */
+  public void setupEncodingContext(
+    FacesContext context,
+    RenderingContext rc,
+    UIXComponent component)
+  {
+  }
+
+  /**
+   * <p>
+   * Called after rendering the current component's children in order to tear
+   * down any special context.
+   * </p>
+   * <p>
+   * <code>tearDownEncodingContext</code> will be called on the component if
+   * <code>setupEncodingContext</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 #setupEncodingContext
+   */
+  public void tearDownEncodingContext(
+    FacesContext context,
+    RenderingContext rc,
+    UIXComponent     component)
+  {
+  }
+  
   //
   // COERCION HELPERS
   //
@@ -186,7 +272,7 @@
   @Override
   public final void encodeBegin(FacesContext context,
                           UIComponent component) throws IOException
-  {
+  {    
     if (!getRendersChildren())
     {
       RenderingContext arc = RenderingContext.getCurrentInstance();
@@ -596,7 +682,9 @@
     RenderingContext arc,
     UIComponent      component,
     FacesBean        bean)
-  {}
+  {
+    setupEncodingContext(context, arc, (UIXComponent)component);
+  }
   
   /**
    * Hook method that gets invoked after the component is encoded
@@ -609,7 +697,9 @@
     RenderingContext arc,
     UIComponent      component,
     FacesBean        bean)
-  {}
+  {
+    tearDownEncodingContext(context, arc, (UIXComponent)component);
+  }
 
   //
   // Rendering convenience methods.

Modified: myfaces/trinidad/trunk_1.2.x/trinidad-api/src/main/java/org/apache/myfaces/trinidad/util/CollectionUtils.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk_1.2.x/trinidad-api/src/main/java/org/apache/myfaces/trinidad/util/CollectionUtils.java?rev=736165&r1=736164&r2=736165&view=diff
==============================================================================
--- myfaces/trinidad/trunk_1.2.x/trinidad-api/src/main/java/org/apache/myfaces/trinidad/util/CollectionUtils.java (original)
+++ myfaces/trinidad/trunk_1.2.x/trinidad-api/src/main/java/org/apache/myfaces/trinidad/util/CollectionUtils.java Tue Jan 20 15:18:43 2009
@@ -25,6 +25,7 @@
 import java.io.Serializable;
 import java.lang.reflect.Array;
 
+import java.util.AbstractQueue;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
@@ -34,7 +35,8 @@
 import java.util.List;
 import java.util.ListIterator;
 import java.util.Map;
-import java.util.Map.Entry;
+import java.util.NoSuchElementException;
+import java.util.Queue;
 import java.util.RandomAccess;
 import java.util.Set;
 
@@ -49,6 +51,49 @@
   {
     // no-op
   }
+  
+  /**
+   * Returns an ArrayList containing all of the elements of the
+   * Iterator
+   * @param iterator Iterator to copy the contexts of
+   * @return an ArrayList containing a copy of the iterator contents
+   */
+  public static <T> ArrayList<T> arrayList(Iterator<T> iterator)
+  {
+    ArrayList<T> arrayList = new ArrayList<T>();
+    
+    while (iterator.hasNext())
+      arrayList.add(iterator.next());
+    
+    return arrayList;
+  }
+
+  /**
+   * Returns an empty, unmodifiable, Serializable Queue.
+   * @return an empty, unmodifiable, Serializable Queue.
+   */
+  public static <T> Queue<T> emptyQueue()
+  {
+    return (Queue<T>)_EMPTY_QUEUE;
+  }
+
+  /**
+   * Returns an empty, unmodifiable, Iterator.
+   * @return an empty, unmodifiable, Iterator.
+   */
+  public static <T> Iterator<T> emptyIterator()
+  {
+    return (Iterator<T>)_EMPTY_ITERATOR;
+  }
+
+  /**
+   * Returns an empty, unmodifiable, ListIterator.
+   * @return an empty, unmodifiable, ListIterator.
+   */
+  public static <T> ListIterator<T> emptyListIterator()
+  {
+    return (ListIterator<T>)_EMPTY_LIST_ITERATOR;
+  }
 
   /**
    * Returns a Collection based on the passed in Collection <code>c</code>,
@@ -725,6 +770,104 @@
     private final Map<K, V> _delegate;
   }
 
+  private static class EmptyIterator implements Iterator
+  {
+    public boolean hasNext()
+    {
+      return false;
+    }
+
+    public Object next()
+    {
+      throw new NoSuchElementException();
+    }
+
+    public void remove()
+    {
+      throw new UnsupportedOperationException();
+    }
+  }
+  
+  private static final class EmptyListIterator extends EmptyIterator implements ListIterator
+  {
+    public boolean hasPrevious()
+    {
+      return false;
+    }
+
+    public Object previous()
+    {
+      throw new NoSuchElementException();
+    }
+
+    public int nextIndex()
+    {
+      return 0;
+    }
+
+    public int previousIndex()
+    {
+      return -1;
+    }
+
+    public void set(Object e)
+    {
+      throw new UnsupportedOperationException();
+    }
+
+    public void add(Object e)
+    {
+      throw new UnsupportedOperationException();
+    }
+  }
+
+  private static final class EmptyQueue extends AbstractQueue implements Serializable
+  {
+    public Iterator iterator()
+    {
+      return _EMPTY_ITERATOR;
+    }
+
+    public int size()
+    {
+      return 0;
+    }
+
+    @Override
+    public boolean isEmpty()
+    {
+      return true;
+    }
+    
+    @Override
+    public boolean contains(Object o)
+    {
+      return false;
+    }
+
+    public boolean offer(Object e)
+    {
+      throw new UnsupportedOperationException();
+    }
+
+    public Object poll()
+    {
+      return null;
+    }
+
+    public Object peek()
+    {
+      return null;
+    }
+    
+    private Object readResolve()
+    {
+      return _EMPTY_QUEUE;
+    }
+
+    private static final long serialVersionUID = 0L;
+  }
+
   //
   // Build up references to implementation classes used by Collections to implement the following
   // features.  This way we can detect when these classes are used and work around problems.
@@ -732,6 +875,10 @@
   private static final Class<? extends List> _CHECKED_LIST;
   private static final Class<? extends List> _UNMODIFIABLE_LIST;
   private static final Class<? extends List> _SYNCHRONIZED_LIST;
+  private static final Queue _EMPTY_QUEUE = new EmptyQueue();
+  private static final Iterator _EMPTY_ITERATOR = new EmptyIterator();
+  private static final Iterator _EMPTY_LIST_ITERATOR = new EmptyListIterator();
+   
   
   static
   {

Modified: myfaces/trinidad/trunk_1.2.x/trinidad-api/src/test/java/org/apache/myfaces/trinidad/context/MockRequestContext.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk_1.2.x/trinidad-api/src/test/java/org/apache/myfaces/trinidad/context/MockRequestContext.java?rev=736165&r1=736164&r2=736165&view=diff
==============================================================================
--- myfaces/trinidad/trunk_1.2.x/trinidad-api/src/test/java/org/apache/myfaces/trinidad/context/MockRequestContext.java (original)
+++ myfaces/trinidad/trunk_1.2.x/trinidad-api/src/test/java/org/apache/myfaces/trinidad/context/MockRequestContext.java Tue Jan 20 15:18:43 2009
@@ -19,6 +19,8 @@
 package org.apache.myfaces.trinidad.context;
 
 import java.awt.Color;
+
+import java.util.Collection;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Locale;
@@ -30,7 +32,11 @@
 import javax.faces.component.UIViewRoot;
 import javax.faces.context.FacesContext;
 
+import javax.faces.event.PhaseId;
+
 import org.apache.myfaces.trinidad.change.ChangeManager;
+import org.apache.myfaces.trinidad.component.visit.VisitContext;
+import org.apache.myfaces.trinidad.component.visit.VisitHint;
 import org.apache.myfaces.trinidad.config.RegionManager;
 import org.apache.myfaces.trinidad.webapp.UploadedFileProcessor;
 
@@ -348,6 +354,16 @@
     throw new UnsupportedOperationException("Not implemented yet");
   }
 
+  @Override
+  public VisitContext createVisitContext(
+   FacesContext context,
+   Collection<String> ids,
+   Set<VisitHint> hints,
+   PhaseId phaseId)
+  {
+    throw new UnsupportedOperationException("Not implemented yet");
+  }
+
 
   static private final TimeZone _FIXED_TIME_ZONE =
     TimeZone.getTimeZone("America/Los_Angeles");

Modified: myfaces/trinidad/trunk_1.2.x/trinidad-examples/trinidad-demo/src/main/java/org/apache/myfaces/trinidaddemo/ComponentEditorHandler.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk_1.2.x/trinidad-examples/trinidad-demo/src/main/java/org/apache/myfaces/trinidaddemo/ComponentEditorHandler.java?rev=736165&r1=736164&r2=736165&view=diff
==============================================================================
--- myfaces/trinidad/trunk_1.2.x/trinidad-examples/trinidad-demo/src/main/java/org/apache/myfaces/trinidaddemo/ComponentEditorHandler.java (original)
+++ myfaces/trinidad/trunk_1.2.x/trinidad-examples/trinidad-demo/src/main/java/org/apache/myfaces/trinidaddemo/ComponentEditorHandler.java Tue Jan 20 15:18:43 2009
@@ -31,10 +31,14 @@
 
 import javax.faces.component.UIComponent;
 
+import org.apache.myfaces.trinidad.context.RequestContext;
+
 public class ComponentEditorHandler
 {
   public String update()
   {
+    boolean rendered = _editedComponent.isRendered();
+
     List<PropertyOfComponent> list = _list;
     if (list != null)
     {
@@ -44,6 +48,14 @@
       }
     }
 
+    RequestContext rc = RequestContext.getCurrentInstance();
+    
+    // If we toggled rendered, we'd better toggle the parent
+    if (rendered != _editedComponent.isRendered())
+      rc.addPartialTarget(_editedComponent.getParent());
+    else
+      rc.addPartialTarget(_editedComponent);
+
     return null;
   }
 

Modified: myfaces/trinidad/trunk_1.2.x/trinidad-examples/trinidad-demo/src/main/webapp/WEB-INF/web.xml
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk_1.2.x/trinidad-examples/trinidad-demo/src/main/webapp/WEB-INF/web.xml?rev=736165&r1=736164&r2=736165&view=diff
==============================================================================
--- myfaces/trinidad/trunk_1.2.x/trinidad-examples/trinidad-demo/src/main/webapp/WEB-INF/web.xml (original)
+++ myfaces/trinidad/trunk_1.2.x/trinidad-examples/trinidad-demo/src/main/webapp/WEB-INF/web.xml Tue Jan 20 15:18:43 2009
@@ -42,6 +42,12 @@
     <param-value>false</param-value>
   </context-param>
 
+  <!-- Temporary internal flag to set to enabled and test Optimized PPR -->
+  <context-param>
+    <param-name>org.apache.myfaces.trinidadinternal.ENABLE_PPR_OPTIMIZATION</param-name>
+    <param-value>false</param-value>
+  </context-param>
+
   <!-- Parameter to set the maximum number of client view state tokens.
        Uncomment this to test low-token-count scenarios.
   <context-param>

Modified: myfaces/trinidad/trunk_1.2.x/trinidad-examples/trinidad-demo/src/main/webapp/components/editor.jspf
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk_1.2.x/trinidad-examples/trinidad-demo/src/main/webapp/components/editor.jspf?rev=736165&r1=736164&r2=736165&view=diff
==============================================================================
--- myfaces/trinidad/trunk_1.2.x/trinidad-examples/trinidad-demo/src/main/webapp/components/editor.jspf (original)
+++ myfaces/trinidad/trunk_1.2.x/trinidad-examples/trinidad-demo/src/main/webapp/components/editor.jspf Tue Jan 20 15:18:43 2009
@@ -47,6 +47,6 @@
           </tr:column>
           <f:facet name="footer">
             <tr:commandButton  text="Update"
-                              action="#{editor.update}"/>
+                              action="#{editor.update}" partialSubmit="true"/>
           </f:facet>
         </tr:table>

Modified: myfaces/trinidad/trunk_1.2.x/trinidad-examples/trinidad-demo/src/main/webapp/components/showDetailItem.jspx
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk_1.2.x/trinidad-examples/trinidad-demo/src/main/webapp/components/showDetailItem.jspx?rev=736165&r1=736164&r2=736165&view=diff
==============================================================================
--- myfaces/trinidad/trunk_1.2.x/trinidad-examples/trinidad-demo/src/main/webapp/components/showDetailItem.jspx (original)
+++ myfaces/trinidad/trunk_1.2.x/trinidad-examples/trinidad-demo/src/main/webapp/components/showDetailItem.jspx Tue Jan 20 15:18:43 2009
@@ -47,7 +47,7 @@
             </tr:inputText>
           </tr:panelFormLayout>
           <tr:panelTabbed>
-            <tr:showDetailItem binding="#{editor.component}" text="Tab 1">
+            <tr:showDetailItem id="editedComponent" binding="#{editor.component}" text="Tab 1">
               <tr:panelHeader text="Header 1">
                 <tr:panelFormLayout>
                   <tr:inputText readOnly="true" label="Label 1-1" value="Value"

Modified: myfaces/trinidad/trunk_1.2.x/trinidad-examples/trinidad-demo/src/main/webapp/demos/carDemo.jspx
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk_1.2.x/trinidad-examples/trinidad-demo/src/main/webapp/demos/carDemo.jspx?rev=736165&r1=736164&r2=736165&view=diff
==============================================================================
--- myfaces/trinidad/trunk_1.2.x/trinidad-examples/trinidad-demo/src/main/webapp/demos/carDemo.jspx (original)
+++ myfaces/trinidad/trunk_1.2.x/trinidad-examples/trinidad-demo/src/main/webapp/demos/carDemo.jspx Tue Jan 20 15:18:43 2009
@@ -66,14 +66,14 @@
           <!-- A link to show the options;  it starts out disabled -->
           <tr:commandLink id="launchOptions" disabled="true"
                          shortDesc="Click to pick new options"
-                         partialTriggers="modelsChoice makeChoice"
+                         partialTriggers="modelsChoice makesChoice"
                          returnListener="#{carBacking.returnOptions}"
                          binding="#{carBacking.launchOptions}"
                          useWindow="true"
                          action="dialog:optionsDialog" text="Pick options: "/>
           <tr:outputText id="options"
                          binding="#{carBacking.options}"
-                         partialTriggers="launchOptions modelsChoice makeChoice"/>
+                         partialTriggers="launchOptions modelsChoice makesChoice"/>
          </tr:panelGroupLayout>
 
         </tr:panelPage>

Added: myfaces/trinidad/trunk_1.2.x/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/context/FullVisitContext.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk_1.2.x/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/context/FullVisitContext.java?rev=736165&view=auto
==============================================================================
--- myfaces/trinidad/trunk_1.2.x/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/context/FullVisitContext.java (added)
+++ myfaces/trinidad/trunk_1.2.x/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/context/FullVisitContext.java Tue Jan 20 15:18:43 2009
@@ -0,0 +1,163 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.myfaces.trinidadinternal.context;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.Set;
+
+import javax.faces.component.NamingContainer;
+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;
+import org.apache.myfaces.trinidad.component.visit.VisitHint;
+import org.apache.myfaces.trinidad.component.visit.VisitResult;
+
+/**
+ *
+ * <p>A VisitContext implementation that is
+ * used when performing a full component tree visit.</p>
+ */
+class FullVisitContext extends VisitContext
+{
+
+  /**
+   * Creates a FullVisitorContext instance.
+   * @param facesContext the FacesContext for the current request
+   * @throws NullPointerException  if {@code facesContext}
+   *                               is {@code null}
+   */    
+  public FullVisitContext(FacesContext facesContext)
+  {
+    this(facesContext, null, null);
+  }
+
+  /**
+   * Creates a FullVisitorContext instance with the specified
+   * hints.
+   *
+   * @param facesContext the FacesContext for the current request
+   * @param hints a the VisitHints for this visit
+   * @param phaseId PhaseId, if any that visit is ocurring under
+   * @throws NullPointerException  if {@code facesContext}
+   *                               is {@code null}
+   * @throws IllegalArgumentException if the phaseId is specified and
+   * hints does not contain VisitHint.EXECUTE_LIFECYCLE
+   */    
+  public FullVisitContext(
+    FacesContext facesContext,
+    Set<VisitHint> hints,
+    PhaseId phaseId)
+  {
+    if (facesContext == null)
+      throw new NullPointerException();
+
+    if ((phaseId != null) && ((hints == null) || (!hints.contains(VisitHint.EXECUTE_LIFECYCLE))))
+      throw new IllegalArgumentException();
+    
+    _facesContext = facesContext;
+    _phaseId = phaseId;
+
+    // Copy and store hints - ensure unmodifiable and non-empty
+    EnumSet<VisitHint> hintsEnumSet = ((hints == null) || (hints.isEmpty()))
+                                          ? EnumSet.noneOf(VisitHint.class)
+                                          : EnumSet.copyOf(hints);
+
+    _hints = Collections.unmodifiableSet(hintsEnumSet);
+  }
+
+  /**
+   * @see VisitContext#getFacesContext VisitContext.getFacesContext()
+   */
+  @Override
+  public FacesContext getFacesContext()
+  {
+    return _facesContext;
+  }
+
+  /**
+   * <p>Returns the PhaseId, if any that, that this visit is ocurring under
+   * @return the current PhaseId
+   */
+  public PhaseId getPhaseId()
+  {
+    return _phaseId;
+  }
+
+  /**
+   * @see VisitContext#getIdsToVisit VisitContext.getIdsToVisit()
+   */
+  @Override
+  public Collection<String> getIdsToVisit()
+  {
+    // We always visits all ids
+    return ALL_IDS;
+  }
+
+  /**
+   * @see VisitContext#getSubtreeIdsToVisit VisitContext.getSubtreeIdsToVisit()
+   */
+  @Override
+  public Collection<String> getSubtreeIdsToVisit(UIComponent component)
+  {
+    // Make sure component is a NamingContainer
+    if (!(component instanceof NamingContainer))
+    {
+      throw new IllegalArgumentException("Component is not a NamingContainer: " + component);
+    }
+
+    // We always visits all ids
+    return ALL_IDS;
+  }
+
+  /**
+   * @see VisitContext#getHints VisitContext.getHints
+   */
+  @Override
+  public Set<VisitHint> getHints()
+  {
+    return _hints;
+  }
+
+  /**
+   * @see VisitContext#invokeVisitCallback VisitContext.invokeVisitCallback()
+   */
+  @Override
+  public VisitResult invokeVisitCallback(
+    UIComponent component, 
+    VisitCallback callback)
+  {
+    // Nothing interesting here - just invoke the callback.
+    // (PartialVisitContext.invokeVisitCallback() does all of the 
+    // interesting work.)
+    return callback.visit(this, component);
+  }
+
+  // The FacesContext for this request
+  private final FacesContext _facesContext;
+
+  // Our visit hints
+  private final Set<VisitHint> _hints;
+  private final PhaseId _phaseId;
+}