Revision: 1390
          http://stripes.svn.sourceforge.net/stripes/?rev=1390&view=rev
Author:   bengunter
Date:     2011-01-06 18:09:14 +0000 (Thu, 06 Jan 2011)

Log Message:
-----------
STS-788: Fixed issues reported by S?\195?\169bastien Lesaint.

- When a new layout context is created, it calls pushBody(Writer) to insert the 
LayoutWriter which controls output. However, after the layout process was 
completed, it was not calling popBody(). This caused problems when the layout 
tags were executing within another tag (like stripes:form) that had pushed a 
BodyContent.

- The render tag documentation does not state that it must be the outermost 
output-producing tag in a page. (The definition tag documentation does.) I 
changed the render tag so it not longer clears the output buffer and returns 
EVAL_PAGE instead of SKIP_PAGE to make it compatible with the old 
implementation. To hide any stray render tag contents, it now implements 
BodyTag and returns EVAL_BODY_BUFFERED for component registration phase, 
discarding the body content afterward, and EVAL_BODY_INCLUDE for component 
render phase. In the latter case, the undesirable output is discarded by the 
LayoutWriter.

Modified Paths:
--------------
    
branches/1.5.x/stripes/src/net/sourceforge/stripes/tag/layout/LayoutContext.java
    
branches/1.5.x/stripes/src/net/sourceforge/stripes/tag/layout/LayoutRenderTag.java

Modified: 
branches/1.5.x/stripes/src/net/sourceforge/stripes/tag/layout/LayoutContext.java
===================================================================
--- 
branches/1.5.x/stripes/src/net/sourceforge/stripes/tag/layout/LayoutContext.java
    2011-01-06 14:12:59 UTC (rev 1389)
+++ 
branches/1.5.x/stripes/src/net/sourceforge/stripes/tag/layout/LayoutContext.java
    2011-01-06 18:09:14 UTC (rev 1390)
@@ -93,11 +93,17 @@
     public static LayoutContext pop(PageContext pageContext) {
         LayoutContext context = lookup(pageContext);
         log.debug("Pop context ", context.getRenderPage(), " -> ", 
context.getDefinitionPage());
+
         pageContext.setAttribute(LAYOUT_CONTEXT_KEY, context.previous);
-        if (context.previous != null) {
+
+        if (context.previous == null) {
+            pageContext.popBody();
+        }
+        else {
             context.previous.next = null;
             context.previous = null;
         }
+
         return context;
     }
 

Modified: 
branches/1.5.x/stripes/src/net/sourceforge/stripes/tag/layout/LayoutRenderTag.java
===================================================================
--- 
branches/1.5.x/stripes/src/net/sourceforge/stripes/tag/layout/LayoutRenderTag.java
  2011-01-06 14:12:59 UTC (rev 1389)
+++ 
branches/1.5.x/stripes/src/net/sourceforge/stripes/tag/layout/LayoutRenderTag.java
  2011-01-06 18:09:14 UTC (rev 1390)
@@ -14,10 +14,11 @@
  */
 package net.sourceforge.stripes.tag.layout;
 
-import java.io.IOException;
-
 import javax.servlet.jsp.JspException;
+import javax.servlet.jsp.tagext.BodyContent;
+import javax.servlet.jsp.tagext.BodyTag;
 import javax.servlet.jsp.tagext.DynamicAttributes;
+import javax.servlet.jsp.tagext.Tag;
 
 import net.sourceforge.stripes.exception.StripesJspException;
 import net.sourceforge.stripes.exception.StripesRuntimeException;
@@ -31,12 +32,13 @@
  * @author Tim Fennell, Ben Gunter
  * @since Stripes 1.1
  */
-public class LayoutRenderTag extends LayoutTag implements DynamicAttributes {
+public class LayoutRenderTag extends LayoutTag implements BodyTag, 
DynamicAttributes {
     private static final Log log = Log.getInstance(LayoutRenderTag.class);
 
     private String name;
     private LayoutContext context;
     private boolean contextIsNew, silent;
+    private BodyContent bodyContent;
 
     /** Gets the name of the layout to be used. */
     public String getName() { return name; }
@@ -116,10 +118,27 @@
         // Render tags never output their contents directly
         context.getOut().setSilent(true, pageContext);
 
-        return EVAL_BODY_INCLUDE;
+        return contextIsNew ? EVAL_BODY_BUFFERED : EVAL_BODY_INCLUDE;
     }
 
     /**
+     * Set the tag's body content. Called by the JSP engine during component 
registration phase,
+     * when {...@link #doStartTag()} returns {...@link 
BodyTag#EVAL_BODY_BUFFERED}
+     */
+    public void setBodyContent(BodyContent bodyContent) {
+        this.bodyContent = bodyContent;
+    }
+
+    /** Does nothing. */
+    public void doInitBody() throws JspException {
+    }
+
+    /** Returns {...@link Tag#SKIP_BODY}. */
+    public int doAfterBody() throws JspException {
+        return SKIP_BODY;
+    }
+
+    /**
      * After the first pass (see {...@link 
LayoutContext#isComponentRenderPhase()}):
      * <ul>
      * <li>Ensure the layout rendered successfully by checking {...@link 
LayoutContext#isRendered()}.</li>
@@ -134,18 +153,6 @@
         try {
             LayoutContext context = getContext();
             if (contextIsNew) {
-                // Substitution of the layout writer for the regular JSP 
writer does not work for
-                // the initial render tag. Its body evaluation still uses the 
original JSP writer
-                // for output. Clear the output buffer before executing the 
definition page.
-                if (isOuterLayoutTag()) {
-                    try {
-                        context.getOut().clear();
-                    }
-                    catch (IOException e) {
-                        log.debug("Could not clear output buffer: ", 
e.getMessage());
-                    }
-                }
-
                 log.debug("End layout init in ", context.getRenderPage());
 
                 try {
@@ -185,14 +192,17 @@
 
             // Restore output's silent flag
             context.getOut().setSilent(silent, pageContext);
-
-            // Skip the rest of the page if this is the outer-most render tag
-            return isOuterLayoutTag() ? SKIP_PAGE : EVAL_PAGE;
+            return EVAL_PAGE;
         }
         finally {
             this.context = null;
             this.contextIsNew = false;
             this.silent = false;
+
+            if (this.bodyContent != null) {
+                this.bodyContent.clearBody();
+                this.bodyContent = null;
+            }
         }
     }
 }


This was sent by the SourceForge.net collaborative development platform, the 
world's largest Open Source development site.

------------------------------------------------------------------------------
Learn how Oracle Real Application Clusters (RAC) One Node allows customers
to consolidate database storage, standardize their database environment, and, 
should the need arise, upgrade to a full multi-node Oracle RAC database 
without downtime or disruption
http://p.sf.net/sfu/oracle-sfdevnl
_______________________________________________
Stripes-development mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/stripes-development

Reply via email to