You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by de...@apache.org on 2006/06/22 09:00:40 UTC

svn commit: r416277 - in /myfaces/core/branches/jsf12/api/src/main/java/javax/faces: component/UIComponent.java webapp/UIComponentClassicTagBase.java webapp/UIComponentTag.java

Author: dennisbyrne
Date: Thu Jun 22 00:00:40 2006
New Revision: 416277

URL: http://svn.apache.org/viewvc?rev=416277&view=rev
Log:
added a protected field to UIComponent, located by clirr for binary compatibility http://clirr.sourceforge.net/clirr-core/anttask.html
UIComponentTag and UIComponentClassTagBase do not use a List as a Stack now.
scrapped and reimplemented all generated methods, just to be on the safe side
clirr util now says API is binary compatible, UOEs still exist

Modified:
    myfaces/core/branches/jsf12/api/src/main/java/javax/faces/component/UIComponent.java
    myfaces/core/branches/jsf12/api/src/main/java/javax/faces/webapp/UIComponentClassicTagBase.java
    myfaces/core/branches/jsf12/api/src/main/java/javax/faces/webapp/UIComponentTag.java

Modified: myfaces/core/branches/jsf12/api/src/main/java/javax/faces/component/UIComponent.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/jsf12/api/src/main/java/javax/faces/component/UIComponent.java?rev=416277&r1=416276&r2=416277&view=diff
==============================================================================
--- myfaces/core/branches/jsf12/api/src/main/java/javax/faces/component/UIComponent.java (original)
+++ myfaces/core/branches/jsf12/api/src/main/java/javax/faces/component/UIComponent.java Thu Jun 22 00:00:40 2006
@@ -33,6 +33,9 @@
 public abstract class UIComponent
         implements StateHolder
 {
+    
+    protected Map<String,ValueExpression> bindings; 
+    
     public UIComponent()
     {
     }

Modified: myfaces/core/branches/jsf12/api/src/main/java/javax/faces/webapp/UIComponentClassicTagBase.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/jsf12/api/src/main/java/javax/faces/webapp/UIComponentClassicTagBase.java?rev=416277&r1=416276&r2=416277&view=diff
==============================================================================
--- myfaces/core/branches/jsf12/api/src/main/java/javax/faces/webapp/UIComponentClassicTagBase.java (original)
+++ myfaces/core/branches/jsf12/api/src/main/java/javax/faces/webapp/UIComponentClassicTagBase.java Thu Jun 22 00:00:40 2006
@@ -3,6 +3,7 @@
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Stack;
 
 import javax.faces.application.Application;
 import javax.faces.component.UIComponent;
@@ -18,6 +19,9 @@
 import javax.servlet.jsp.tagext.JspIdConsumer;
 import javax.servlet.jsp.tagext.Tag;
 
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
 /**
  * @author Dennis Byrne
  * @since 1.2
@@ -27,279 +31,264 @@
         implements JspIdConsumer, BodyTag
 {
 
-    private UIComponent component ;
-    
+    private static final Log log = LogFactory
+            .getLog(UIComponentClassicTagBase.class);
+
+    // do not change this w/out doing likewise in UIComponentTag
+    private static final String COMPONENT_STACK_ATTR = "org.apache.myfaces.COMPONENT_STACK";
+
+    private static final String VERBATIM_COMP_TYPE = "javax.faces.HtmlOutputText";
+
+    private UIComponent component;
+
     private FacesContext ctx;
-    
-    protected PageContext pageContext ;
-    
-    private Tag parent ;
-    
+
+    protected PageContext pageContext;
+
+    private Tag parent;
+
     private ResponseWriter responseWriter;
-    
+
     private String id;
-    
+
     private BodyContent bodyContent;
-    
+
     private String jspId;
-    
-    private List<String> children ;
-    
-    private List<String> facets ;
-    
-    private boolean created ;
-    
-    private static final String VERBATIM_COMP_TYPE = "javax.faces.HtmlOutputText";
 
-    public int doAfterBody() throws JspException
-    {
-        throw new UnsupportedOperationException("1.2");
-    }
-    
-    protected String getFacesJspId()
-    {
-        throw new UnsupportedOperationException("1.2");
-    }
+    private List<String> children;
 
-    public void setJspId(String id)
-    {
-        throw new UnsupportedOperationException("1.2");
-    }
+    private List<String> facets;
 
-    protected UIComponent findComponent(FacesContext context)
-            throws JspException
-    {
-        throw new UnsupportedOperationException("1.2");
-    }
+    private boolean created;
 
-    public static UIComponentClassicTagBase getParentUIComponentClassicTagBase(
-            PageContext context)
+    protected void addChild(UIComponent child)
     {
-        throw new UnsupportedOperationException("1.2");
+        getChildren().add(child.getId());
     }
 
-    public int doStartTag() throws JspException
+    protected void addFacet(String name)
     {
-        throw new UnsupportedOperationException("1.2");
+        getFacets().add(name);
     }
 
-    public int doEndTag() throws JspException
+    protected void addVerbatimAfterComponent(
+            UIComponentClassicTagBase parentTag, UIComponent verbatim,
+            UIComponent component)
     {
-        throw new UnsupportedOperationException("1.2");
+        addVerbatimComponent(parentTag, verbatim, component, 1);
     }
 
-    public void release()
+    protected void addVerbatimBeforeComponent(
+            UIComponentClassicTagBase parentTag, UIComponent verbatim,
+            UIComponent component)
     {
-        throw new UnsupportedOperationException("1.2");
+        addVerbatimComponent(parentTag, verbatim, component, 0);
     }
 
-    protected int getDoAfterBodyValue() throws JspException
-    {
-        return SKIP_BODY;
-    }
+    protected abstract UIComponent createComponent(FacesContext context,
+            String newId) throws JspException;
 
-    public void doInitBody() throws JspException
+    protected UIOutput createVerbatimComponent()
     {
-        // intentional noop
+        FacesContext _ctx = getFacesContext();
+
+        if (_ctx == null)
+            throw new NullPointerException("FacesContext");
+
+        Application app = _ctx.getApplication();
+
+        if (app == null)
+            throw new NullPointerException("Application");
+
+        UIViewRoot root = _ctx.getViewRoot();
+
+        if (root == null)
+            throw new NullPointerException("UIViewRoot");
+
+        String uniqueId = root.createUniqueId();
+
+        if (log.isDebugEnabled())
+            log
+                    .debug("JSF 1.2 SPEC: Use the Application instance to create a new component "
+                            + "with the following characteristics: "
+                            + "componentType is javax.faces.HtmlOutputText, "
+                            + "transient is true, "
+                            + "escape is false, "
+                            + "id is FacesContext.getViewRoot().createUniqueId() "
+                            + uniqueId);
+
+        UIComponent component = app.createComponent(VERBATIM_COMP_TYPE);
+        component.setTransient(true);
+        component.getAttributes().put("escape", Boolean.FALSE);
+        component.setId(uniqueId);
+
+        return (UIOutput) component;
     }
-    
+
     protected UIComponent createVerbatimComponentFromBodyContent()
     {
-        
+
         // the 'single exit point' rule made this look like perl
-        
-        if( bodyContent == null)
+
+        if (bodyContent == null)
             return null;
-        
+
         String bodyString = bodyContent.getString();
-        
-        if( bodyString == null) // nothing
+
+        if (log.isDebugEnabled())
+            log.debug("JSF 1.2 SPEC : return null if there is no body content");
+
+        if (bodyString == null) // nothing
             return null;
-        
+
         bodyContent.clearBody();
-        
+
         String trimmedBody = bodyString.trim();
-        
-        if( "".equals(trimmedBody) ) // whitespace
+
+        if (log.isDebugEnabled())
+            log
+                    .debug("JSF 1.2 SPEC: return null if ... the body content is whitespace");
+
+        if ("".equals(trimmedBody)) // whitespace
             return null;
-        
-        if( trimmedBody.startsWith("<!--") 
-                && trimmedBody.endsWith("-->") ) // comments
+
+        if (log.isDebugEnabled())
+            log
+                    .debug("JSF 1.2 SPEC: return null if ... the body content is a comment");
+
+        if (trimmedBody.startsWith("<!--") && trimmedBody.endsWith("-->")) // comments
             return null;
-        
+
+        if (log.isDebugEnabled())
+            log
+                    .debug("JSF 1.2 SPEC : Create a transient UIOutput component from the body content ");
+
         UIOutput output = createVerbatimComponent();
         output.setValue(bodyString);
-        
+
         return output;
     }
-    
-    /**
-     * Helper method for addVerbatimBeforeComponent and addVerbatimAfterComponent.
-     */
-    
-    private void addVerbatimComponent(
-            UIComponentClassicTagBase parentTag, 
-            UIComponent verbatim,
-            UIComponent component, int shift){
-        
-        if( component == null )
-            throw new NullPointerException("UIComponent");
-        
-        UIComponent parent = component.getParent();
-        
-        if( parent != null ){
-            
-            List<UIComponent> brood = parent.getChildren();
-            
-            if( ! brood.contains(component) )
-                throw new IllegalStateException("Child component can find parent, but parent does not claim child ");
-            
-            brood.add(brood.indexOf(component) + shift, verbatim);
-            
-        }else if( parent == null && ! ( component instanceof UIViewRoot ) )
-            throw new NullPointerException("Could not find parent ");
-        
-    }
-    
-    protected void addVerbatimAfterComponent(
-            UIComponentClassicTagBase parentTag, UIComponent verbatim,
-            UIComponent component)
+
+    public int doAfterBody() throws JspException
     {
-        addVerbatimComponent(parentTag, verbatim, component, 1);
+        throw new UnsupportedOperationException("1.2");
     }
-    
-    protected void addVerbatimBeforeComponent(
-            UIComponentClassicTagBase parentTag, UIComponent verbatim,
-            UIComponent component)
+
+    public int doEndTag() throws JspException
     {
-        addVerbatimComponent(parentTag, verbatim, component, 0);
+        throw new UnsupportedOperationException("1.2");
+
+        // popTag();
     }
-    
-    protected UIOutput createVerbatimComponent()
+
+    public void doInitBody() throws JspException
     {
-        FacesContext _ctx = getFacesContext();
-        
-        if( _ctx == null )
-            throw new NullPointerException("FacesContext");
-        
-        Application app = _ctx.getApplication();
-        
-        if( app == null )
-            throw new NullPointerException("Application");
-        
-        UIViewRoot root = _ctx.getViewRoot();
-        
-        if( root == null )
-            throw new NullPointerException("UIViewRoot");    
-        
-        UIComponent component = app.createComponent(VERBATIM_COMP_TYPE);
-        component.setTransient(false);
-        component.getAttributes().put("escape", Boolean.FALSE);
-        component.setId(root.createUniqueId());
-        
-        return (UIOutput)component;
+        // intentional noop
     }
-    
-    protected FacesContext getFacesContext()
+
+    public int doStartTag() throws JspException
     {
-        return ctx != null ? ctx : FacesContext.getCurrentInstance();
+        getStack(pageContext).add(this); // push 
+
+        throw new UnsupportedOperationException("1.2");
     }
 
-    protected String getFacetName()
+    protected void encodeBegin() throws IOException
     {
-        if( parent == null || ! ( parent instanceof FacetTag ) )
-            return null;
-        else
-            return ((FacetTag)parent).getName();
+        if (component == null)
+            throw new NullPointerException("UIComponent component");
+
+        component.encodeBegin(ctx);
     }
-    
-    public boolean getCreated()
+
+    protected void encodeChildren() throws IOException
     {
-        return created;
+        if (component == null)
+            throw new NullPointerException("UIComponent component");
+
+        component.encodeChildren(ctx);
     }
-    
-    protected int getIndexOfNextChildTag()
+
+    protected void encodeEnd() throws IOException
     {
-        return getChildren().size();
+        if (component == null)
+            throw new NullPointerException("UIComponent component");
+
+        component.encodeEnd(ctx);
     }
-    
-    protected List<String> getCreatedComponents()
+
+    protected UIComponent findComponent(FacesContext context)
+            throws JspException
     {
-        return children;
+        throw new UnsupportedOperationException("1.2");
     }
-    
-    public JspWriter getPreviousOut()
+
+    public BodyContent getBodyContent()
     {
-        if( bodyContent == null)
-            throw new NullPointerException("BodyContent");
-        
-        return bodyContent.getEnclosingWriter();
-    }
-    
-    private List<String> getChildren(){
-        if( children == null)
-            children = new ArrayList<String>();
-        return children;
+        return bodyContent;
     }
-    
-    protected void addChild(UIComponent child)
+
+    public UIComponent getComponentInstance()
     {
-        getChildren().add(child.getId());
+        return component;
     }
 
-    private List<String> getFacets(){
-        if( facets == null)
-            facets = new ArrayList<String>();
-        return facets;
+    public boolean getCreated()
+    {
+        return created;
     }
-    
-    protected void addFacet(String name)
+
+    protected List<String> getCreatedComponents()
     {
-        getFacets().add(name);
+        return children;
     }
-    
-    public void setBodyContent(BodyContent bodyContent)
+
+    protected int getDoEndValue() throws JspException
     {
-        this.bodyContent = bodyContent;
+        return EVAL_PAGE;
     }
-    
+
     protected int getDoStartValue() throws JspException
     {
         return EVAL_BODY_BUFFERED;
     }
 
-    protected int getDoEndValue() throws JspException
+    protected int getDoAfterBodyValue() throws JspException
     {
-        return EVAL_PAGE;
+        return SKIP_BODY;
     }
 
-    protected void encodeBegin() throws IOException
+    protected FacesContext getFacesContext()
     {
-        if( component == null )
-            throw new NullPointerException("UIComponent component");
-        
-        component.encodeBegin(ctx);
+        return ctx != null ? ctx : FacesContext.getCurrentInstance();
     }
 
-    protected void encodeChildren() throws IOException
+    protected String getFacesJspId()
     {
-        if( component == null )
-            throw new NullPointerException("UIComponent component");
-        
-        component.encodeChildren(ctx);
+        throw new UnsupportedOperationException("1.2");
     }
 
-    protected void encodeEnd() throws IOException
+    protected String getFacetName()
     {
-        if( component == null )
-            throw new NullPointerException("UIComponent component");
-        
-        component.encodeEnd(ctx);
+        if (parent == null || !(parent instanceof FacetTag))
+            return null;
+        else
+            return ((FacetTag) parent).getName();
     }
 
-    public void setPageContext(PageContext pageContext)
+    protected String getId()
     {
-        this.pageContext = pageContext;
+        return id;
+    }
+
+    protected int getIndexOfNextChildTag()
+    {
+        return getChildren().size();
+    }
+
+    public String getJspId()
+    {
+        return jspId;
     }
 
     public Tag getParent()
@@ -307,49 +296,171 @@
         return parent;
     }
 
-    public void setParent(Tag parent)
+    public static UIComponentClassicTagBase getParentUIComponentClassicTagBase(
+            PageContext pageContext)
     {
-        this.parent = parent;
+        Stack stack = getStack(pageContext);
+
+        int size = stack.size();
+
+        return size > 1 ? (UIComponentClassicTagBase) stack.get(size - 1)
+                : null;
     }
 
-    protected void setupResponseWriter()
+    public JspWriter getPreviousOut()
     {
-        // intentional no-op
+        if (bodyContent == null)
+            throw new NullPointerException("BodyContent");
+
+        return bodyContent.getEnclosingWriter();
     }
 
-    public BodyContent getBodyContent()
+    protected abstract boolean hasBinding();
+
+    public void release()
     {
-        return bodyContent;
+        throw new UnsupportedOperationException("1.2");
+    }
+
+    public void setBodyContent(BodyContent bodyContent)
+    {
+        this.bodyContent = bodyContent;
+    }
+
+    public void setJspId(String id)
+    {
+        throw new UnsupportedOperationException("1.2");
     }
 
     public void setId(String id)
     {
-        if( id != null && id.startsWith(UIViewRoot.UNIQUE_ID_PREFIX) )
-            throw new IllegalArgumentException("This is not a bug - @id may not begin w/ " + UIViewRoot.UNIQUE_ID_PREFIX);
-        
+        if (id != null && id.startsWith(UIViewRoot.UNIQUE_ID_PREFIX))
+            throw new IllegalArgumentException(
+                    "This is not a bug - @id may not begin w/ "
+                            + UIViewRoot.UNIQUE_ID_PREFIX);
+
         this.id = id;
     }
 
-    protected String getId()
+    public void setPageContext(PageContext pageContext)
     {
-        return id;
+        this.pageContext = pageContext;
     }
 
-    public String getJspId()
+    public void setParent(Tag parent)
     {
-        return jspId;
+        this.parent = parent;
     }
 
     protected abstract void setProperties(UIComponent component);
 
-    protected abstract UIComponent createComponent(FacesContext context,
-            String newId) throws JspException;
+    protected void setupResponseWriter()
+    {
+        // intentional no-op
+    }
 
-    protected abstract boolean hasBinding();
+    /**
+     * Returns a request scoped stack, creating one if necessary.
+     * 
+     * @see UIComponentClassicTagBase.getStack()
+     */
 
-    public UIComponent getComponentInstance()
+    private static final Stack getStack(PageContext pageContext)
     {
-        return component;
+        Stack stack = (Stack) pageContext.getAttribute(COMPONENT_STACK_ATTR,
+                PageContext.REQUEST_SCOPE);
+
+        if (stack == null)
+        {
+            stack = new Stack();
+            pageContext.setAttribute(COMPONENT_STACK_ATTR,
+                    PageContext.REQUEST_SCOPE);
+        }
+
+        return stack;
+    }
+
+    /**
+     * @see UIComponentTag.popTag
+     */
+
+    private void popTag()
+    {
+        Stack stack = getStack(pageContext);
+
+        int size = stack.size();
+
+        if (size == 0)
+        {
+            if (log.isWarnEnabled())
+                log
+                        .warn("If you can read this in your log files, "
+                                + "there may be a bug in MyFaces. popTag() "
+                                + "should not be called when there are no "
+                                + "Tags to pop from the stack.  Please report "
+                                + "this to a MyFaces mailing list or the issue tracker ");
+        }
+        else
+            stack.pop();
+
+        if (size <= 1)
+            pageContext.removeAttribute(COMPONENT_STACK_ATTR,
+                    PageContext.REQUEST_SCOPE);
+    }
+
+    /**
+     * Helper method for addVerbatimBeforeComponent and addVerbatimAfterComponent.
+     */
+
+    private void addVerbatimComponent(UIComponentClassicTagBase parentTag,
+            UIComponent verbatim, UIComponent component, int shift)
+    {
+
+        if (component == null)
+            throw new NullPointerException("UIComponent");
+
+        UIComponent parent = component.getParent();
+
+        if (parent != null)
+        {
+
+            List<UIComponent> brood = parent.getChildren();
+
+            if (!brood.contains(component))
+                throw new IllegalStateException(
+                        "Child component can find parent, but parent does not claim child ");
+
+            if (log.isDebugEnabled())
+                log.debug("adding verbatim component to list of UIComponents");
+
+            brood.add(brood.indexOf(component) + shift, verbatim);
+
+        }
+        else if (parent == null && !(component instanceof UIViewRoot))
+            throw new NullPointerException("Could not find parent ");
+
+    }
+
+    /**
+     * Null safe method for facets.
+     */
+
+    private List<String> getFacets()
+    {
+        if (facets == null)
+            facets = new ArrayList<String>();
+        return facets;
+    }
+
+    /**
+     * Null safe method for children.
+     */
+
+    private List<String> getChildren()
+    {
+        if (children == null)
+            children = new ArrayList<String>();
+        return children;
     }
 
-}
+}
\ No newline at end of file

