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