Revision: 1253
          http://stripes.svn.sourceforge.net/stripes/?rev=1253&view=rev
Author:   bengunter
Date:     2010-06-08 20:03:28 +0000 (Tue, 08 Jun 2010)

Log Message:
-----------
STS-391: Enable streaming even using the decorator pattern by allowing 
layout-component within a layout-component even when the two tags have the same 
name. This is accomplished by changing LayoutComponentTag to use 
LayoutComponentRenderer to do the heavy lifting via a new write() method that 
renders the component directly to the JSP writer. LayoutComponentRenderer's 
toString() method now uses the write() method but sets up a buffer in the 
LayoutWriter beforehand and closes the buffer afterward. To use these new 
capabilities, one need only replace component references like ${body} with 
<s:layout-component name="body" />.

Modified Paths:
--------------
    
branches/1.5.x/stripes/src/net/sourceforge/stripes/tag/layout/LayoutComponentRenderer.java
    
branches/1.5.x/stripes/src/net/sourceforge/stripes/tag/layout/LayoutComponentTag.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/LayoutComponentRenderer.java
===================================================================
--- 
branches/1.5.x/stripes/src/net/sourceforge/stripes/tag/layout/LayoutComponentRenderer.java
  2010-06-07 20:51:40 UTC (rev 1252)
+++ 
branches/1.5.x/stripes/src/net/sourceforge/stripes/tag/layout/LayoutComponentRenderer.java
  2010-06-08 20:03:28 UTC (rev 1253)
@@ -14,9 +14,11 @@
  */
 package net.sourceforge.stripes.tag.layout;
 
+import java.io.IOException;
 import java.util.Iterator;
 import java.util.LinkedList;
 
+import javax.servlet.ServletException;
 import javax.servlet.jsp.PageContext;
 
 import net.sourceforge.stripes.controller.StripesConstants;
@@ -89,12 +91,19 @@
         return sourceContext;
     }
 
-    @Override
-    public String toString() {
+    /**
+     * Write the component to the page context's writer, optionally buffering 
the output.
+     * 
+     * @return True if the named component was found and it indicated that it 
successfully rendered;
+     *         otherwise, false.
+     * @throws IOException If thrown by {...@link PageContext#include(String)}
+     * @throws ServletException If thrown by {...@link 
PageContext#include(String)}
+     */
+    public boolean write() throws ServletException, IOException {
         final PageContext pageContext = getPageContext();
         if (pageContext == null) {
             log.error("Failed to render component \"", componentName, "\" 
without a page context!");
-            return "[Failed to render component \"" + componentName + "\" 
without a page context!]";
+            return false;
         }
 
         // Get the current page so we can be sure not to invoke it again (see 
below)
@@ -138,38 +147,63 @@
                 log.debug("Start stringify \"", componentName, "\" in ", 
context.getRenderPage(),
                         " -> ", context.getDefinitionPage(), " from ", 
source.getRenderPage(),
                         " -> ", source.getDefinitionPage());
-                context.getOut().openBuffer(pageContext);
                 context.getOut().setSilent(true, pageContext);
                 pageContext.include(source.getRenderPage(), false);
                 log.debug("End stringify \"", componentName, "\" in ", 
context.getRenderPage(),
                         " -> ", context.getDefinitionPage(), " from ", 
source.getRenderPage(),
                         " -> ", source.getDefinitionPage());
+
+                // If the component name has been cleared then the component 
rendered
+                if (context.getComponent() == null)
+                    return true;
             }
-            catch (Exception e) {
-                log.error(e, "Unhandled exception trying to render component 
\"", componentName,
-                        "\" to a string in context ", source.getRenderPage(), 
" -> ", source
-                                .getDefinitionPage());
-                return "[Failed to render \"" + componentName + "\". See log 
for details.]";
-            }
             finally {
-                // Determine if the component rendered before resetting the 
context properties
-                boolean rendered = context.getComponent() == null;
-
                 // Reset the context properties
                 context.setComponentRenderPhase(phaseFlag);
                 context.setComponent(component);
                 context.getOut().setSilent(silent, pageContext);
                 sourceContext = currentSource;
-
-                // Pop the buffer contents and return them if the component 
did render
-                String value = context.getOut().closeBuffer(pageContext);
-                if (rendered)
-                    return value;
             }
         }
 
         log.debug("Component \"", componentName, "\" evaluated to empty string 
in context ",
                 context.getRenderPage(), " -> ", context.getDefinitionPage());
-        return "";
+        return false;
     }
+
+    /**
+     * Open a buffer in {...@link LayoutWriter}, call {...@link #write()} to 
render the component and then
+     * return the buffer contents.
+     */
+    @Override
+    public String toString() {
+        final PageContext pageContext = getPageContext();
+        if (pageContext == null) {
+            log.error("Failed to render component \"", componentName, "\" 
without a page context!");
+            return "[Failed to render component \"" + componentName + "\" 
without a page context!]";
+        }
+
+        final LayoutContext context = LayoutContext.lookup(pageContext);
+        String contents;
+        context.getOut().openBuffer(pageContext);
+        try {
+            write();
+        }
+        catch (Exception e) {
+            log.error(e, "Unhandled exception trying to render component \"", 
componentName,
+                    "\" to a string in context ", context.getRenderPage(), //
+                    " -> ", context.getDefinitionPage());
+            return "[Failed to render \"" + componentName + "\". See log for 
details.]";
+        }
+        finally {
+            contents = context.getOut().closeBuffer(pageContext);
+            if ("".equals(contents)) {
+                log.debug("Component \"", componentName,
+                        "\" evaluated to empty string in context ", 
context.getRenderPage(),
+                        " -> ", context.getDefinitionPage());
+            }
+        }
+
+        return contents;
+    }
 }

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
       2010-06-07 20:51:40 UTC (rev 1252)