Modified: myfaces/core/branches/jsf12/api/src/main/java/javax/faces/webapp/UIComponentTag.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/jsf12/api/src/main/java/javax/faces/webapp/UIComponentTag.java?rev=416277&r1=416276&r2=416277&view=diff
==============================================================================
--- myfaces/core/branches/jsf12/api/src/main/java/javax/faces/webapp/UIComponentTag.java (original)
+++ myfaces/core/branches/jsf12/api/src/main/java/javax/faces/webapp/UIComponentTag.java Thu Jun 22 00:00:40 2006
@@ -34,7 +34,11 @@
 import javax.servlet.jsp.PageContext;
 import javax.servlet.jsp.tagext.Tag;
 import java.io.IOException;
-import java.util.*;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+import java.util.Stack;
 
 /**
  * Base class for all JSP tags that represent a JSF UIComponent.
@@ -56,7 +60,9 @@
 {
     private static final String FORMER_CHILD_IDS_SET_ATTR = UIComponentTag.class.getName() + ".FORMER_CHILD_IDS";
     private static final String FORMER_FACET_NAMES_SET_ATTR = UIComponentTag.class.getName() + ".FORMER_FACET_NAMES";
-    private static final String COMPONENT_STACK_ATTR =  UIComponentTag.class.getName() + ".COMPONENT_STACK";
+    
+    // do not change this w/out doing likewise in UIComponentClassicTagBase
+    private static final String COMPONENT_STACK_ATTR = "org.apache.myfaces.COMPONENT_STACK";
 
     private static final String UNIQUE_ID_COUNTER_ATTR = UIComponentTag.class.getName() + ".UNIQUE_ID_COUNTER";
 
@@ -181,59 +187,35 @@
 
     /**
      * Return the nearest JSF tag that encloses this tag.
+     * @deprecated
      */
     public static UIComponentTag getParentUIComponentTag(PageContext pageContext)
     {
-        // Question: why not just walk up the _parent chain testing for
-        // instanceof UIComponentTag rather than maintaining a separate
-        // stack with the pushTag and popTag methods?
-        List list = (List)pageContext.getAttribute(COMPONENT_STACK_ATTR,
-                                                   PageContext.REQUEST_SCOPE);
-        if (list != null)
-        {
-            return (UIComponentTag)list.get(list.size() - 1);
-        }
-        return null;
-    }
-
-    /** See documentation for pushTag. */
-    private void popTag()
-    {
-        List list = (List)pageContext.getAttribute(COMPONENT_STACK_ATTR,
-                                                    PageContext.REQUEST_SCOPE);
-        if (list != null)
-        {
-            int size = list.size();
-            list.remove(size -1);
-            if (size <= 1)
-            {
-                pageContext.removeAttribute(COMPONENT_STACK_ATTR,
-                                             PageContext.REQUEST_SCOPE);
-            }
-        }
+        Stack stack = getStack(pageContext);
+        
+        int size = stack.size();
+        
+        return size > 1 ? (UIComponentTag)stack.get(size - 1) : null;
     }
 
     /**
-     * Push this tag onto the stack of JSP tags seen.
-     * <p>
      * The pageContext's request scope map is used to hold a stack of
      * JSP tag objects seen so far, so that a new tag can find the
      * parent tag that encloses it. Access to the parent tag is used
      * to find the parent UIComponent for the component associated
      * with this tag plus some other uses. 
      */
