TILES-103
Refactored attribute list JSP tags hierarchy.

git-svn-id: https://svn.apache.org/repos/asf/tiles/framework/trunk@507986 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/tiles-core/src/main/java/org/apache/tiles/taglib/AddAttributeTag.java b/tiles-core/src/main/java/org/apache/tiles/taglib/AddAttributeTag.java
new file mode 100644
index 0000000..a099929
--- /dev/null
+++ b/tiles-core/src/main/java/org/apache/tiles/taglib/AddAttributeTag.java
@@ -0,0 +1,141 @@
+/*
+ * $Id$
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.tiles.taglib;
+
+import org.apache.tiles.taglib.ContainerTagSupport;
+import org.apache.tiles.taglib.ComponentConstants;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import javax.servlet.jsp.JspException;
+import javax.servlet.jsp.PageContext;
+import javax.servlet.jsp.tagext.TagSupport;
+
+/**
+ * <p><strong>Adds an attribute in enclosing attribute container tag.</strong></p>
+ * <p>Enclosing attribute container tag can be : 
+ * <ul>
+ * <li>&lt;putListAttribute&gt;</li> 
+ * <li>&lt;putAttribute&gt;</li> 
+ * </ul>
+ * (or any other tag which implements the <code>{@link AddAttributeTagParent}</code> interface.
+ * Exception is thrown if no appropriate tag can be found.</p>
+ * <p>Put tag can have following atributes :
+ * <ul>
+ * <li>name : Name of the attribute</li>
+ * <li>value : value to put as attribute</li>
+ * <li>type : value type. Only valid if value is a String and is set by
+ * value="something" or by a bean.
+ * Possible type are : string (value is used as direct string),
+ * template (value is used as a page url to insert),
+ * definition (value is used as a definition name to insert)</li>
+ * <li>role : Role to check when 'insert' will be called. If enclosing tag is
+ * &lt;insert&gt;, role is checked immediately. If enclosing tag is
+ * &lt;definition&gt;, role will be checked when this definition will be
+ * inserted.</li>
+ * </ul></p>
+ * <p>Value can also come from tag body. Tag body is taken into account only if
+ * value is not set by one of the tag attributes. In this case Attribute type is
+ * "string", unless tag body define another type.</p>
+ *
+ * @version $Rev$ $Date$
+ */
+public class AddAttributeTag extends ContainerTagSupport implements ComponentConstants {
+
+    private static final Log LOG = LogFactory.getLog(AddAttributeTag.class);
+
+    /**
+     * Associated attribute value.
+     */
+    private Object value = null;
+
+    /**
+     * Requested type for the value.
+     */
+    private String type = null;
+
+    public Object getValue() {
+        return value;
+    }
+
+    public void setValue(Object value) {
+        this.value = value;
+    }
+
+    public String getType() {
+        return type;
+    }
+
+    public void setType(String type) {
+        this.type = type;
+    }
+
+    /**
+     * Release all allocated resources.
+     */
+    public void release() {
+        super.release();
+        value = null;
+        type = null;
+    }
+
+    /**
+     * Save the body content of this tag (if any)
+     *
+     * @throws JspException if a JSP exception has occurred
+     */
+    public int doAfterBody() throws JspException {
+        if (bodyContent != null) {
+            value = bodyContent.getString();
+            type = "string";
+        }
+        return (SKIP_BODY);
+    }
+
+    @Override
+    protected void startContext(PageContext context) {
+        if (container != null) {
+            componentContext = container.getComponentContext(context);
+        }
+    }
+
+    @Override
+    protected void endContext(PageContext context) {
+        // Do nothing
+    }
+
+    protected void execute() throws JspException {
+        AddAttributeTagParent parent = (AddAttributeTagParent)
+            TagSupport.findAncestorWithClass(this, AddAttributeTagParent.class);
+
+
+        if (parent == null) {
+            String message = "Error: enclosing tag '"
+                +getParent().getClass().getName()+" doesn't accept 'put' tag.";
+            LOG.error(message);
+            throw new JspException(message);
+        }
+
+        parent.processNestedTag(this);
+    }
+}
diff --git a/tiles-core/src/main/java/org/apache/tiles/taglib/AddAttributeTagParent.java b/tiles-core/src/main/java/org/apache/tiles/taglib/AddAttributeTagParent.java
new file mode 100644
index 0000000..8c40020
--- /dev/null
+++ b/tiles-core/src/main/java/org/apache/tiles/taglib/AddAttributeTagParent.java
@@ -0,0 +1,41 @@
+/*
+ * $Id$
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.tiles.taglib;
+
+import javax.servlet.jsp.JspException;
+
+/**
+ * Tag classes implementing this interface can contain nested {@link AddAttributeTag}.
+ * This interface defines a method called by nested tags.
+ *
+ * @version $Rev$ $Date$
+ */
+public interface AddAttributeTagParent {
+    /**
+     * Process the nested tag.
+     *
+     * @param nestedTag Nested tag to process.
+     */
+    void processNestedTag(AddAttributeTag nestedTag) throws JspException;
+
+}
diff --git a/tiles-core/src/main/java/org/apache/tiles/taglib/AddListAttributeTag.java b/tiles-core/src/main/java/org/apache/tiles/taglib/AddListAttributeTag.java
new file mode 100644
index 0000000..fb496af
--- /dev/null
+++ b/tiles-core/src/main/java/org/apache/tiles/taglib/AddListAttributeTag.java
@@ -0,0 +1,110 @@
+/*
+ * $Id$
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.tiles.taglib;
+
+import org.apache.tiles.ComponentAttribute;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.servlet.jsp.JspException;
+import javax.servlet.jsp.PageContext;
+
+/**
+ * AddListAttribute tag implementation.
+ *
+ * @since Tiles 1.0
+ * @version $Rev$ $Date$
+ */
+public class AddListAttributeTag extends AddAttributeTag
+    implements AddAttributeTagParent {
+
+    /**
+     * Get list defined in tag.
+     */
+    @SuppressWarnings("unchecked")
+    public List<ComponentAttribute> getValue() {
+        return (List<ComponentAttribute>) super.getValue();
+    }
+
+    public void setValue(Object object) {
+        throw new IllegalStateException("The value of the PutListAttributeTag must be the originally defined list.");
+    }
+
+    public int doStartTag() {
+        super.setValue(new ArrayList<ComponentAttribute>());
+    	return super.doStartTag();
+    }
+    /**
+     * PutListAttributeTag may not have any body, except for PutAttribute tags.
+     *
+     * @throws JspException if a JSP exception has occurred
+     */
+    public int doAfterBody() throws JspException {
+        return (SKIP_BODY);
+    }
+    
+    /**
+     * Release the state of this put list by
+     * clearing the contents of the list.
+     */
+    public void release() {
+        super.setValue(null);
+        super.release();
+    }
+
+    /**
+     * Process nested &lg;addAttribute&gt; tag.
+     * <p/>
+     * Places the value of the nested tag within the
+     * {@link org.apache.tiles.ComponentContext}.It is the responsibility
+     * of the descendent to check security.  Tags extending
+     * the {@link org.apache.tiles.taglib.ContainerTagSupport} will automatically provide
+     * the appropriate security.
+     *
+     * @param nestedTag the put tag desciendent.
+     */
+    public void processNestedTag(AddAttributeTag nestedTag) {
+        ComponentAttribute attribute = new ComponentAttribute(
+            nestedTag.getValue(), nestedTag.getRole(),
+            nestedTag.getType());
+
+        this.addValue(attribute);	
+    }
+
+    @Override
+    protected void startContext(PageContext context) {
+        if (container != null) {
+            componentContext = container.getComponentContext(context);
+        }
+    }
+
+    @Override
+    protected void endContext(PageContext context) {
+        // Do nothing
+    }
+
+	private void addValue( ComponentAttribute attribute ) {
+		this.getValue().add(attribute);
+	}
+}
diff --git a/tiles-core/src/main/java/org/apache/tiles/taglib/PutAttributeTagParent.java b/tiles-core/src/main/java/org/apache/tiles/taglib/PutAttributeTagParent.java
index 865b8b8..08f4ee3 100644
--- a/tiles-core/src/main/java/org/apache/tiles/taglib/PutAttributeTagParent.java
+++ b/tiles-core/src/main/java/org/apache/tiles/taglib/PutAttributeTagParent.java
@@ -28,7 +28,7 @@
 import javax.servlet.jsp.JspException;
 
 /**
- * Tag classes implementing this interface can contain nested PutTag.
+ * Tag classes implementing this interface can contain nested {@link PutAttributeTag}.
  * This interface defines a method called by nested tags.
  *
  * @version $Rev$ $Date$
diff --git a/tiles-core/src/main/java/org/apache/tiles/taglib/PutListAttributeTag.java b/tiles-core/src/main/java/org/apache/tiles/taglib/PutListAttributeTag.java
index 51ffe48..578770e 100644
--- a/tiles-core/src/main/java/org/apache/tiles/taglib/PutListAttributeTag.java
+++ b/tiles-core/src/main/java/org/apache/tiles/taglib/PutListAttributeTag.java
@@ -23,7 +23,6 @@
 package org.apache.tiles.taglib;
 
 import org.apache.tiles.ComponentAttribute;
-import org.apache.tiles.taglib.PutAttributeTagParent;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -38,11 +37,12 @@
  * @version $Rev$ $Date$
  */
 public class PutListAttributeTag extends PutAttributeTag
