Author: apetrelli
Date: Wed Jun 24 16:05:28 2009
New Revision: 788065

URL: http://svn.apache.org/viewvc?rev=788065&view=rev
Log:
TILES-429
Now attributes are deep copied in the BasicAttributeContext copy constructor.

Modified:
    
tiles/framework/trunk/tiles-api/src/main/java/org/apache/tiles/Attribute.java
    
tiles/framework/trunk/tiles-api/src/main/java/org/apache/tiles/BasicAttributeContext.java
    
tiles/framework/trunk/tiles-api/src/main/java/org/apache/tiles/ListAttribute.java
    
tiles/framework/trunk/tiles-api/src/test/java/org/apache/tiles/BasicAttributeContextTest.java

Modified: 
tiles/framework/trunk/tiles-api/src/main/java/org/apache/tiles/Attribute.java
URL: 
http://svn.apache.org/viewvc/tiles/framework/trunk/tiles-api/src/main/java/org/apache/tiles/Attribute.java?rev=788065&r1=788064&r2=788065&view=diff
==============================================================================
--- 
tiles/framework/trunk/tiles-api/src/main/java/org/apache/tiles/Attribute.java 
(original)
+++ 
tiles/framework/trunk/tiles-api/src/main/java/org/apache/tiles/Attribute.java 
Wed Jun 24 16:05:28 2009
@@ -34,7 +34,7 @@
  *
  * @version $Rev$ $Date$
  */
-public class Attribute implements Serializable {
+public class Attribute implements Serializable, Cloneable {
 
     /**
      * The name of the template renderer.
@@ -572,4 +572,10 @@
         return nullSafeHashCode(value) + nullSafeHashCode(renderer)
                 + nullSafeHashCode(roles) + nullSafeHashCode(expressionObject);
     }
+
+    /** {...@inheritdoc} */
+    @Override
+    public Attribute clone() {
+        return new Attribute(this);
+    }
 }

Modified: 
tiles/framework/trunk/tiles-api/src/main/java/org/apache/tiles/BasicAttributeContext.java
URL: 
http://svn.apache.org/viewvc/tiles/framework/trunk/tiles-api/src/main/java/org/apache/tiles/BasicAttributeContext.java?rev=788065&r1=788064&r2=788065&view=diff
==============================================================================
--- 
tiles/framework/trunk/tiles-api/src/main/java/org/apache/tiles/BasicAttributeContext.java
 (original)
+++ 
tiles/framework/trunk/tiles-api/src/main/java/org/apache/tiles/BasicAttributeContext.java
 Wed Jun 24 16:05:28 2009
@@ -82,7 +82,7 @@
      */
     public BasicAttributeContext(Map<String, Attribute> attributes) {
         if (attributes != null) {
-            this.attributes = new HashMap<String, Attribute>(attributes);
+            this.attributes = deepCopyAttributeMap(attributes);
         }
     }
 
@@ -103,7 +103,7 @@
             this.preparer = context.getPreparer();
             this.attributes = new HashMap<String, Attribute>();
             for (String name : context.getLocalAttributeNames()) {
-                attributes.put(name, context.getLocalAttribute(name));
+                attributes.put(name, new 
Attribute(context.getLocalAttribute(name)));
             }
             inheritCascadedAttributes(context);
         }
@@ -146,8 +146,8 @@
         } else {
             this.cascadedAttributes = new HashMap<String, Attribute>();
             for (String name : context.getCascadedAttributeNames()) {
-                cascadedAttributes
-                        .put(name, context.getCascadedAttribute(name));
+                cascadedAttributes.put(name, new Attribute(context
+                        .getCascadedAttribute(name)));
             }
         }
     }
@@ -405,7 +405,7 @@
         }
         preparer = context.preparer;
         if (context.attributes != null && !context.attributes.isEmpty()) {
-            attributes = new HashMap<String, Attribute>(context.attributes);
+            attributes = deepCopyAttributeMap(context.attributes);
         }
         copyCascadedAttributes(context);
     }
@@ -418,8 +418,7 @@
     private void copyCascadedAttributes(BasicAttributeContext context) {
         if (context.cascadedAttributes != null
                 && !context.cascadedAttributes.isEmpty()) {
-            cascadedAttributes = new HashMap<String, Attribute>(
-                    context.cascadedAttributes);
+            cascadedAttributes = 
deepCopyAttributeMap(context.cascadedAttributes);
         }
     }
 
@@ -452,4 +451,23 @@
 
         return destination;
     }
