Author: hlship
Date: Thu Oct 30 17:18:24 2008
New Revision: 709306

URL: http://svn.apache.org/viewvc?rev=709306&view=rev
Log:
TAP54-34: When using a Grid inside a Form, sorting the Grid may cause updates 
(when the form is submitted) to be applied to the wrong objects

Added:
    tapestry/tapestry5/trunk/tapestry-core/src/test/app1/GridFormEncoderDemo.tml
    
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/GridFormEncoderDemo.java
Modified:
    
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/Grid.java
    
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/Grid.xdoc
    
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/GridRows.java
    
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/Loop.xdoc
    
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ComponentClassTransformerImpl.java
    
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/util/DefaultPrimaryKeyEncoder.java
    tapestry/tapestry5/trunk/tapestry-core/src/test/app1/GridFormDemo.tml
    
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/IntegrationTests.java
    
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/GridFormDemo.java
    
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/Start.java
    
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/services/ToDoDatabase.java
    
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/services/ToDoDatabaseImpl.java
    tapestry/tapestry5/trunk/tapestry-core/src/test/resources/log4j.properties
    
tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/CtClassSourceImpl.java

Modified: 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/Grid.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/Grid.java?rev=709306&r1=709305&r2=709306&view=diff
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/Grid.java
 (original)
+++ 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/Grid.java
 Thu Oct 30 17:18:24 2008
@@ -42,8 +42,10 @@
  * A Grid may operate inside a [EMAIL PROTECTED] 
org.apache.tapestry5.corelib.components.Form}. By overriding the cell renderers 
of
  * properties, the default output-only behavior can be changed to produce a 
complex form with individual control for
  * editing properties of each row. This is currently workable but less than 
ideal -- if the order of rows provided by
- * the [EMAIL PROTECTED] GridDataSource} changes between render and form 
submission, then there's the possibility that data will be
- * applied to the wrong server-side objects.
+ * the [EMAIL PROTECTED] org.apache.tapestry5.grid.GridDataSource} changes 
between render and form submission, then there's the
+ * possibility that data will be applied to the wrong server-side objects. In 
general, when using Grid and Form
+ * together, you want to provide the Grid with a [EMAIL PROTECTED] 
org.apache.tapestry5.PrimaryKeyEncoder} (via the encoder
+ * parameter).
  *
  * @see org.apache.tapestry5.beaneditor.BeanModel
  * @see org.apache.tapestry5.services.BeanModelSource
@@ -204,6 +206,14 @@
     private boolean inPlace;
 
     /**
+     * Changes how state is recorded into the form to store the [EMAIL 
PROTECTED] org.apache.tapestry5.PrimaryKeyEncoder#toKey(Object)
+     * primary key} for each row (rather than the index), and restore the 
[EMAIL PROTECTED]
+     * org.apache.tapestry5.PrimaryKeyEncoder#toValue(java.io.Serializable) 
row values} from the primary keys.
+     */
+    @Parameter
+    private PrimaryKeyEncoder encoder;
+
+    /**
      * The name of the psuedo-zone that encloses the Grid.
      */
     @Property(write = false)
@@ -229,7 +239,6 @@
     @Environmental
     private ClientBehaviorSupport clientBehaviorSupport;
 
-    @SuppressWarnings("unused")
     @Component(
             parameters = {
                     "index=inherit:columnIndex",
@@ -238,7 +247,6 @@
                     "zone=zone"})
     private GridColumns columns;
 
-    @SuppressWarnings("unused")
     @Component(
             parameters = {
                     "rowIndex=inherit:rowIndex",
@@ -249,6 +257,7 @@
                     "row=row",
                     "overrides=overrides",
                     "volatile=inherit:volatile",
+                    "encoder=inherit:encoder",
                     "lean=inherit:lean"})
     private GridRows rows;
 
@@ -259,15 +268,12 @@
             "zone=zone"})
     private GridPager pager;
 
-    @SuppressWarnings("unused")
     @Component(parameters = "to=pagerTop")
     private Delegate pagerTop;
 
-    @SuppressWarnings("unused")
     @Component(parameters = "to=pagerBottom")
     private Delegate pagerBottom;
 
-    @SuppressWarnings("unused")
     @Component(parameters = "class=tableClass", inheritInformalParameters = 
true)
     private Any table;
 
