Revision: 1479
          http://stripes.svn.sourceforge.net/stripes/?rev=1479&view=rev
Author:   bengunter
Date:     2012-03-05 16:19:23 +0000 (Mon, 05 Mar 2012)
Log Message:
-----------
Rolled up fix for STS-871 from 1.5.x branch.

Modified Paths:
--------------
    trunk/stripes/src/net/sourceforge/stripes/tag/layout/LayoutComponentTag.java
    trunk/stripes/src/net/sourceforge/stripes/tag/layout/LayoutContext.java
    
trunk/stripes/src/net/sourceforge/stripes/tag/layout/LayoutDefinitionTag.java
    trunk/stripes/src/net/sourceforge/stripes/tag/layout/LayoutRenderTag.java

Added Paths:
-----------
    
trunk/stripes/src/net/sourceforge/stripes/tag/layout/LayoutRenderTagPath.java

Property Changed:
----------------
    trunk/


Property changes on: trunk
___________________________________________________________________
Modified: svn:mergeinfo
   - /branches/1.5.x:1463-1464,1466,1468-1469,1471,1473,1475
   + /branches/1.5.x:1463-1464,1466,1468-1469,1471,1473,1475,1477-1478

Modified: 
trunk/stripes/src/net/sourceforge/stripes/tag/layout/LayoutComponentTag.java
===================================================================
--- 
trunk/stripes/src/net/sourceforge/stripes/tag/layout/LayoutComponentTag.java    
    2012-03-05 16:16:15 UTC (rev 1478)
+++ 
trunk/stripes/src/net/sourceforge/stripes/tag/layout/LayoutComponentTag.java    
    2012-03-05 16:19:23 UTC (rev 1479)
@@ -15,13 +15,13 @@
 package net.sourceforge.stripes.tag.layout;
 
 import java.io.IOException;
-import java.util.Iterator;
-import java.util.List;
 import java.util.regex.Pattern;
 
 import javax.servlet.jsp.JspException;
+import javax.servlet.jsp.PageContext;
 
 import net.sourceforge.stripes.exception.StripesJspException;
+import net.sourceforge.stripes.exception.StripesRuntimeException;
 import net.sourceforge.stripes.util.Log;
 
 /**
@@ -49,88 +49,42 @@
     /** Sets the name of the component. */
     public void setName(String name) { this.name = name; }
 