-    private void pushTag()
+    
+    private void popTag()
     {
-        List list = (List)pageContext.getAttribute(COMPONENT_STACK_ATTR,
-                                                    PageContext.REQUEST_SCOPE);
-        if (list == null)
-        {
-            list = new ArrayList();
-            pageContext.setAttribute(COMPONENT_STACK_ATTR,
-                                      list,
-                                      PageContext.REQUEST_SCOPE);
-        }
-        list.add(this);
+        Stack stack = getStack(pageContext);
+        
+        int size = stack.size();
+        stack.remove(size -1);
+        if (size <= 1)
+            pageContext.removeAttribute(COMPONENT_STACK_ATTR,
+                                         PageContext.REQUEST_SCOPE);
+        
     }
 
     /**
@@ -322,7 +304,7 @@
                 throw new JspException(e.getMessage(), e);
             }
         }
-        pushTag();
+        getStack(pageContext).add(this); // push this tag on the stack
         return getDoStartValue();
     }
 
@@ -985,6 +967,26 @@
         buf.insert(0,intBuf);
 
         getPathToComponent(component.getParent(),buf);
+    }
+    
+    /**
+     * Returns a request scoped stack, creating one if necessary.
+     * 
+     * @see UIComponentClassicTagBase.getStack()
+     */
+    
+    private static final Stack getStack(PageContext pageContext){
+        
+        Stack stack = (Stack) pageContext.getAttribute(COMPONENT_STACK_ATTR,
+                PageContext.REQUEST_SCOPE);
+        
+        if(stack == null){
+            stack = new Stack();
+            pageContext.setAttribute(COMPONENT_STACK_ATTR, stack, 
+                    PageContext.REQUEST_SCOPE);
+        }
+        
+        return stack;
     }
 
 }