Revision: 1424
          http://stripes.svn.sourceforge.net/stripes/?rev=1424&view=rev
Author:   bengunter
Date:     2011-04-21 19:40:45 +0000 (Thu, 21 Apr 2011)

Log Message:
-----------
The final unfixed error case for STS-788, reported by Nick Stuart, involves a 
stripes:layout-render tag nested within a stripes:form tag. The bad behavior of 
the layout-render tag happens because stripes:form buffers its body content. 
Unfortunately, due to the way Jasper compiles JSP to Java, there is no way to 
change the value of the local "out" variable in the Java code after the a tag 
begins executing. That makes it impossible to fix that issue using the same 
means of enabling and disabling output as I have been using. This revision 
changes LayoutWriter to use a form of in-band signaling instead. 
LayoutWriter#setSilent(..) writes a control character (currently NUL) to output 
to toggle the silent state, and LayoutWriter#write(..) looks for and reacts to 
these control characters. This patch finally fixes all the issues that have 
been reported in STS-788 so far.

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

Modified: 
branches/1.5.x/stripes/src/net/sourceforge/stripes/tag/layout/LayoutComponentTag.java
===================================================================
--- 
branches/1.5.x/stripes/src/net/sourceforge/stripes/tag/layout/LayoutComponentTag.java
       2011-03-14 14:28:44 UTC (rev 1423)
+++ 
branches/1.5.x/stripes/src/net/sourceforge/stripes/tag/layout/LayoutComponentTag.java
       2011-04-21 19:40:45 UTC (rev 1424)
@@ -14,6 +14,7 @@
  */
 package net.sourceforge.stripes.tag.layout;
 
+import java.io.IOException;
 import java.util.Iterator;
 import java.util.List;
 import java.util.regex.Pattern;
@@ -265,6 +266,9 @@
 
             return EVAL_PAGE;
         }
