Revision: 1477
          http://stripes.svn.sourceforge.net/stripes/?rev=1477&view=rev
Author:   bengunter
Date:     2012-03-05 15:17:22 +0000 (Mon, 05 Mar 2012)
Log Message:
-----------
Fixed STS-871: Layout renders wrong component definition. Updated code can 
differentiate between two component tags with the same component path within a 
page.

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/LayoutContext.java
    
branches/1.5.x/stripes/src/net/sourceforge/stripes/tag/layout/LayoutRenderTag.java

Added Paths:
-----------
    
branches/1.5.x/stripes/src/net/sourceforge/stripes/tag/layout/LayoutRenderTagPath.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
       2012-02-17 14:45:57 UTC (rev 1476)
+++ 
branches/1.5.x/stripes/src/net/sourceforge/stripes/tag/layout/LayoutComponentTag.java
       2012-03-05 15:17:22 UTC (rev 1477)
@@ -15,8 +15,6 @@
 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;
@@ -71,42 +69,6 @@
     }
 
     /**
-     * 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());
-    }
-
-    /**
-     * 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}.
      * 
@@ -118,19 +80,12 @@
         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());
     }
 
     /**
@@ -164,7 +119,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;

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
    2012-02-17 14:45:57 UTC (rev 1476)
+++ 
branches/1.5.x/stripes/src/net/sourceforge/stripes/tag/layout/LayoutContext.java
    2012-03-05 15:17:22 UTC (rev 1477)
@@ -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: 
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
  2012-02-17 14:45:57 UTC (rev 1476)
+++ 
branches/1.5.x/stripes/src/net/sourceforge/stripes/tag/layout/LayoutRenderTag.java
  2012-03-05 15:17:22 UTC (rev 1477)
@@ -40,6 +40,7 @@
     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. */
@@ -48,6 +49,9 @@
     /** Sets the name of the layout to be used. */
     public void setName(String name) { this.name = name; }
 
+    /** Get the {@link LayoutRenderTagPath} that identifies this tag within 
the current page. */
+    public LayoutRenderTagPath getPath( ) { return path; }
+
     /** Look up an existing layout context or create a new one if none is 
found. */
     public LayoutContext getContext() {
         if (context == null) {
@@ -56,11 +60,18 @@
             boolean create = context == null || 
!context.isComponentRenderPhase()
                     || isChildOfCurrentComponent();
 
-            if (create)
+            LayoutRenderTagPath path;
+            if (create) {
                 context = LayoutContext.push(this);
+                path = context.getComponentPath();
+            }
+            else {
+                path = new LayoutRenderTagPath(this);
+            }
 
             this.context = context;
             this.contextIsNew = create;
+            this.path = path;
         }
 
         return context;
@@ -201,6 +212,7 @@
         finally {
             this.context = null;
             this.contextIsNew = false;
+            this.path = null;
             this.silent = false;
 
             if (this.bodyContent != null) {

Added: 
branches/1.5.x/stripes/src/net/sourceforge/stripes/tag/layout/LayoutRenderTagPath.java
===================================================================
--- 
branches/1.5.x/stripes/src/net/sourceforge/stripes/tag/layout/LayoutRenderTagPath.java
                              (rev 0)
+++ 
branches/1.5.x/stripes/src/net/sourceforge/stripes/tag/layout/LayoutRenderTagPath.java
      2012-03-05 15:17:22 UTC (rev 1477)
@@ -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