-    implements PutAttributeTagParent {
+    implements AddAttributeTagParent {
 
     /**
      * Get list defined in tag.
      */
+    @SuppressWarnings("unchecked")
     public List<ComponentAttribute> getValue() {
         return (List<ComponentAttribute>) super.getValue();
     }
@@ -84,7 +84,7 @@
      *
      * @param nestedTag the put tag desciendent.
      */
-    public void processNestedTag(PutAttributeTag nestedTag) {
+    public void processNestedTag(AddAttributeTag nestedTag) {
         ComponentAttribute attribute = new ComponentAttribute(
             nestedTag.getValue(), nestedTag.getRole(),
             nestedTag.getType());
diff --git a/tiles-core/src/main/resources/META-INF/tld/tiles-core.tld b/tiles-core/src/main/resources/META-INF/tld/tiles-core.tld
index 308c005..9c07903 100644
--- a/tiles-core/src/main/resources/META-INF/tld/tiles-core.tld
+++ b/tiles-core/src/main/resources/META-INF/tld/tiles-core.tld
@@ -389,9 +389,9 @@
 		<li>&lt;definition&gt;</li> 
 		<li>&lt;insertAttribute&gt;</li> 
 		<li>&lt;insertDefinition&gt;</li>
-		<li>&lt;putList&gt;</li>
+		<li>&lt;putListAttribute&gt;</li>
 		</ul>
-		(or any other tag which implements the <code>{@link PutTagParent}</code> interface.
+		(or any other tag which implements the <code>{@link PutAttributeTagParent}</code> interface.
 		Exception is thrown if no appropriate tag can be found.</p>
 		<p>Put tag can have following atributes :
 		<ul>
@@ -422,7 +422,7 @@
       </description>
       <attribute>
          <name>name</name>
-         <required>false</required>
+         <required>true</required>
          <rtexprvalue>true</rtexprvalue>
          <description>
          <![CDATA[
@@ -498,14 +498,14 @@
       </attribute>
    </tag>
    <tag>
-      <name>add</name>
+      <name>addAttribute</name>
        <!--
            Intentionally PutTag, it doubles for the AddTag
            The only difference between the two is that the name
            is not used in the Add Tag (and it's only valid within
            the PutList
         -->
-      <tag-class>org.apache.tiles.taglib.PutAttributeTag</tag-class>
+      <tag-class>org.apache.tiles.taglib.AddAttributeTag</tag-class>
       <body-content>JSP</body-content>
       <description>
       <![CDATA[
@@ -560,6 +560,20 @@
       </attribute>
    </tag>
    <tag>
+      <name>addListAttribute</name>
+      <tag-class>org.apache.tiles.taglib.AddListAttributeTag</tag-class>
+      <body-content>JSP</body-content>
+      <description>
+      <![CDATA[
+      <p><strong>Declare a list that will be pass as attribute to tile.
+      </strong></p>
+      <p>Declare a list that will be pass as attribute to tile.
+      List elements are added using the tag 'add'.
+      This tag can only be used inside 'insert' or 'definition' tag.</p>
+      ]]>
+      </description>
+   </tag>
+   <tag>
       <name>getAsString</name>
       <tag-class>org.apache.tiles.taglib.GetAsStringTag</tag-class>
       <body-content>empty</body-content>
diff --git a/tiles-test/src/main/webapp/testputlist.jsp b/tiles-test/src/main/webapp/testputlist.jsp
index 7fea6a5..2486927 100644
--- a/tiles-test/src/main/webapp/testputlist.jsp
+++ b/tiles-test/src/main/webapp/testputlist.jsp
@@ -26,8 +26,8 @@
 <tiles:insertTemplate template="/putattributeslayout.jsp">
   <tiles:putAttribute name="stringTest" value="This is a string" type="string" />
   <tiles:putListAttribute name="list">
-    <tiles:putAttribute value="valueOne" type="string" />
-    <tiles:putAttribute value="valueTwo" type="string" />
-    <tiles:putAttribute value="valueThree" type="string" />
+    <tiles:addAttribute value="valueOne" type="string" />
+    <tiles:addAttribute value="valueTwo" type="string" />
+    <tiles:addAttribute value="valueThree" type="string" />
   </tiles:putListAttribute>
 </tiles:insertTemplate>
\ No newline at end of file