+        catch (IOException e) {
+            throw new JspException(e);
+        }
         finally {
             this.context = null;
             this.silent = false;

Modified: 
branches/1.5.x/stripes/src/net/sourceforge/stripes/tag/layout/LayoutDefinitionTag.java
===================================================================
--- 
branches/1.5.x/stripes/src/net/sourceforge/stripes/tag/layout/LayoutDefinitionTag.java
      2011-03-14 14:28:44 UTC (rev 1423)
+++ 
branches/1.5.x/stripes/src/net/sourceforge/stripes/tag/layout/LayoutDefinitionTag.java
      2011-04-21 19:40:45 UTC (rev 1424)
@@ -14,6 +14,7 @@
  */
 package net.sourceforge.stripes.tag.layout;
 
+import java.io.IOException;
 import java.util.Map;
 
 import javax.servlet.jsp.JspException;
@@ -63,27 +64,32 @@
      */
     @Override
     public int doStartTag() throws JspException {
-        LayoutContext context = getContext(); // Initialize context
-        renderPhase = context.isComponentRenderPhase(); // Initialize phase 
flag
-        silent = context.getOut().isSilent();
+        try {
+            LayoutContext context = getContext(); // Initialize context
+            renderPhase = context.isComponentRenderPhase(); // Initialize 
phase flag
+            silent = context.getOut().isSilent();
 
-        // Flag this definition has rendered, even though it's not really done 
yet.
-        context.setRendered(true);
+            // Flag this definition has rendered, even though it's not really 
done yet.
+            context.setRendered(true);
 
-        // Put any additional parameters into page context for the definition 
to use
-        if (!renderPhase) {
-            for (Map.Entry<String, Object> entry : 
context.getParameters().entrySet()) {
-                pageContext.setAttribute(entry.getKey(), entry.getValue());
+            // Put any additional parameters into page context for the 
definition to use
+            if (!renderPhase) {
+                for (Map.Entry<String, Object> entry : 
context.getParameters().entrySet()) {
+                    pageContext.setAttribute(entry.getKey(), entry.getValue());
+                }
             }
-        }
 
-        // Put component renderers into the page context, even those from 
previous contexts
-        exportComponentRenderers();
+            // Put component renderers into the page context, even those from 
previous contexts
+            exportComponentRenderers();
 
-        // Enable output only if this is the definition execution, not a 
component render
-        context.getOut().setSilent(renderPhase, pageContext);
+            // Enable output only if this is the definition execution, not a 
component render
+            context.getOut().setSilent(renderPhase, pageContext);
 
-        return EVAL_BODY_INCLUDE;
+            return EVAL_BODY_INCLUDE;
+        }
+        catch (IOException e) {
+            throw new JspException(e);
+        }
     }
 
     /**
@@ -97,6 +103,9 @@
             getContext().getOut().setSilent(silent, pageContext);
             return SKIP_PAGE;
         }
+        catch (IOException e) {
+            throw new JspException(e);
+        }
         finally {
             this.context = null;
             this.renderPhase = false;

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-03-14 14:28:44 UTC (rev 1423)
+++ 
branches/1.5.x/stripes/src/net/sourceforge/stripes/tag/layout/LayoutRenderTag.java
  2011-04-21 19:40:45 UTC (rev 1424)
@@ -14,6 +14,8 @@
  */
 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;
@@ -95,24 +97,29 @@
      */
     @Override
     public int doStartTag() throws JspException {
-        LayoutContext context = getContext();
-        silent = context.getOut().isSilent();
+        try {
+            LayoutContext context = getContext();
+            silent = context.getOut().isSilent();
 
-        if (contextIsNew) {
-            log.debug("Start layout init in ", context.getRenderPage());
-            pushPageContextAttributes(context.getParameters());
-        }
+            if (contextIsNew) {
+                log.debug("Start layout init in ", context.getRenderPage());
+                pushPageContextAttributes(context.getParameters());
+            }
 
-        if (context.isComponentRenderPhase()) {
-            log.debug("Start component render phase for ", 
context.getComponent(), " in ",
-                    context.getRenderPage());
-            exportComponentRenderers();
-        }
+            if (context.isComponentRenderPhase()) {
+                log.debug("Start component render phase for ", 
context.getComponent(), " in ",
+                        context.getRenderPage());
+                exportComponentRenderers();
+            }
 
-        // Render tags never output their contents directly
-        context.getOut().setSilent(true, pageContext);
+            // Render tags never output their contents directly
+            context.getOut().setSilent(true, pageContext);
 
-        return contextIsNew ? EVAL_BODY_BUFFERED : EVAL_BODY_INCLUDE;
+            return contextIsNew ? EVAL_BODY_BUFFERED : EVAL_BODY_INCLUDE;
+        }
+        catch (IOException e) {
+            throw new JspException(e);
+        }
     }
 
     /**
@@ -172,9 +179,13 @@
                         );
                 }
 
+                context.getOut().setSilent(silent, pageContext);
                 LayoutContext.pop(pageContext);
                 popPageContextAttributes(); // remove any dynattrs from page 
scope
             }
+            else {
+                context.getOut().setSilent(silent, pageContext);
+            }
 
             if (context.isComponentRenderPhase()) {
                 log.debug("End component render phase for ", 
context.getComponent(), " in ",
@@ -182,10 +193,11 @@
                 cleanUpComponentRenderers();
             }
 
-            // Restore output's silent flag
-            context.getOut().setSilent(silent, pageContext);
             return EVAL_PAGE;
         }
+        catch (IOException e) {
+            throw new JspException(e);
+        }
         finally {
             this.context = null;
             this.contextIsNew = false;

Modified: 
branches/1.5.x/stripes/src/net/sourceforge/stripes/tag/layout/LayoutWriter.java
===================================================================
--- 
branches/1.5.x/stripes/src/net/sourceforge/stripes/tag/layout/LayoutWriter.java 
    2011-03-14 14:28:44 UTC (rev 1423)
+++ 
branches/1.5.x/stripes/src/net/sourceforge/stripes/tag/layout/LayoutWriter.java 
    2011-04-21 19:40:45 UTC (rev 1424)
@@ -38,8 +38,11 @@
 public class LayoutWriter extends Writer {
     private static final Log log = Log.getInstance(LayoutWriter.class);
 
+    /** The control character that, when encountered in the output stream, 
toggles the silent state. */
+    private static final char TOGGLE = 0;
+
     private LinkedList<Writer> writers = new LinkedList<Writer>();
-    private boolean silent;
+    private boolean silent, silentState;
 
     /**
      * Create a new layout writer that wraps the given JSP writer.
@@ -64,12 +67,17 @@
     /**
      * Enable or disable silent mode. The output buffer for the given page 
context will be flushed
      * before silent mode is enabled to ensure all buffered data are written.
+     * 
+     * @param silent True to silence output, false to enable output.
+     * @param pageContext The page context in use at the time output is to be 
silenced.
+     * @throws IOException If an error occurs writing to output.
      */
-    public void setSilent(boolean silent, PageContext pageContext) {
+    public void setSilent(boolean silent, PageContext pageContext) throws 
IOException {
         if (silent != this.silent) {
+            pageContext.getOut().write(TOGGLE);
             tryFlush(pageContext);
             this.silent = silent;
-            log.trace("Output is " + (silent ? "DISABLED" : "ENABLED"));
+            log.trace("Output is ", (silent ? "DISABLED" : "ENABLED"));
         }
     }
 
@@ -144,7 +152,21 @@
 
     @Override
     public void write(char[] cbuf, int off, int len) throws IOException {
-        if (!isSilent())
-            getOut().write(cbuf, off, len);
+        for (int i = off, mark = i, n = i + len; i < n; ++i) {
+            switch (cbuf[i]) {
+            case TOGGLE:
+                if (this.silentState)
+                    mark = i + 1;
+                else if (i > mark)
+                    getOut().write(cbuf, mark, i - mark);
+                this.silentState = !this.silentState;
+                break;
+            default:
+                if (this.silentState)
+                    ++mark;
+                else if (i > mark && i == n - 1)
+                    getOut().write(cbuf, mark, i - mark + 1);
+            }
+        }
     }
 }


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

------------------------------------------------------------------------------
Fulfilling the Lean Software Promise
Lean software platforms are now widely adopted and the benefits have been 
demonstrated beyond question. Learn why your peers are replacing JEE 
containers with lightweight application servers - and what you can gain 
from the move. http://p.sf.net/sfu/vmware-sfemails
_______________________________________________
Stripes-development mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/stripes-development

Reply via email to