You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by sk...@apache.org on 2005/11/24 05:12:15 UTC

svn commit: r348641 - /myfaces/api/trunk/src/java/javax/faces/component/UIData.java

Author: skitching
Date: Wed Nov 23 20:12:12 2005
New Revision: 348641

URL: http://svn.apache.org/viewcvs?rev=348641&view=rev
Log:
* Explain why _rowState is reset on render
* Explain the _dataModelMap member
* Note that UIColumn components don't get to render their children; the
  UIData does it for them.

Modified:
    myfaces/api/trunk/src/java/javax/faces/component/UIData.java

Modified: myfaces/api/trunk/src/java/javax/faces/component/UIData.java
URL: http://svn.apache.org/viewcvs/myfaces/api/trunk/src/java/javax/faces/component/UIData.java?rev=348641&r1=348640&r2=348641&view=diff
==============================================================================
--- myfaces/api/trunk/src/java/javax/faces/component/UIData.java (original)
+++ myfaces/api/trunk/src/java/javax/faces/component/UIData.java Wed Nov 23 20:12:12 2005
@@ -39,7 +39,12 @@
 import javax.faces.model.ScalarDataModel;
 import javax.servlet.jsp.jstl.sql.Result;
 
-/**<h1>
+/**
+ * Represents a component which has multiple "rows" of data.
+ * <p>
+ * The children of this component are expected to be UIColumn components.
+ * <p>
+ *<h1>
  * Implementation Notes
  * </h1>
  * <p>
@@ -53,11 +58,8 @@
  * current state then reinitialise themselves from the appropriate saved
  * state. This allows a single set of real objects to represent multiple
  * objects which have the same types but potentially different internal
- * state.
- * </p>
- * <p>
- * When a row is selected for the first time, its state is set to a
- * clean "initial" state.
+ * state. When a row is selected for the first time, its state is set to
+ * a clean "initial" state.
  * </p>
  * <p>
  * Note that a table is a "naming container", so that components
@@ -83,6 +85,21 @@
  * row currently being decoded. Exactly the same process applies for
  * the later validation and updateModel phases.
  * </p>
+ * <p>
+ * When the data model for the table is bound to a backing bean property,
+ * and no validation errors have occured during processing of a postback,
+ * the data model is refetched at the start of the rendering phase
+ * (ie after the update model phase) so that the contents of the data model
+ * can be changed as a result of the latest form submission. Because the
+ * saved row state must correspond to the elements within the data model,
+ * the row state must be discarded whenever a new data model is fetched;
+ * not doing this would cause all sorts of inconsistency issues. This does
+ * imply that changing the state of components within the table (such as
+ * modifying the rendered state) during the invokeApplication phase has no
+ * effect on the rendering of the table. When a validation error has occurred,
+ * a new DataModel is <i>not</i> fetched, and the saved state of the child
+ * components is <i>not</i> discarded.
+ * </p>
  * @author Manfred Geiler (latest modification by $Author$)
  * @version $Revision$ $Date$
  */
@@ -110,6 +127,13 @@
     // holds for each row the states of the child components of this UIData 
     private Map _rowStates = new HashMap();
 
+    /**
+     * Handle case where this table is nested inside another table.
+     * See method getDataModel for more details.
+     * <p>
+     * Key: parentClientId (aka rowId when nested within a parent table)
+     * Value: DataModel
+     */
     private Map _dataModelMap = new HashMap();
 
     // will be set to false if the data should not be refreshed at the beginning of the encode phase
@@ -392,13 +416,25 @@
         }
     }
 
+    /**
+     * Perform necessary actions when rendering of this component starts,
+     * before delegating to the inherited implementation which calls the
+     * associated renderer's encodeBegin method.
+     */
     public void encodeBegin(FacesContext context) throws IOException
     {
         _initialDescendantComponentState = null;
         if (_isValidChilds && !hasErrorMessages(context))
         {
-            //Refresh DataModel for rendering:
+            // Clear the data model so that when rendering code calls
+            // getDataModel a fresh model is fetched from the backing
+            // bean via the value-binding.
             _dataModelMap.clear();
+            
+            // When the data model is cleared it is also necessary to
+            // clear the saved row state, as there is an implicit 1:1
+            // relation between objects in the _rowStates and the
+            // corresponding DataModel element.
             _rowStates.clear();
         }
         super.encodeBegin(context);
@@ -494,6 +530,14 @@
         }
     }
 
+    /**
+     * Invoke the specified phase on all facets of all UIColumn children
+     * of this component. Note that no methods are called on the UIColumn
+     * child objects themselves.
+     * 
+     * @param context is the current faces context.
+     * @param processAction specifies a JSF phase: decode, validate or update.
+     */
     private void processColumnFacets(FacesContext context, int processAction)
     {
         for (Iterator childIter = getChildren().iterator(); childIter.hasNext();)
@@ -516,6 +560,14 @@
         }
     }
 
+    /**
+     * Invoke the specified phase on all non-facet children of all UIColumn
+     * children of this component. Note that no methods are called on the
+     * UIColumn child objects themselves.
+     * 
+     * @param context is the current faces context.
+     * @param processAction specifies a JSF phase: decode, validate or update.
+     */
     private void processColumnChildren(FacesContext context, int processAction)
     {
         int first = getFirst();
@@ -576,6 +628,21 @@
         }
     }
 
+    /**
+     * Return the datamodel for this table, potentially fetching the data from
+     * a backing bean via a value-binding if this is the first time this method
+     * has been called.
+     * <p>
+     * This is complicated by the fact that this table may be nested within
+     * another table. In this case a different datamodel should be fetched
+     * for each row. When nested within a parent table, the parent reference
+     * won't change but parent.getClientId() will, as the suffix changes
+     * depending upon the current row index. A map object on this component
+     * is therefore used to cache the datamodel for each row of the table.
+     * In the normal case where this table is not nested inside a component
+     * that changes its id (like a table does) then this map only ever has
+     * one entry.
+     */
     private DataModel getDataModel()
     {
         DataModel dataModel = null;
@@ -595,7 +662,16 @@
     }
 
     /**
-     * Creates a new DataModel around the current value.
+     * Evaluate this object's value property and convert the result into a 
+     * DataModel. Normally this object's value property will be a value-binding
+     * which will cause the value to be fetched from some backing bean.
+     * <p>
+     * The result of fetching the value may be a DataModel object, in which
+     * case that object is returned directly. If the value is of type
+     * List, Array, ResultSet, Result, other object or null then an appropriate
+     * wrapper is created and returned.
+     * <p>
+     * Null is never returned by this method.
      */
     private DataModel createDataModel()
     {