+
+    /**
+     * Deep copies the attribute map, by creating clones (using copy
+     * constructors) of the attributes.
+     *
+     * @param attributes The attribute map to copy.
+     * @return The copied map.
+     */
+    private Map<String, Attribute> deepCopyAttributeMap(
+            Map<String, Attribute> attributes) {
+        Map<String, Attribute> retValue = new HashMap<String, 
Attribute>(attributes.size());
+        for (Map.Entry<String, Attribute> entry : attributes.entrySet()) {
+            Attribute toCopy = entry.getValue();
+            if (toCopy != null) {
+                retValue.put(entry.getKey(), toCopy.clone());
+            }
+        }
+        return retValue;
+    }
 }

Modified: 
tiles/framework/trunk/tiles-api/src/main/java/org/apache/tiles/ListAttribute.java
URL: 
http://svn.apache.org/viewvc/tiles/framework/trunk/tiles-api/src/main/java/org/apache/tiles/ListAttribute.java?rev=788065&r1=788064&r2=788065&view=diff
==============================================================================
--- 
tiles/framework/trunk/tiles-api/src/main/java/org/apache/tiles/ListAttribute.java
 (original)
+++ 
tiles/framework/trunk/tiles-api/src/main/java/org/apache/tiles/ListAttribute.java
 Wed Jun 24 16:05:28 2009
@@ -64,6 +64,17 @@
     }
 
     /**
+     * Copy constructor.
+     *
+     * @param toCopy The list attribute to copy.
+     * @since 2.1.3
+     */
+    public ListAttribute(ListAttribute toCopy) {
+        super(toCopy);
+        this.inherit = toCopy.inherit;
+    }
+
+    /**
      * Add an element in list.
      * We use a property to avoid rewriting a new class.
      *
@@ -142,4 +153,23 @@
         tempList.addAll((List<Object>) value);
         setValue(tempList);
     }
+
+    /** {...@inheritdoc} */
+    @Override
+    public boolean equals(Object obj) {
+        ListAttribute attribute = (ListAttribute) obj;
+        return super.equals(attribute) && this.inherit == attribute.inherit;
+    }
+
+    /** {...@inheritdoc} */
+    @Override
+    public int hashCode() {
+        return super.hashCode() + Boolean.valueOf(inherit).hashCode();
+    }
+
+    /** {...@inheritdoc} */
+    @Override
+    public ListAttribute clone() {
+        return new ListAttribute(this);
+    }
 }

Modified: 
tiles/framework/trunk/tiles-api/src/test/java/org/apache/tiles/BasicAttributeContextTest.java
URL: 
http://svn.apache.org/viewvc/tiles/framework/trunk/tiles-api/src/test/java/org/apache/tiles/BasicAttributeContextTest.java?rev=788065&r1=788064&r2=788065&view=diff
==============================================================================
--- 
tiles/framework/trunk/tiles-api/src/test/java/org/apache/tiles/BasicAttributeContextTest.java
 (original)
+++ 
tiles/framework/trunk/tiles-api/src/test/java/org/apache/tiles/BasicAttributeContextTest.java
 Wed Jun 24 16:05:28 2009
@@ -20,6 +20,7 @@
  */
 package org.apache.tiles;
 
+import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.LinkedHashSet;
@@ -443,4 +444,36 @@
         assertTrue("There are cascaded attributes", names == null
                 || names.isEmpty());
     }
+
+    /**
+     * Tests {...@link BasicAttributeContext} for the TILES-429 bug.
+     */
+    public void testTiles429() {
+        AttributeContext toCopy = new BasicAttributeContext();
+        toCopy.putAttribute("name1", new Attribute("value1"), false);
+        toCopy.putAttribute("name2", new Attribute("value2"), true);
+        List<Object> listOfObjects = new ArrayList<Object>();
+        listOfObjects.add(1);
+        ListAttribute listAttribute = new ListAttribute(listOfObjects);
+        listAttribute.setInherit(true);
+        toCopy.putAttribute("name3", listAttribute);
+        Attribute templateAttribute = Attribute
+                .createTemplateAttribute("/template.jsp");
+        Set<String> roles = new HashSet<String>();
+        roles.add("role1");
+        roles.add("role2");
+        templateAttribute.setRoles(roles);
+        toCopy.setTemplateAttribute(templateAttribute);
+        toCopy.setPreparer("my.preparer.Preparer");
+        AttributeContext context = new BasicAttributeContext(toCopy);
+        Attribute attribute = context.getAttribute("name1");
+        attribute.setValue("newValue1");
+        attribute = context.getAttribute("name1");
+        assertEquals("newValue1", attribute.getValue());
+        attribute = toCopy.getAttribute("name1");
+        assertEquals("value1", attribute.getValue());
+        attribute = context.getAttribute("name3");
+        assertTrue(attribute instanceof ListAttribute);
+        assertTrue(((ListAttribute) attribute).isInherit());
+    }
 }


Reply via email to