+++ 
branches/1.5.x/stripes/src/net/sourceforge/stripes/tag/layout/LayoutComponentTag.java
       2010-06-08 20:03:28 UTC (rev 1253)
@@ -14,11 +14,8 @@
  */
 package net.sourceforge.stripes.tag.layout;
 
-import java.io.IOException;
-import java.util.Iterator;
 import java.util.regex.Pattern;
 
-import javax.servlet.ServletException;
 import javax.servlet.jsp.JspException;
 
 import net.sourceforge.stripes.exception.StripesJspException;
@@ -130,37 +127,19 @@
             }
             else if (isChildOfDefinition()) {
                 if (!context.isComponentRenderPhase()) {
-                    // Set render phase flag and the name of the component to 
render. Iterate down
-                    // the stack of layout contexts, executing each render 
page that contains a
-                    // component with the same name as this one until the 
component has rendered or
-                    // we run out of contexts.
-                    context.setComponentRenderPhase(true);
-                    context.setComponent(getName());
-                    Iterator<LayoutContext> iterator = 
LayoutContext.getStack(pageContext, true)
-                            .descendingIterator();
-                    while (iterator.hasNext() && context.getComponent() != 
null) {
-                        LayoutContext renderer = iterator.next();
-                        if (renderer.getComponents().containsKey(getName())) {
-                            String renderPage = renderer.getRenderPage();
-                            log.debug("Execute component ", getName(), " in ", 
context
-                                    .getDefinitionPage(), " with include of ", 
renderPage);
-                            boolean silent = context.getOut().isSilent();
-                            context.getOut().setSilent(true, pageContext);
-                            pageContext.include(renderPage, false);
-                            context.getOut().setSilent(silent, pageContext);
-                        }
-                    }
-                    context.setComponentRenderPhase(false);
+                    // Use a layout component renderer to do the heavy lifting
+                    log.debug("Invoke layout component renderer for recursive 
render");
+                    LayoutComponentRenderer renderer = new 
LayoutComponentRenderer(getName());
+                    renderer.pushPageContext(pageContext);
+                    boolean rendered = renderer.write();
 
-                    // The current component name should be cleared after the 
component has
-                    // rendered. If it is not cleared then the component did 
not render so we need
-                    // to output the default content from the layout 
definition.
-                    if (context.getComponent() != null) {
+                    // If the component did not render then we need to output 
the default contents
+                    // from the layout definition.
+                    if (!rendered) {
                         log.debug("Component was not present in ", 
context.getRenderPage(),
                                 " so using default content from ", 
context.getDefinitionPage());
 
                         context.getOut().setSilent(false, pageContext);
-                        context.setComponent(null);
                         return EVAL_BODY_INCLUDE;
                     }
                 }
@@ -168,16 +147,30 @@
                     log.debug("No-op for ", getName(), " in ", 
context.getDefinitionPage());
                 }
             }
+            else if (isChildOfComponent() && isCurrentComponent()
+                    && context.isComponentRenderPhase()) {
+                LayoutComponentTag parent = getLayoutAncestor();
+                if (getName().equals(parent.getName())) {
+                    log.debug("Invoke layout component renderer for recursive 
render");
+                    LayoutComponentRenderer renderer = 
(LayoutComponentRenderer) pageContext
+                            .getAttribute(getName());
+                    renderer.write();
+                }
+            }
 
             context.getOut().setSilent(true, pageContext);
             return SKIP_BODY;
         }
-        catch (ServletException e) {
-            throw new StripesJspException(e);
+        catch (Exception e) {
+            log.error(e, "Unhandled exception trying to render component \"", 
getName(),
+                    "\" to a string in context ", context.getRenderPage(), " 
-> ", context
+                            .getDefinitionPage());
+
+            if (e instanceof RuntimeException)
+                throw (RuntimeException) e;
+            else
+                throw new StripesJspException(e);
         }
-        catch (IOException e) {
-            throw new StripesJspException(e);
-        }
     }
 
     /**

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 
    2010-06-07 20:51:40 UTC (rev 1252)
+++ 
branches/1.5.x/stripes/src/net/sourceforge/stripes/tag/layout/LayoutWriter.java 
    2010-06-08 20:03:28 UTC (rev 1253)
@@ -78,6 +78,7 @@
      * closed and its contents retrieved by calling {...@link 
#closeBuffer(PageContext)}.
      */
     public void openBuffer(PageContext pageContext) {
+        log.trace("Open buffer");
         tryFlush(pageContext);
         writers.add(new StringWriter(1024));
     }
@@ -90,7 +91,9 @@
      */
     public String closeBuffer(PageContext pageContext) {
         if (getOut() instanceof StringWriter) {
-            return ((StringWriter) writers.removeLast()).toString();
+            String contents = ((StringWriter) writers.removeLast()).toString();
+            log.trace("Closed buffer: \"", contents, "\"");
+            return contents;
         }
         else {
             throw new StripesRuntimeException(


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

------------------------------------------------------------------------------
ThinkGeek and WIRED's GeekDad team up for the Ultimate 
GeekDad Father's Day Giveaway. ONE MASSIVE PRIZE to the 
lucky parental unit.  See the prize list and enter to win: 
http://p.sf.net/sfu/thinkgeek-promo
_______________________________________________
Stripes-development mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/stripes-development

Reply via email to