@@ -297,17 +303,24 @@
     /**
      * A version of GridDataSource that caches the availableRows property. 
This addresses TAPESTRY-2245.
      */
-    class CachingDataSource implements GridDataSource
+    static class CachingDataSource implements GridDataSource
     {
+        private final GridDataSource delegate;
+
         private boolean availableRowsCached;
 
         private int availableRows;
 
+        CachingDataSource(GridDataSource delegate)
+        {
+            this.delegate = delegate;
+        }
+
         public int getAvailableRows()
         {
             if (!availableRowsCached)
             {
-                availableRows = source.getAvailableRows();
+                availableRows = delegate.getAvailableRows();
                 availableRowsCached = true;
             }
 
@@ -316,17 +329,17 @@
 
         public void prepare(int startIndex, int endIndex, List<SortConstraint> 
sortConstraints)
         {
-            source.prepare(startIndex, endIndex, sortConstraints);
+            delegate.prepare(startIndex, endIndex, sortConstraints);
         }
 
         public Object getRowValue(int index)
         {
-            return source.getRowValue(index);
+            return delegate.getRowValue(index);
         }
 
         public Class getRowType()
         {
-            return source.getRowType();
+            return delegate.getRowType();
         }
     }
 
@@ -449,7 +462,12 @@
 
     void setupDataSource()
     {
-        cachingSource = new CachingDataSource();
+        // TAP5-34: We pass the source into the CachingDataSource now; 
previously
+        // we were accessing source directly, but during submit the value 
wasn't
+        // cached, and therefore access was very inefficient, and sorting was
+        // very inconsistent during the processing of the form submission.
+
+        cachingSource = new CachingDataSource(source);
 
         int availableRows = cachingSource.getAvailableRows();
 

Modified: 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/Grid.xdoc
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/Grid.xdoc?rev=709306&r1=709305&r2=709306&view=diff
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/Grid.xdoc
 (original)
+++ 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/Grid.xdoc
 Thu Oct 30 17:18:24 2008
@@ -3,10 +3,13 @@
         <section name="Related Components">
             <ul>
                 <li>
-                    <a href="BeanEditForm">BeanEditForm</a>
+                    <a href="BeanEditForm.html">BeanEditForm</a>
                 </li>
                 <li>
-                    <a href="BeanDisplay">BeanDisplay</a>
+                    <a href="BeanDisplay.html">BeanDisplay</a>
+                </li>
+                <li>
+                    <a href="Loop.html"></a>
                 </li>
             </ul>
         </section>

Modified: 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/GridRows.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/GridRows.java?rev=709306&r1=709305&r2=709306&view=diff
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/GridRows.java
 (original)
+++ 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/GridRows.java
 Thu Oct 30 17:18:24 2008
@@ -28,6 +28,7 @@
 package org.apache.tapestry5.corelib.components;
 
 import org.apache.tapestry5.ComponentAction;
+import org.apache.tapestry5.PrimaryKeyEncoder;
 import org.apache.tapestry5.PropertyOverrides;
 import org.apache.tapestry5.annotations.Environmental;
 import org.apache.tapestry5.annotations.Parameter;
@@ -40,6 +41,7 @@
 import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
 import org.apache.tapestry5.services.FormSupport;
 
+import java.io.Serializable;
 import java.util.List;
 
 /**
@@ -50,17 +52,24 @@
  * form render and the form submission, this can cause unexpected results, 
including applying changes to the wrong
  * objects.
  */
[EMAIL PROTECTED]({"unchecked"})
 public class GridRows
 {
     private int startRow;
 
-    static class SetupForRow implements ComponentAction<GridRows>
+    private boolean recordStateByIndex;
+    private boolean recordStateByEncoder;
+
+    /**
+     * This action is used when a [EMAIL PROTECTED] 
org.apache.tapestry5.PrimaryKeyEncoder} is not.
+     */
+    static class SetupForRowByIndex implements ComponentAction<GridRows>
     {
         private static final long serialVersionUID = -3216282071752371975L;
 
         private final int rowIndex;
 
-        public SetupForRow(int rowIndex)
+        public SetupForRowByIndex(int rowIndex)
         {
             this.rowIndex = rowIndex;
         }
@@ -73,7 +82,57 @@
         @Override
         public String toString()
         {
-            return String.format("GridRows.SetupForRow[%d]", rowIndex);
+            return String.format("GridRows.SetupForRowByIndex[%d]", rowIndex);
+        }
+    }
+
+    /**
+     * This action is used when a [EMAIL PROTECTED] 
org.apache.tapestry5.PrimaryKeyEncoder} is provided.
+     */
+    static class SetupForRowByKey implements ComponentAction<GridRows>
+    {
+        private final Serializable rowKey;
+
+        SetupForRowByKey(Serializable rowKey)
+        {
+            this.rowKey = rowKey;
+        }
+
+        public void execute(GridRows component)
+        {
+            component.setupForRowByKey(rowKey);
+        }
+
+        @Override
+        public String toString()
+        {
+            return String.format("GridRows.SetupForRowByKey[%s]", rowKey);
+        }
+    }
+
+
+    /**
+     * This action is also associated with the [EMAIL PROTECTED] 
org.apache.tapestry5.PrimaryKeyEncoder}; it allows the PKE to be
+     * informed of the series of keys to expect with the form submission.
+     */
+    static class PrepareForKeys implements ComponentAction<GridRows>
+    {
+        private List<Serializable> storedKeys;
+
+        public PrepareForKeys(List<Serializable> storedKeys)
+        {
+            this.storedKeys = storedKeys;
+        }
+
+        public void execute(GridRows component)
+        {
+            component.prepareForKeys(storedKeys);
+        }
+
+        @Override
+        public String toString()
+        {
+            return "GridRows.PrepareForKeys" + storedKeys.toString();
         }
     }
 
@@ -133,6 +192,14 @@
     private boolean volatileState;
 
     /**
+     * Changes how state is recorded into the form to store the [EMAIL 
PROTECTED] org.apache.tapestry5.PrimaryKeyEncoder#toKey(Object)
+     * primary key} for each row (rather than the index), and restore the 
[EMAIL PROTECTED]
+     * org.apache.tapestry5.PrimaryKeyEncoder#toValue(java.io.Serializable) 
row values} from the primary keys.
+     */
+    @Parameter
+    private PrimaryKeyEncoder encoder;
+
+    /**
      * Optional output parameter (only set during rendering) that identifies 
the current row index. This is the index on
      * the page (i.e., always numbered from zero) as opposed to the row index 
inside the [EMAIL PROTECTED]
      * org.apache.tapestry5.grid.GridDataSource}.
@@ -147,11 +214,9 @@
     @Property
     private int columnIndex;
 
-
     @Environmental(false)
     private FormSupport formSupport;
 
-    private boolean recordingStateInsideForm;
 
     private int endRow;
 
@@ -165,6 +230,8 @@
     @Property(write = false)
     private PropertyModel columnModel;
 
+    private List<Serializable> encodedPrimaryKeys;
+
     public String getRowClass()
     {
         List<String> classes = CollectionFactory.newList();
@@ -227,7 +294,20 @@
 
         dataRowIndex = startRow;
 
-        recordingStateInsideForm = !volatileState && formSupport != null;
+        boolean recordingStateInsideForm = !volatileState && formSupport != 
null;
+
+        recordStateByIndex = recordingStateInsideForm && (encoder == null);
+        recordStateByEncoder = recordingStateInsideForm && (encoder != null);
+
+        if (recordStateByEncoder)
+        {
+            encodedPrimaryKeys = CollectionFactory.newList();
+
+            // As we render, we'll fill in encodedPrimaryKeys.  That's ok, 
because nothing is serialized
+            // until later.  When the form is submitted, this will give us a 
chance to inform
+            // the PKE about the keys to expect.
+            formSupport.store(this, new PrepareForKeys(encodedPrimaryKeys));
+        }
     }
 
     /**
@@ -238,19 +318,55 @@
         row = gridModel.getDataSource().getRowValue(rowIndex);
     }
 
-    boolean beginRender()
+    /**
+     * Callback method that bypasses the data source and converts a primary 
key back into a row value (via [EMAIL PROTECTED]
+     * org.apache.tapestry5.PrimaryKeyEncoder#toValue(java.io.Serializable)}).
+     */
+    void setupForRowByKey(Serializable rowKey)
     {
-        // When needed, store a callback used when the form is submitted.
+        row = encoder.toValue(rowKey);
 
-        if (recordingStateInsideForm) formSupport.store(this, new 
SetupForRow(dataRowIndex));
+        if (row == null)
+            throw new IllegalArgumentException(
+                    String.format("%s returned null for key %s.", encoder, 
rowKey));
+    }
+
+    /**
+     * Callback method that allows the primary key encoder to prepare for the 
keys that will be resolved to row values
+     * in this request.
+     */
+    private void prepareForKeys(List<Serializable> storedKeys)
+    {
+        encoder.prepareForKeys(storedKeys);
+    }
 
-        // And do it now for the render.
+
+    boolean beginRender()
+    {
+        // Setup for this row.
 
         setupForRow(dataRowIndex);
 
         // Update the index parameter (which starts from zero).
         rowIndex = dataRowIndex - startRow;
 
+
+        if (row != null)
+        {
+            // When needed, store a callback used when the form is submitted.
+
+            if (recordStateByIndex)
+                formSupport.store(this, new SetupForRowByIndex(dataRowIndex));
+
+            if (recordStateByEncoder)
+            {
+                Serializable key = encoder.toKey(row);
+                encodedPrimaryKeys.add(key);
+
+                formSupport.store(this, new SetupForRowByKey(key));
+            }
+        }
+
         // If the row is null, it's because the rowIndex is too large (see the 
notes
         // on GridDataSource).  When row is null, return false to not render 
anything for this iteration
         // of the loop.

Modified: 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/Loop.xdoc
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/Loop.xdoc?rev=709306&r1=709305&r2=709306&view=diff
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/Loop.xdoc
 (original)
+++ 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/Loop.xdoc
 Thu Oct 30 17:18:24 2008
@@ -38,25 +38,22 @@
 public class NavBar
 {
     @Parameter(defaultPrefix="literal", required=true)
-    private String _pages;
+    private String pages;
 
     @Inject
-    private ComponentResources _resources;
+    private ComponentResources resources;
 
+    @Property
     private String _pageName;
 
-    public String getPageName() { return _pageName; }
-
-    public void setPageName(String pageName) { _pageName = pageName; }
-
     public String[] getPageNames()
     {
-        return _pages.split(",");
+        return pages.split(",");
     }
 
     public String getTabClass()
     {
-        if (_pageName.equalsIgnoreCase(_resources.getPageName())
+        if (pageName.equalsIgnoreCase(resources.getPageName())
             return "current";
 
         return null;
@@ -162,9 +159,10 @@
 public class EditOrder
 {
     @Inject
-    private OrderDAO _orderDAO;
+    private OrderDAO orderDAO;
 
-    private final PrimaryKeyEncoder<Long,LineItem> _encoder = new 
PrimaryKeyEncoder<Long,LineItem>()
+    @Property
+    private final PrimaryKeyEncoder<Long,LineItem> encoder = new 
PrimaryKeyEncoder<Long,LineItem>()
     {
         public Long toKey(LineItem value) { return value.getId(); }
 
@@ -172,25 +170,20 @@
 
         public LineItem toValue(Long key)
         {
-            return _orderDAO.getLineItem(key);
+            return orderDAO.getLineItem(key);
         }
     };
 
     @Persist
-    private long _orderId;
-
-    private LineItem _item;
+    private long orderId;
 
-    public PrimaryKeyEncoder getEncoder() { return _encoder ; }
+    @Property
+    private LineItem item;
 
     public List<LineItem> getItems()
     {
-        return _orderDAO.getLineItemsForOrder(_orderId);
+        return orderDAO.getLineItemsForOrder(orderId);
     }
-
-    public LineItem getItem() { return _item; }
-
-    public void setLineItem(LineItem item) { _item = item; }
 }]]></source>
 
                 <p>
@@ -202,7 +195,8 @@
                 <p>
                     We've glossed over a few issues here, including how to 
handle
                     the case that a particular item has been deleted or changed
-                    between the render request and the form submission.
+                    between the render request and the form submission, as 
well as how the orderId
+                    property gets set in the first place.
                 </p>
 
                 <p>

Modified: 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ComponentClassTransformerImpl.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ComponentClassTransformerImpl.java?rev=709306&r1=709305&r2=709306&view=diff
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ComponentClassTransformerImpl.java
 (original)
+++ 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ComponentClassTransformerImpl.java
 Thu Oct 30 17:18:24 2008
@@ -131,7 +131,8 @@
 
         String classname = ctClass.getName();
 
-        Logger logger = loggerSource.getLogger("tapestry.transfomer." + 
classname);
+        Logger transformLogger = loggerSource.getLogger("tapestry.transfomer." 
+ classname);
+        Logger logger = loggerSource.getLogger(classname);
 
         // If the parent class is in a controlled package, it will already 
have been loaded and
         // transformed (that is driven by the ComponentInstantiatorSource).
@@ -175,7 +176,8 @@
             throw new TransformationException(transformation, ex);
         }
 
-        logger.debug(TapestryMarkers.CLASS_TRANSFORMATION, "Finished class 
transformation: {}", transformation);
+        transformLogger.debug(TapestryMarkers.CLASS_TRANSFORMATION, "Finished 
class transformation: {}",
+                              transformation);
 
         nameToClassTransformation.put(classname, transformation);
         nameToComponentModel.put(classname, model);

Modified: 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/util/DefaultPrimaryKeyEncoder.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/util/DefaultPrimaryKeyEncoder.java?rev=709306&r1=709305&r2=709306&view=diff
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/util/DefaultPrimaryKeyEncoder.java
 (original)
+++ 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/util/DefaultPrimaryKeyEncoder.java
 Thu Oct 30 17:18:24 2008
@@ -25,10 +25,10 @@
 import java.util.Set;
 
 /**
- * A default, extensible version of [EMAIL PROTECTED] PrimaryKeyEncoder} that 
is based on loading known values into an internal
- * map. When there's a reasonable number (hundreds, perhaps thousands) of 
items to choose from, and those items are fast
- * and cheap to read and instantiate, this implementation is a good bet. For 
very large result sets, you'll need to
- * create your own implementation of [EMAIL PROTECTED] PrimaryKeyEncoder}.
+ * A default, extensible version of [EMAIL PROTECTED] 
org.apache.tapestry5.PrimaryKeyEncoder} that is based on loading known values
+ * into an internal map. When there's a reasonable number (hundreds, perhaps 
thousands) of items to choose from, and
+ * those items are fast and cheap to read and instantiate, this implementation 
is a good bet. For very large result
+ * sets, you'll need to create your own implementation of [EMAIL PROTECTED] 
PrimaryKeyEncoder}.
  *
  * @param <K> the key type (which must be serializable)
  * @param <V> the value type

Modified: tapestry/tapestry5/trunk/tapestry-core/src/test/app1/GridFormDemo.tml
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/app1/GridFormDemo.tml?rev=709306&r1=709305&r2=709306&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/app1/GridFormDemo.tml 
(original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/app1/GridFormDemo.tml Thu 
Oct 30 17:18:24 2008
@@ -1,35 +1,38 @@
 <html t:type="Border"
-  xmlns:t="http://tapestry.apache.org/schema/tapestry_5_0_0.xsd";>
+      xmlns:t="http://tapestry.apache.org/schema/tapestry_5_0_0.xsd";>
 
-  <h1>Grid Form Demo</h1>
+    <h1>Grid Form Demo</h1>
 
 
-  <t:form>
+    <t:form>
 
-    <t:errors />
+        <t:errors/>
 
-    <table t:type="Grid" source="items" row="item" pagerposition="top"
-      rowsperpage="5">
+        <table t:type="Grid" source="items" row="item" pagerposition="top"
+               add="id" reorder="id,title,urgency"
+               rowsperpage="5">
 
-      <t:parameter name="titleCell">
-        <t:textfield t:id="title" value="item.title" />
-      </t:parameter>
+            <t:parameter name="idCell">${item.id}</t:parameter>
 
-      <t:parameter name="urgencyCell">
-        <t:select t:id="urgency" value="item.urgency" />
-      </t:parameter>
+            <t:parameter name="titleCell">
+                <t:textfield t:id="title" value="item.title"/>
+            </t:parameter>
 
-    </table>
+            <t:parameter name="urgencyCell">
+                <t:select t:id="urgency" value="item.urgency"/>
+            </t:parameter>
 
-    <p>
-      <input type="submit" value="Update Items" />
-    </p>
-  </t:form>
+        </table>
+
+        <p>
+            <input type="submit" value="Update Items"/>
+        </p>
+    </t:form>
 
 
-  <p>
-    [
-    <a t:type="ActionLink" t:id="reset">reset</a>
-    ]
-  </p>
+    <p>
+        [
+        <a t:type="ActionLink" t:id="reset">reset</a>
+        ]
+    </p>
 </html>

Added: 
tapestry/tapestry5/trunk/tapestry-core/src/test/app1/GridFormEncoderDemo.tml
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/app1/GridFormEncoderDemo.tml?rev=709306&view=auto
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-core/src/test/app1/GridFormEncoderDemo.tml 
(added)
+++ 
tapestry/tapestry5/trunk/tapestry-core/src/test/app1/GridFormEncoderDemo.tml 
Thu Oct 30 17:18:24 2008
@@ -0,0 +1,39 @@
+<html t:type="Border"
+      xmlns:t="http://tapestry.apache.org/schema/tapestry_5_0_0.xsd";>
+
+    <h1>Grid Form Encoder Demo</h1>
+
+
+    <t:form>
+
+        <t:errors/>
+
+        <table t:type="Grid" source="items" row="item" pagerposition="top"
+               encoder="encoder"
+               add="id" reorder="id,title,urgency"
+               rowsperpage="5">
+
+            <t:parameter name="idCell">${item.id}</t:parameter>
+
+            <t:parameter name="titleCell">
+                <t:textfield t:id="title" value="item.title"/>
+            </t:parameter>
+
+            <t:parameter name="urgencyCell">
+                <t:select t:id="urgency" value="item.urgency"/>
+            </t:parameter>
+
+        </table>
+
+        <p>
+            <input type="submit" value="Update Items"/>
+        </p>
+    </t:form>
+
+
+    <p>
+        [
+        <a t:type="ActionLink" t:id="reset">reset</a>
+        ]
+    </p>
+</html>

Modified: 
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/IntegrationTests.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/IntegrationTests.java?rev=709306&r1=709305&r2=709306&view=diff
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/IntegrationTests.java
 (original)
+++ 
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/IntegrationTests.java
 Thu Oct 30 17:18:24 2008
@@ -1159,6 +1159,28 @@
     }
 
     @Test
+    public void grid_inside_form_with_encoder()
+    {
+        start("Grid Form Encoder Demo", "reset", "2");
+
+        // The first input field is the form's hidden field.
+
+        assertFieldValue("title", "ToDo # 6");
+        assertFieldValueSeries("title_%d", 0, "ToDo # 7", "ToDo # 8", "ToDo # 
9", "ToDo # 10");
+
+        type("title_0", "Cure Cancer");
+        select("urgency_0", "Top Priority");
+
+        type("title_1", "Pay Phone Bill");
+        select("urgency_1", "Low");
+
+        clickAndWait(SUBMIT);
+
+        assertFieldValueSeries("title_%d", 0, "Cure Cancer", "Pay Phone Bill");
+        assertFieldValueSeries("urgency_%d", 0, "HIGH", "LOW");
+    }
+
+    @Test
     public void missing_template_for_page()
     {
         start("Missing Template Demo");

Modified: 
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/GridFormDemo.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/GridFormDemo.java?rev=709306&r1=709305&r2=709306&view=diff
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/GridFormDemo.java
 (original)
+++ 
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/GridFormDemo.java
 Thu Oct 30 17:18:24 2008
@@ -72,5 +72,4 @@
             database.add(item);
         }
     }
-
 }

Added: 
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/GridFormEncoderDemo.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/GridFormEncoderDemo.java?rev=709306&view=auto
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/GridFormEncoderDemo.java
 (added)
+++ 
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/GridFormEncoderDemo.java
 Thu Oct 30 17:18:24 2008
@@ -0,0 +1,20 @@
+package org.apache.tapestry5.integration.app1.pages;
+
+import org.apache.tapestry5.PrimaryKeyEncoder;
+import org.apache.tapestry5.integration.app1.data.ToDoItem;
+import org.apache.tapestry5.util.DefaultPrimaryKeyEncoder;
+
+public class GridFormEncoderDemo extends GridFormDemo
+{
+    public PrimaryKeyEncoder<Long, ToDoItem> getEncoder()
+    {
+        DefaultPrimaryKeyEncoder<Long, ToDoItem> result = new 
DefaultPrimaryKeyEncoder<Long, ToDoItem>();
+
+        for (ToDoItem item : getItems())
+        {
+            result.add(item.getId(), item);
+        }
+
+        return result;
+    }
+}

Modified: 
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/Start.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/Start.java?rev=709306&r1=709305&r2=709306&view=diff
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/Start.java
 (original)
+++ 
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/Start.java
 Thu Oct 30 17:18:24 2008
@@ -65,6 +65,9 @@
 
     private static final List<Item> ITEMS = CollectionFactory.newList(
 
+            new Item("GridFormEncoderDemo", "Grid Form Encoder Demo",
+                     "Grid inside a Form using the PrimaryKeyEncoder option"),
+
             new Item("DateFieldAjaxFormLoop", "DateField inside AjaxFormLoop",
                      "Show that DateField component works correctly inside 
AjaxFormLoop"),
 

Modified: 
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/services/ToDoDatabase.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/services/ToDoDatabase.java?rev=709306&r1=709305&r2=709306&view=diff
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/services/ToDoDatabase.java
 (original)
+++ 
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/services/ToDoDatabase.java
 Thu Oct 30 17:18:24 2008
@@ -55,4 +55,9 @@
      * @throws RuntimeException if the item does not exist
      */
     void remove(long itemId);
+
+    /**
+     * Gets the item, or returns null.
+     */
+    ToDoItem get(long itemId);
 }

Modified: 
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/services/ToDoDatabaseImpl.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/services/ToDoDatabaseImpl.java?rev=709306&r1=709305&r2=709306&view=diff
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/services/ToDoDatabaseImpl.java
 (original)
+++ 
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/services/ToDoDatabaseImpl.java
 Thu Oct 30 17:18:24 2008
@@ -114,5 +114,10 @@
             throw new RuntimeException(String.format("ToDoItem #%d not 
found.", itemId));
     }
 
+    public ToDoItem get(long itemId)
+    {
+        ToDoItem item = items.get(itemId);
 
+        return item == null ? null : item.clone();
+    }
 }

Modified: 
tapestry/tapestry5/trunk/tapestry-core/src/test/resources/log4j.properties
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/resources/log4j.properties?rev=709306&r1=709305&r2=709306&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/resources/log4j.properties 
(original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/resources/log4j.properties 
Thu Oct 30 17:18:24 2008
@@ -19,9 +19,9 @@
 
 # A1 uses PatternLayout.
 log4j.appender.A1.layout=org.apache.log4j.PatternLayout
-log4j.appender.A1.layout.ConversionPattern= %d{HH:mm:ss,SSS} [%p] %c{1} %m%n
+log4j.appender.A1.layout.ConversionPattern=[%p] %c{1} %m%n
 
 log4j.category.org.apache.tapestry5.integration.app2=debug
 
-# log4j.category.org.apache.tapestry5.corelib.components=debug
+log4j.category.org.apache.tapestry5.corelib.components.Form=debug
 

Modified: 
tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/CtClassSourceImpl.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/CtClassSourceImpl.java?rev=709306&r1=709305&r2=709306&view=diff
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/CtClassSourceImpl.java
 (original)
+++ 
tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/CtClassSourceImpl.java
 Thu Oct 30 17:18:24 2008
@@ -26,6 +26,8 @@
  */
 public class CtClassSourceImpl implements CtClassSource
 {
+    private static final String WRITE_DIR = 
System.getProperty("javassist-write-dir");
+
     private final ClassFactoryClassPool pool;
 
     private final ClassLoader loader;
@@ -81,7 +83,6 @@
         return pool.makeClass(name, ctSuperClass);
     }
 
-    private static final String WRITE_DIR = 
System.getProperty("javassist-write-dir");
 
     public Class createClass(CtClass ctClass)
     {
@@ -108,13 +109,7 @@
     {
         try
         {
-            boolean pruning = ctClass.stopPruning(true);
-
-            ctClass.writeFile(WRITE_DIR);
-
-            ctClass.defrost();
-
-            ctClass.stopPruning(pruning);
+            ctClass.debugWriteFile(WRITE_DIR);
         }
         catch (Exception ex)
         {


Reply via email to