-    /**
-     * Get the current layout context.
-     * 
-     * @throws StripesJspException If a {@link LayoutContext} is not found.
-     */
-    public LayoutContext getContext() throws StripesJspException {
-        if (context == null) {
-            context = LayoutContext.lookup(pageContext);
+    @Override
+    public void setPageContext(PageContext pageContext) {
+        // Call super method
+        super.setPageContext(pageContext);
 
-            if (context == null) {
-                throw new StripesJspException("A component tag named \"" + 
getName() + "\" in "
-                        + getCurrentPagePath() + " was unable to find a layout 
context.");
-            }
+        // Initialize the layout context and related fields
+        context = LayoutContext.lookup(pageContext);
 
-            log.trace("Component ", getName() + " has context ", 
context.getRenderPage(), " -> ",
-                    context.getDefinitionPage());
+        if (context == null) {
+            throw new StripesRuntimeException("A component tag named \"" + 
getName() + "\" in "
+                    + getCurrentPagePath() + " was unable to find a layout 
context.");
         }
 
-        return context;
-    }
+        log.trace("Component ", getName() + " has context ", 
context.getRenderPage(), " -> ",
+                context.getDefinitionPage());
 
-    /**
-     * True if this tag is a component that must execute so that the current 
component tag can
-     * execute. That is, this tag is a parent of the current component.
-     * 
-     * @throws StripesJspException if thrown by {@link #getContext()}.
-     */
-    protected boolean isPathComponent() throws StripesJspException {
-        List<String> path = getContext().getComponentPath();
-        return path == null ? false : isPathComponent(this, path.iterator());
+        silent = context.getOut().isSilent();
     }
 
     /**
-     * Recursive method called from {@link #isPathComponent()} that returns 
true if the specified
-     * tag's name is present in the component path iterator at the same 
position where this tag
-     * occurs in the render/component tag tree. For example, if the path 
iterator contains the
-     * component names {@code ["foo", "bar"]} then this method will return 
true if the tag's name is
-     * {@code "bar"} and it is a child of a render tag that is a child of a 
component tag whose name
-     * is {@code "foo"}.
-     * 
-     * @param tag The tag to check
-     * @param path The path to the check the tag against
-     * @return
-     */
-    protected boolean isPathComponent(LayoutComponentTag tag, Iterator<String> 
path) {
-        LayoutTag parent = tag.getLayoutParent();
-        if (parent instanceof LayoutRenderTag) {
-            parent = parent.getLayoutParent();
-            if (!(parent instanceof LayoutComponentTag) || parent instanceof 
LayoutComponentTag
-                    && isPathComponent((LayoutComponentTag) parent, path) && 
path.hasNext()) {
-                return tag.getName().equals(path.next());
-            }
-        }
-
-        return false;
-    }
-
-    /**
      * True if this tag is the component to be rendered on this pass from
      * {@link LayoutDefinitionTag}.
      * 
      * @throws StripesJspException If a {@link LayoutContext} is not found.
      */
     public boolean isCurrentComponent() throws StripesJspException {
-        final LayoutContext context = getContext();
         String name = context.getComponent();
         if (name == null || !name.equals(getName()))
             return false;
 
-        final List<String> want = context.getComponentPath();
-        if (want == null)
-            return true;
-
         final LayoutTag parent = getLayoutParent();
         if (!(parent instanceof LayoutRenderTag))
-            return false;
+            return context.getComponentPath().getComponentPath() == null;
 
-        final List<String> got = context.getPathToRenderTag((LayoutRenderTag) 
parent);
-        if (got == null)
-            return false;
-
-        return want.equals(got);
+        final LayoutRenderTagPath got = ((LayoutRenderTag) parent).getPath();
+        return got != null && got.equals(context.getComponentPath());
     }
 
     /**
@@ -154,9 +108,6 @@
     @Override
     public int doStartTag() throws JspException {
         try {
-            LayoutContext context = getContext();
-            silent = context.getOut().isSilent();
-
             if (context.isComponentRenderPhase()) {
                 if (isChildOfRender()) {
                     if (isCurrentComponent()) {
@@ -164,7 +115,7 @@
                         context.getOut().setSilent(false, pageContext);
                         return EVAL_BODY_INCLUDE;
                     }
-                    else if (isPathComponent()) {
+                    else if (context.getComponentPath().isPathComponent(this)) 
{
                         log.debug("Silently execute '", getName(), "' in ", 
context.getRenderPage());
                         context.getOut().setSilent(true, pageContext);
                         return EVAL_BODY_INCLUDE;
@@ -280,7 +231,6 @@
             // Set current component name back to null as a signal to the 
component tag within the
             // definition tag that the component did, indeed, render and it 
should not output the
             // default contents.
-            LayoutContext context = getContext();
             if (isCurrentComponent())
                 context.setComponent(null);
 

Modified: 
trunk/stripes/src/net/sourceforge/stripes/tag/layout/LayoutContext.java
===================================================================
--- trunk/stripes/src/net/sourceforge/stripes/tag/layout/LayoutContext.java     
2012-03-05 16:16:15 UTC (rev 1478)
+++ trunk/stripes/src/net/sourceforge/stripes/tag/layout/LayoutContext.java     
2012-03-05 16:19:23 UTC (rev 1479)
@@ -21,10 +21,7 @@
 import java.nio.CharBuffer;
 import java.nio.charset.Charset;
 import java.nio.charset.CharsetDecoder;
-import java.util.Collections;
 import java.util.HashMap;
-import java.util.LinkedList;
-import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
 
@@ -143,7 +140,7 @@
     private Map<String,LayoutComponentRenderer> components = new 
HashMap<String,LayoutComponentRenderer>();
     private Map<String,Object> parameters = new HashMap<String,Object>();
     private String renderPage, component;
-    private List<String> componentPath;
+    private LayoutRenderTagPath componentPath;
     private boolean componentRenderPhase, rendered;
 
     /**
@@ -155,37 +152,10 @@
     public LayoutContext(LayoutRenderTag renderTag) {
         this.renderTag = renderTag;
         this.renderPage = renderTag.getCurrentPagePath();
-
-        List<String> path = getPathToRenderTag(renderTag);
-        if (path != null) {
-            this.componentPath = Collections.unmodifiableList(path);
-            log.debug("Path is ", this.componentPath);
-        }
+        this.componentPath = new LayoutRenderTagPath(renderTag);
+        log.debug("Path is ", this.componentPath);
     }
 
-    /**
-     * Calculate the path to a render tag. The path is a list of names of 
components that must
-     * execute, in order, so that the specified render tag can execute.
-     * 
-     * @param tag The render tag.
-     * @return A list of component names or null if the render tag is not a 
child of a component.
-     */
-    public List<String> getPathToRenderTag(LayoutRenderTag tag) {
-        LinkedList<String> path = null;
-
-        for (LayoutTag parent = tag.getLayoutParent(); parent instanceof 
LayoutComponentTag;) {
-            if (path == null)
-                path = new LinkedList<String>();
-
-            path.addFirst(((LayoutComponentTag) parent).getName());
-
-            parent = parent.getLayoutParent();
-            parent = parent instanceof LayoutRenderTag ? 
parent.getLayoutParent() : null;
-        }
-
-        return path;
-    }
-
     /** Get the previous layout context from the stack. */
     public LayoutContext getPrevious() { return previous; }
 
@@ -447,7 +417,7 @@
      * Get the list of components in the render page that must execute so that 
the render tag that
      * created this context can execute.
      */
-    public List<String> getComponentPath() { return componentPath; }
+    public LayoutRenderTagPath getComponentPath() { return componentPath; }
 
     /** Get the layout writer to which the layout is rendered. */
     public LayoutWriter getOut() { return out; }

Modified: 
trunk/stripes/src/net/sourceforge/stripes/tag/layout/LayoutDefinitionTag.java
===================================================================
--- 
trunk/stripes/src/net/sourceforge/stripes/tag/layout/LayoutDefinitionTag.java   
    2012-03-05 16:16:15 UTC (rev 1478)
+++ 
trunk/stripes/src/net/sourceforge/stripes/tag/layout/LayoutDefinitionTag.java   
    2012-03-05 16:19:23 UTC (rev 1479)
@@ -20,7 +20,7 @@
 import javax.servlet.jsp.JspException;
 import javax.servlet.jsp.PageContext;
 
-import net.sourceforge.stripes.exception.StripesJspException;
+import net.sourceforge.stripes.exception.StripesRuntimeException;
 
 /**
  * On the surface, allows a developer to define a layout using a custom tag - 
but is actually
@@ -34,25 +34,23 @@
     private LayoutContext context;
     private boolean renderPhase, silent;
 
-    /**
-     * Get the current layout context.
-     * 
-     * @throws StripesJspException If there is no {@link LayoutContext} for 
this layout in the
-     *             current {@link PageContext}.
-     */
-    public LayoutContext getContext() throws StripesJspException {
-        if (context == null) {
-            context = LayoutContext.lookup(pageContext);
+    @Override
+    public void setPageContext(PageContext pageContext) {
+        // Call super method
+        super.setPageContext(pageContext);
+        
+        // Initialize layout context and related fields
+        context = LayoutContext.lookup(pageContext);
 
-            if (context == null || getLayoutParent() != null) {
-                throw new StripesJspException("The JSP page " + 
getCurrentPagePath()
-                        + " contains a layout-definition tag and was invoked 
directly. "
-                        + "A layout-definition can only be invoked by a page 
that contains "
-                        + "a layout-render tag.");
-            }
+        if (context == null || getLayoutParent() != null) {
+            throw new StripesRuntimeException("The JSP page " + 
getCurrentPagePath()
+                    + " contains a layout-definition tag and was invoked 
directly. "
+                    + "A layout-definition can only be invoked by a page that 
contains "
+                    + "a layout-render tag.");
         }
 
-        return context;
+        renderPhase = context.isComponentRenderPhase();
+        silent = context.getOut().isSilent();
     }
 
     /**
@@ -65,10 +63,6 @@
     @Override
     public int doStartTag() throws JspException {
         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);
 
@@ -100,7 +94,7 @@
     public int doEndTag() throws JspException {
         try {
             cleanUpComponentRenderers();
-            getContext().getOut().setSilent(silent, pageContext);
+            context.getOut().setSilent(silent, pageContext);
             return SKIP_PAGE;
         }
         catch (IOException e) {

Modified: 
trunk/stripes/src/net/sourceforge/stripes/tag/layout/LayoutRenderTag.java
===================================================================
--- trunk/stripes/src/net/sourceforge/stripes/tag/layout/LayoutRenderTag.java   
2012-03-05 16:16:15 UTC (rev 1478)
+++ trunk/stripes/src/net/sourceforge/stripes/tag/layout/LayoutRenderTag.java   
2012-03-05 16:19:23 UTC (rev 1479)
@@ -40,30 +40,47 @@
     private String name;
     private LayoutContext context;
     private boolean contextIsNew, silent;
+    private LayoutRenderTagPath path;
     private BodyContent bodyContent;
 
     /** Gets the name of the layout to be used. */
     public String getName() { return name; }
 
-    /** Sets the name of the layout to be used. */
-    public void setName(String name) { this.name = name; }
+    /** Sets the name of the layout to be used and then calls {@link 
#initialize()}. */
+    public void setName(String name) {
+        this.name = name;
+        initialize();
+    }
 
-    /** Look up an existing layout context or create a new one if none is 
found. */
-    public LayoutContext getContext() {
-        if (context == null) {
-            LayoutContext context = LayoutContext.lookup(pageContext);
+    /** Get the {@link LayoutRenderTagPath} that identifies this tag within 
the current page. */
+    public LayoutRenderTagPath getPath( ) { return path; }
 
-            boolean create = context == null || 
!context.isComponentRenderPhase()
-                    || isChildOfCurrentComponent();
+    /**
+     * Initialize fields before execution begins. Typically, this would be 
done by overriding
+     * {@link #setPageContext(javax.servlet.jsp.PageContext)}, but that isn't 
possible in this case
+     * because some of the logic depends on {@link #setName(String)} having 
been called, which does
+     * not happen until after {@link 
#setPageContext(javax.servlet.jsp.PageContext)} has been
+     * called.
+     */
+    protected void initialize() {
+        LayoutContext context = LayoutContext.lookup(pageContext);
 
-            if (create)
-                context = LayoutContext.push(this);
+        boolean create = context == null || !context.isComponentRenderPhase()
+                || isChildOfCurrentComponent();
 
-            this.context = context;
-            this.contextIsNew = create;
+        LayoutRenderTagPath path;
+        if (create) {
+            context = LayoutContext.push(this);
+            path = context.getComponentPath();
         }
+        else {
+            path = new LayoutRenderTagPath(this);
+        }
 
-        return context;
+        this.context = context;
+        this.contextIsNew = create;
+        this.path = path;
+        this.silent = context.getOut().isSilent();
     }
 
     /** Returns true if this tag is a child of the current component tag. */
@@ -81,7 +98,7 @@
 
     /** Used by the JSP container to provide the tag with dynamic attributes. 
*/
     public void setDynamicAttribute(String uri, String localName, Object 
value) throws JspException {
-        getContext().getParameters().put(localName, value);
+        context.getParameters().put(localName, value);
     }
 
     /**
@@ -98,9 +115,6 @@
     @Override
     public int doStartTag() throws JspException {
         try {
-            LayoutContext context = getContext();
-            silent = context.getOut().isSilent();
-
             if (contextIsNew) {
                 log.debug("Start layout init in ", context.getRenderPage());
                 pushPageContextAttributes(context.getParameters());
@@ -152,7 +166,6 @@
     @Override
        public int doEndTag() throws JspException {
         try {
-            LayoutContext context = getContext();
             if (contextIsNew) {
                 log.debug("End layout init in ", context.getRenderPage());
 
@@ -201,6 +214,7 @@
         finally {
             this.context = null;
             this.contextIsNew = false;
+            this.path = null;
             this.silent = false;
 
             if (this.bodyContent != null) {

Copied: 
trunk/stripes/src/net/sourceforge/stripes/tag/layout/LayoutRenderTagPath.java 
(from rev 1478, 
branches/1.5.x/stripes/src/net/sourceforge/stripes/tag/layout/LayoutRenderTagPath.java)
===================================================================
--- 
trunk/stripes/src/net/sourceforge/stripes/tag/layout/LayoutRenderTagPath.java   
                            (rev 0)
+++ 
trunk/stripes/src/net/sourceforge/stripes/tag/layout/LayoutRenderTagPath.java   
    2012-03-05 16:19:23 UTC (rev 1479)
@@ -0,0 +1,161 @@
+/* Copyright 2012 Ben Gunter
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package net.sourceforge.stripes.tag.layout;
+
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+
+import javax.servlet.jsp.PageContext;
+
+import net.sourceforge.stripes.exception.StripesJspException;
+
+/**
+ * Uniquely identifies a {@link LayoutRenderTag} within a page. Within a 
single page, any number of
+ * render tags can be accessible via the same "path," where a path consists of 
zero or more
+ * component tags that are parents of the render tag. This class helps to 
distinguish between
+ * multiple render tags with the same component path by assigning sequential 
indexes to them.
+ * 
+ * @author Ben Gunter
+ * @since Stripes 1.5.7
+ */
+public class LayoutRenderTagPath {
+    private List<String> componentPath;
+    private int index;
+
+    /** Construct a new instance to identify the specified tag. */
+    public LayoutRenderTagPath(LayoutRenderTag tag) {
+        this.componentPath = calculateComponentPath(tag);
+        this.index = incrementIndex(tag.getPageContext());
+    }
+
+    /**
+     * Calculate the path to a render tag. The path is a list of names of 
components that must
+     * execute, in order, so that the specified render tag can execute.
+     * 
+     * @param tag The render tag.
+     * @return A list of component names or null if the render tag is not a 
child of a component.
+     */
+    protected List<String> calculateComponentPath(LayoutRenderTag tag) {
+        LinkedList<String> path = null;
+
+        for (LayoutTag parent = tag.getLayoutParent(); parent instanceof 
LayoutComponentTag;) {
+            if (path == null)
+                path = new LinkedList<String>();
+
+            path.addFirst(((LayoutComponentTag) parent).getName());
+
+            parent = parent.getLayoutParent();
+            parent = parent instanceof LayoutRenderTag ? 
parent.getLayoutParent() : null;
+        }
+
+        return path;
+    }
+
+    /** Get the next index for this path from the specified page context. */
+    protected int incrementIndex(PageContext pageContext) {
+        String key = getClass().getName() + "#" + toStringWithoutIndex();
+        Integer index = (Integer) pageContext.getAttribute(key);
+        if (index == null)
+            index = 0;
+        else
+            ++index;
+        pageContext.setAttribute(key, index);
+        return index;
+    }
+
+    /** Get the names of the {@link LayoutComponentTag}s that are parent tags 
of the render tag. */
+    public List<String> getComponentPath() {
+        return componentPath;
+    }
+
+    /** Get the index (zero-based) of the combined render page and component 
path within the page. */
+    public int getIndex() {
+        return index;
+    }
+
+    /**
+     * True if the specified tag is a component that must execute so that the 
current component tag
+     * can execute. That is, this tag is a parent of the current component.
+     * 
+     * @param tag The tag to check to see if it is part of this path.
+     * @throws StripesJspException if thrown by {@link #getContext()}.
+     */
+    public boolean isPathComponent(LayoutComponentTag tag) throws 
StripesJspException {
+        List<String> path = getComponentPath();
+        return path == null ? false : isPathComponent(tag, path.iterator());
+    }
+
+    /**
+     * Recursive method called from {@link #isPathComponent()} that returns 
true if the specified
+     * tag's name is present in the component path iterator at the same 
position where this tag
+     * occurs in the render/component tag tree. For example, if the path 
iterator contains the
+     * component names {@code ["foo", "bar"]} then this method will return 
true if the tag's name is
+     * {@code "bar"} and it is a child of a render tag that is a child of a 
component tag whose name
+     * is {@code "foo"}.
+     * 
+     * @param tag The tag to check
+     * @param path The path to the check the tag against
+     * @return
+     */
+    protected boolean isPathComponent(LayoutComponentTag tag, Iterator<String> 
path) {
+        LayoutTag parent = tag.getLayoutParent();
+        if (parent instanceof LayoutRenderTag) {
+            parent = parent.getLayoutParent();
+            if (!(parent instanceof LayoutComponentTag) || parent instanceof 
LayoutComponentTag
+                    && isPathComponent((LayoutComponentTag) parent, path) && 
path.hasNext()) {
+                return tag.getName().equals(path.next());
+            }
+        }
+
+        return false;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        LayoutRenderTagPath that = (LayoutRenderTagPath) obj;
+        if (index != that.index)
+            return false;
+        if (componentPath == that.componentPath)
+            return true;
+        if (componentPath == null || that.componentPath == null)
+            return false;
+        return componentPath.equals(that.componentPath);
+    }
+
+    @Override
+    public int hashCode() {
+        return toString().hashCode();
+    }
+
+    @Override
+    public String toString() {
+        return toStringWithoutIndex() + '[' + index + ']';
+    }
+
+    /** Get a string representation of this instance without including the 
index. */
+    public String toStringWithoutIndex() {
+        if (componentPath == null)
+            return "";
+
+        StringBuilder s = new StringBuilder();
+        for (Iterator<String> it = componentPath.iterator(); it.hasNext();) {
+            s.append(it.next());
+            if (it.hasNext())
+                s.append('>');
+        }
+        return s.toString();
+    }
+}

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


------------------------------------------------------------------------------
Try before you buy = See our experts in action!
The most comprehensive online learning library for Microsoft developers
is just $99.99! Visual Studio, SharePoint, SQL - plus HTML5, CSS3, MVC3,
Metro Style Apps, more. Free future releases when you subscribe now!
http://p.sf.net/sfu/learndevnow-dev2
_______________________________________________
Stripes-development mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/stripes-development

Reply via email to