Coverage Report - javax.faces.component.UIData
 
Classes in this File Line Coverage Branch Coverage Complexity
UIData
74%
540/722
57%
296/513
5.315
UIData$1
33%
4/12
25%
1/4
5.315
UIData$2
100%
1/1
N/A
5.315
UIData$EditableValueHolderState
100%
11/11
N/A
5.315
UIData$FacesEventWrapper
46%
7/15
N/A
5.315
UIData$PropertyKeys
100%
7/7
N/A
5.315
 
 1  
 /*
 2  
  * Licensed to the Apache Software Foundation (ASF) under one
 3  
  * or more contributor license agreements.  See the NOTICE file
 4  
  * distributed with this work for additional information
 5  
  * regarding copyright ownership.  The ASF licenses this file
 6  
  * to you under the Apache License, Version 2.0 (the
 7  
  * "License"); you may not use this file except in compliance
 8  
  * with the License.  You may obtain a copy of the License at
 9  
  *
 10  
  *   http://www.apache.org/licenses/LICENSE-2.0
 11  
  *
 12  
  * Unless required by applicable law or agreed to in writing,
 13  
  * software distributed under the License is distributed on an
 14  
  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 15  
  * KIND, either express or implied.  See the License for the
 16  
  * specific language governing permissions and limitations
 17  
  * under the License.
 18  
  */
 19  
 package javax.faces.component;
 20  
 
 21  
 import java.io.IOException;
 22  
 import java.io.Serializable;
 23  
 import java.sql.ResultSet;
 24  
 import java.util.ArrayList;
 25  
 import java.util.Collection;
 26  
 import java.util.HashMap;
 27  
 import java.util.Iterator;
 28  
 import java.util.List;
 29  
 import java.util.Map;
 30  
 
 31  
 import javax.el.ValueExpression;
 32  
 import javax.faces.FacesException;
 33  
 import javax.faces.application.FacesMessage;
 34  
 import javax.faces.application.StateManager;
 35  
 import javax.faces.component.visit.VisitCallback;
 36  
 import javax.faces.component.visit.VisitContext;
 37  
 import javax.faces.component.visit.VisitHint;
 38  
 import javax.faces.component.visit.VisitResult;
 39  
 import javax.faces.context.FacesContext;
 40  
 import javax.faces.event.AbortProcessingException;
 41  
 import javax.faces.event.FacesEvent;
 42  
 import javax.faces.event.FacesListener;
 43  
 import javax.faces.event.PhaseId;
 44  
 import javax.faces.event.PostValidateEvent;
 45  
 import javax.faces.event.PreValidateEvent;
 46  
 import javax.faces.model.ArrayDataModel;
 47  
 import javax.faces.model.CollectionDataModel;
 48  
 import javax.faces.model.DataModel;
 49  
 import javax.faces.model.ListDataModel;
 50  
 import javax.faces.model.ResultDataModel;
 51  
 import javax.faces.model.ResultSetDataModel;
 52  
 import javax.faces.model.ScalarDataModel;
 53  
 import javax.servlet.jsp.jstl.sql.Result;
 54  
 
 55  
 import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFComponent;
 56  
 import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFFacet;
 57  
 import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFProperty;
 58  
 
 59  
 /**
 60  
  * Represents an abstraction of a component which has multiple "rows" of data.
 61  
  * <p>
 62  
  * The children of this component are expected to be UIColumn components.
 63  
  * <p>
 64  
  * Note that the same set of child components are reused to implement each row of the table in turn during such phases
 65  
  * as apply-request-values and render-response. Altering any of the members of these components therefore affects the
 66  
  * attribute for every row, except for the following members:
 67  
  * <ul>
 68  
  * <li>submittedValue
 69  
  * <li>value (where no EL binding is used)
 70  
  * <li>valid
 71  
  * </ul>
 72  
  * <p>
 73  
  * This reuse of the child components also means that it is not possible to save a reference to a component during table
 74  
  * processing, then access it later and expect it to still represent the same row of the table.
 75  
  * <h1>
 76  
  * Implementation Notes</h1>
 77  
  * <p>
 78  
  * Each of the UIColumn children of this component has a few component children of its own to render the contents of the
 79  
  * table cell. However there can be a very large number of rows in a table, so it isn't efficient for the UIColumn and
 80  
  * all its child objects to be duplicated for each row in the table. Instead the "flyweight" pattern is used where a
 81  
  * serialized state is held for each row. When setRowIndex is invoked, the UIColumn objects and their children serialize
 82  
  * their current state then reinitialise themselves from the appropriate saved state. This allows a single set of real
 83  
  * objects to represent multiple objects which have the same types but potentially different internal state. When a row
 84  
  * is selected for the first time, its state is set to a clean "initial" state. Transient components (including any
 85  
  * read-only component) do not save their state; they are just reinitialised as required. The state saved/restored when
 86  
  * changing rows is not the complete component state, just the fields that are expected to vary between rows:
 87  
  * "submittedValue", "value", "isValid".
 88  
  * </p>
 89  
  * <p>
 90  
  * Note that a table is a "naming container", so that components within the table have their ids prefixed with the id of
 91  
  * the table. Actually, when setRowIndex has been called on a table with id of "zzz" the table pretends to its children
 92  
  * that its ID is "zzz_n" where n is the row index. This means that renderers for child components which call
 93  
  * component.getClientId automatically get ids of form "zzz_n:childId" thus ensuring that components in different rows
 94  
  * of the table get different ids.
 95  
  * </p>
 96  
  * <p>
 97  
  * When decoding a submitted page, this class iterates over all its possible rowIndex values, restoring the appropriate
 98  
  * serialized row state then calling processDecodes on the child components. Because the child components (or their
 99  
  * renderers) use getClientId to get the request key to look for parameter data, and because this object pretends to
 100  
  * have a different id per row ("zzz_n") a single child component can decode data from each table row in turn without
 101  
  * being aware that it is within a table. The table's data model is updated before each call to child.processDecodes, so
 102  
  * the child decode method can assume that the data model's rowData points to the model object associated with the row
 103  
  * currently being decoded. Exactly the same process applies for the later validation and updateModel phases.
 104  
  * </p>
 105  
  * <p>
 106  
  * When the data model for the table is bound to a backing bean property, and no validation errors have occured during
 107  
  * processing of a postback, the data model is refetched at the start of the rendering phase (ie after the update model
 108  
  * phase) so that the contents of the data model can be changed as a result of the latest form submission. Because the
 109  
  * saved row state must correspond to the elements within the data model, the row state must be discarded whenever a new
 110  
  * data model is fetched; not doing this would cause all sorts of inconsistency issues. This does imply that changing
 111  
  * the state of any of the members "submittedValue", "value" or "valid" of a component within the table during the
 112  
  * invokeApplication phase has no effect on the rendering of the table. When a validation error has occurred, a new
 113  
  * DataModel is <i>not</i> fetched, and the saved state of the child components is <i>not</i> discarded.
 114  
  * </p>
 115  
  * see Javadoc of the <a href="http://java.sun.com/j2ee/javaserverfaces/1.2/docs/api/index.html">JSF Specification</a>
 116  
  * for more information.
 117  
  */
 118  
 @JSFComponent(defaultRendererType = "javax.faces.Table")
 119  
 public class UIData extends UIComponentBase implements NamingContainer, UniqueIdVendor
 120  
 {
 121  
     public static final String COMPONENT_FAMILY = "javax.faces.Data";
 122  
     public static final String COMPONENT_TYPE = "javax.faces.Data"; // for unit tests
 123  
 
 124  
     private static final String FOOTER_FACET_NAME = "footer";
 125  
     private static final String HEADER_FACET_NAME = "header";
 126  2
     private static final Class<Object[]> OBJECT_ARRAY_CLASS = Object[].class;
 127  
     private static final int PROCESS_DECODES = 1;
 128  
     private static final int PROCESS_VALIDATORS = 2;
 129  
     private static final int PROCESS_UPDATES = 3;
 130  
     //private static final String SKIP_ITERATION_HINT = "javax.faces.visit.SKIP_ITERATION";
 131  
 
 132  2
     private static final Object[] LEAF_NO_STATE = new Object[]{null,null};
 133  
 
 134  136
     private int _rowIndex = -1;
 135  
 
 136  
     // Holds for each row the states of the child components of this UIData.
 137  
     // Note that only "partial" component state is saved: the component fields
 138  
     // that are expected to vary between rows.
 139  136
     private Map<String, Object> _rowStates = new HashMap<String, Object>();
 140  136
     private Map<String, Map<String, Object> > _rowDeltaStates = new HashMap<String, Map<String, Object> >();
 141  136
     private Map<String, Map<String, Object> > _rowTransientStates = new HashMap<String, Map<String, Object> >();
 142  
 
 143  
     /**
 144  
      * Handle case where this table is nested inside another table. See method getDataModel for more details.
 145  
      * <p>
 146  
      * Key: parentClientId (aka rowId when nested within a parent table) Value: DataModel
 147  
      */
 148  136
     private Map<String, DataModel> _dataModelMap = new HashMap<String, DataModel>();
 149  
 
 150  
     // will be set to false if the data should not be refreshed at the beginning of the encode phase
 151  136
     private boolean _isValidChilds = true;
 152  
 
 153  136
     private Object _initialDescendantComponentState = null;
 154  
     
 155  136
     private Object _initialDescendantFullComponentState = null;
 156  
 
 157  
     //private int _first;
 158  
     //private boolean _firstSet;
 159  
     //private int _rows;
 160  
     //private boolean _rowsSet;
 161  
     //private Object _value;
 162  
 
 163  
     private static class FacesEventWrapper extends FacesEvent
 164  
     {
 165  
         private static final long serialVersionUID = 6648047974065628773L;
 166  
         private FacesEvent _wrappedFacesEvent;
 167  
         private int _rowIndex;
 168  
 
 169  
         public FacesEventWrapper(FacesEvent facesEvent, int rowIndex, UIData redirectComponent)
 170  
         {
 171  2
             super(redirectComponent);
 172  2
             _wrappedFacesEvent = facesEvent;
 173  2
             _rowIndex = rowIndex;
 174  2
         }
 175  
 
 176  
         @Override
 177  
         public PhaseId getPhaseId()
 178  
         {
 179  4
             return _wrappedFacesEvent.getPhaseId();
 180  
         }
 181  
 
 182  
         @Override
 183  
         public void setPhaseId(PhaseId phaseId)
 184  
         {
 185  0
             _wrappedFacesEvent.setPhaseId(phaseId);
 186  0
         }
 187  
 
 188  
         @Override
 189  
         public void queue()
 190  
         {
 191  0
             _wrappedFacesEvent.queue();
 192  0
         }
 193  
 
 194  
         @Override
 195  
         public String toString()
 196  
         {
 197  0
             return _wrappedFacesEvent.toString();
 198  
         }
 199  
 
 200  
         @Override
 201  
         public boolean isAppropriateListener(FacesListener faceslistener)
 202  
         {
 203  0
             return _wrappedFacesEvent.isAppropriateListener(faceslistener);
 204  
         }
 205  
 
 206  
         @Override
 207  
         public void processListener(FacesListener faceslistener)
 208  
         {
 209  0
             _wrappedFacesEvent.processListener(faceslistener);
 210  0
         }
 211  
 
 212  
         public FacesEvent getWrappedFacesEvent()
 213  
         {
 214  2
             return _wrappedFacesEvent;
 215  
         }
 216  
 
 217  
         public int getRowIndex()
 218  
         {
 219  2
             return _rowIndex;
 220  
         }
 221  
     }
 222  
 
 223  2
     private static final DataModel EMPTY_DATA_MODEL = new DataModel()
 224  2
     {
 225  
         @Override
 226  
         public boolean isRowAvailable()
 227  
         {
 228  0
             return false;
 229  
         }
 230  
 
 231  
         @Override
 232  
         public int getRowCount()
 233  
         {
 234  6
             return 0;
 235  
         }
 236  
 
 237  
         @Override
 238  
         public Object getRowData()
 239  
         {
 240  0
             throw new IllegalArgumentException();
 241  
         }
 242  
 
 243  
         @Override
 244  
         public int getRowIndex()
 245  
         {
 246  0
             return -1;
 247  
         }
 248  
 
 249  
         @Override
 250  
         public void setRowIndex(int i)
 251  
         {
 252  10
             if (i < -1)
 253  
             {
 254  0
                 throw new IllegalArgumentException();
 255  
             }
 256  10
         }
 257  
 
 258  
         @Override
 259  
         public Object getWrappedData()
 260  
         {
 261  0
             return null;
 262  
         }
 263  
 
 264  
         @Override
 265  
         public void setWrappedData(Object obj)
 266  
         {
 267  0
             if (obj == null)
 268  
             {
 269  0
                 return; // Clearing is allowed
 270  
             }
 271  0
             throw new UnsupportedOperationException(this.getClass().getName() + " UnsupportedOperationException");
 272  
         }
 273  
     };
 274  
 
 275  
     private static class EditableValueHolderState implements Serializable
 276  
     {
 277  
         private final Object _value;
 278  
         private final boolean _localValueSet;
 279  
         private final boolean _valid;
 280  
         private final Object _submittedValue;
 281  
 
 282  
         public EditableValueHolderState(EditableValueHolder evh)
 283  98
         {
 284  98
             _value = evh.getLocalValue();
 285  98
             _localValueSet = evh.isLocalValueSet();
 286  98
             _valid = evh.isValid();
 287  98
             _submittedValue = evh.getSubmittedValue();
 288  98
         }
 289  
 
 290  
         public void restoreState(EditableValueHolder evh)
 291  
         {
 292  100
             evh.setValue(_value);
 293  100
             evh.setLocalValueSet(_localValueSet);
 294  100
             evh.setValid(_valid);
 295  100
             evh.setSubmittedValue(_submittedValue);
 296  100
         }
 297  
     }
 298  
 
 299  
     /**
 300  
      * Construct an instance of the UIData.
 301  
      */
 302  
     public UIData()
 303  136
     {
 304  136
         setRendererType("javax.faces.Table");
 305  136
     }
 306  
 
 307  
     @Override
 308  
     public boolean invokeOnComponent(FacesContext context, String clientId, ContextCallback callback)
 309  
         throws FacesException
 310  
     {
 311  4
         if (context == null || clientId == null || callback == null)
 312  
         {
 313  0
             throw new NullPointerException();
 314  
         }
 315  
         
 316  4
         final String baseClientId = getClientId(context);
 317  
 
 318  
         // searching for this component?
 319  4
         boolean returnValue = baseClientId.equals(clientId);
 320  
 
 321  4
         boolean isCachedFacesContext = isCachedFacesContext();
 322  4
         if (!isCachedFacesContext)
 323  
         {
 324  4
             setCachedFacesContext(context);
 325  
         }
 326  
         
 327  4
         pushComponentToEL(context, this);
 328  
         try
 329  
         {
 330  4
             if (returnValue)
 331  
             {
 332  
                 try
 333  
                 {
 334  0
                     callback.invokeContextCallback(context, this);
 335  0
                     return true;
 336  
                 }
 337  0
                 catch (Exception e)
 338  
                 {
 339  0
                     throw new FacesException(e);
 340  
                 }
 341  
             }
 342  
     
 343  
             // Now Look throught facets on this UIComponent
 344  4
             if (this.getFacetCount() > 0)
 345  
             {
 346  0
                 for (Iterator<UIComponent> it = this.getFacets().values().iterator(); !returnValue && it.hasNext();)
 347  
                 {
 348  0
                     returnValue = it.next().invokeOnComponent(context, clientId, callback);
 349  
                 }
 350  
             }
 351  
     
 352  4
             if (returnValue)
 353  
             {
 354  0
                 return returnValue;
 355  
             }
 356  
             
 357  
             // is the component an inner component?
 358  4
             if (clientId.startsWith(baseClientId))
 359  
             {
 360  
                 // Check if the clientId for the component, which we 
 361  
                 // are looking for, has a rowIndex attached
 362  4
                 char separator = context.getNamingContainerSeparatorChar();
 363  4
                 String subId = clientId.substring(baseClientId.length() + 1);
 364  
                 //If the char next to baseClientId is the separator one and
 365  
                 //the subId matches the regular expression
 366  4
                 if (clientId.charAt(baseClientId.length()) == separator && 
 367  
                         subId.matches("[0-9]+"+separator+".*"))
 368  
                 {
 369  0
                     String clientRow = subId.substring(0, subId.indexOf(separator));
 370  
         
 371  
                     //Now we save the current position
 372  0
                     int oldRow = this.getRowIndex();
 373  
                     
 374  
                     // try-finally --> make sure, that the old row index is restored
 375  
                     try
 376  
                     {
 377  
                         //The conversion is safe, because its already checked on the
 378  
                         //regular expresion
 379  0
                         this.setRowIndex(Integer.parseInt(clientRow));
 380  
                         
 381  
                         // check, if the row is available
 382  0
                         if (!isRowAvailable())
 383  
                         {
 384  0
                             return false;
 385  
                         }
 386  
             
 387  0
                         for (Iterator<UIComponent> it1 = getChildren().iterator(); 
 388  0
                                 !returnValue && it1.hasNext();)
 389  
                         {
 390  
                             //recursive call to find the component
 391  0
                             returnValue = it1.next().invokeOnComponent(context, clientId, callback);
 392  
                         }
 393  
                     }
 394  
                     finally
 395  
                     {
 396  
                         //Restore the old position. Doing this prevent
 397  
                         //side effects.
 398  0
                         this.setRowIndex(oldRow);
 399  0
                     }
 400  0
                 }
 401  
                 else
 402  
                 {
 403  
                     // MYFACES-2370: search the component in the childrens' facets too.
 404  
                     // We have to check the childrens' facets here, because in MyFaces
 405  
                     // the rowIndex is not attached to the clientId for the children of
 406  
                     // facets of the UIColumns. However, in RI the rowIndex is 
 407  
                     // attached to the clientId of UIColumns' Facets' children.
 408  4
                     for (Iterator<UIComponent> itChildren = this.getChildren().iterator();
 409  10
                             !returnValue && itChildren.hasNext();)
 410  
                     {
 411  6
                         UIComponent child = itChildren.next();
 412  6
                         if (child instanceof UIColumn && clientId.equals(child.getClientId(context)))
 413  
                         {
 414  
                             try
 415  
                             {
 416  0
                                 callback.invokeContextCallback(context, child);
 417  
                             }
 418  0
                             catch (Exception e)
 419  
                             {
 420  0
                                 throw new FacesException(e);
 421  0
                             }
 422  0
                             returnValue = true;
 423  
                         }
 424  
                         // process the child's facets
 425  6
                         if (child.getFacetCount() > 0)
 426  
                         {
 427  6
                             for (Iterator<UIComponent> itChildFacets = 
 428  
                                 child.getFacets().values().iterator(); 
 429  12
                                 !returnValue && itChildFacets.hasNext();)
 430  
                             {
 431  
                                 //recursive call to find the component
 432  6
                                 returnValue = itChildFacets.next().invokeOnComponent(
 433  
                                     context, clientId, callback);
 434  
                             }
 435  
                         }
 436  6
                     }
 437  
                 }
 438  
             }
 439  
         }
 440  
         finally
 441  
         {
 442  
             //all components must call popComponentFromEl after visiting is finished
 443  4
             popComponentFromEL(context);
 444  4
             if (!isCachedFacesContext)
 445  
             {
 446  4
                 setCachedFacesContext(null);
 447  
             }
 448  
         }
 449  
 
 450  4
         return returnValue;
 451  
     }
 452  
 
 453  
     public void setFooter(UIComponent footer)
 454  
     {
 455  2
         getFacets().put(FOOTER_FACET_NAME, footer);
 456  2
     }
 457  
 
 458  
     @JSFFacet
 459  
     public UIComponent getFooter()
 460  
     {
 461  0
         return getFacets().get(FOOTER_FACET_NAME);
 462  
     }
 463  
 
 464  
     public void setHeader(UIComponent header)
 465  
     {
 466  2
         getFacets().put(HEADER_FACET_NAME, header);
 467  2
     }
 468  
 
 469  
     @JSFFacet
 470  
     public UIComponent getHeader()
 471  
     {
 472  0
         return getFacets().get(HEADER_FACET_NAME);
 473  
     }
 474  
 
 475  
     public boolean isRowAvailable()
 476  
     {
 477  214
         return getDataModel().isRowAvailable();
 478  
     }
 479  
 
 480  
     public int getRowCount()
 481  
     {
 482  16
         return getDataModel().getRowCount();
 483  
     }
 484  
 
 485  
     public Object getRowData()
 486  
     {
 487  0
         return getDataModel().getRowData();
 488  
     }
 489  
 
 490  
     public int getRowIndex()
 491  
     {
 492  542
         return _rowIndex;
 493  
     }
 494  
 
 495  
     /**
 496  
      * Set the current row index that methods like getRowData use.
 497  
      * <p>
 498  
      * Param rowIndex can be -1, meaning "no row".
 499  
      * <p>
 500  
      * 
 501  
      * @param rowIndex
 502  
      */
 503  
     public void setRowIndex(int rowIndex)
 504  
     {
 505  260
         if (isRowStatePreserved())
 506  
         {
 507  46
             setRowIndexPreserveComponentState(rowIndex);
 508  
         }
 509  
         else
 510  
         {
 511  214
             setRowIndexWithoutPreserveComponentState(rowIndex);
 512  
         }
 513  260
     }
 514  
 
 515  
     private void setRowIndexWithoutPreserveComponentState(int rowIndex)
 516  
     {
 517  214
         if (rowIndex < -1)
 518  
         {
 519  0
             throw new IllegalArgumentException("rowIndex is less than -1");
 520  
         }
 521  
 
 522  214
         if (_rowIndex == rowIndex)
 523  
         {
 524  32
             return;
 525  
         }
 526  
 
 527  182
         FacesContext facesContext = getFacesContext();
 528  
 
 529  182
         if (_rowIndex == -1)
 530  
         {
 531  30
             if (_initialDescendantComponentState == null)
 532  
             {
 533  
                 // Create a template that can be used to initialise any row
 534  
                 // that we haven't visited before, ie a "saved state" that can
 535  
                 // be pushed to the "restoreState" method of all the child
 536  
                 // components to set them up to represent a clean row.
 537  28
                 _initialDescendantComponentState = saveDescendantComponentStates(this, false, false);
 538  
             }
 539  
         }
 540  
         else
 541  
         {
 542  
             // If no initial component state, there are no EditableValueHolder instances,
 543  
             // and that means there is no state to be saved for the current row, so we can
 544  
             // skip row state saving code safely.
 545  152
             if (_initialDescendantComponentState != null)
 546  
             {
 547  
                 // We are currently positioned on some row, and are about to
 548  
                 // move off it, so save the (partial) state of the components
 549  
                 // representing the current row. Later if this row is revisited
 550  
                 // then we can restore this state.
 551  86
                 Collection<Object[]> savedRowState = saveDescendantComponentStates(this, false, false);
 552  86
                 if (savedRowState != null)
 553  
                 {
 554  86
                     _rowStates.put(getContainerClientId(facesContext), savedRowState);
 555  
                 }
 556  
             }
 557  
         }
 558  
 
 559  182
         _rowIndex = rowIndex;
 560  
 
 561  182
         DataModel dataModel = getDataModel();
 562  182
         dataModel.setRowIndex(rowIndex);
 563  
 
 564  182
         String var = (String) getStateHelper().get(PropertyKeys.var);
 565  182
         if (rowIndex == -1)
 566  
         {
 567  20
             if (var != null)
 568  
             {
 569  14
                 facesContext.getExternalContext().getRequestMap().remove(var);
 570  
             }
 571  
         }
 572  
         else
 573  
         {
 574  162
             if (var != null)
 575  
             {
 576  134
                 if (isRowAvailable())
 577  
                 {
 578  132
                     Object rowData = dataModel.getRowData();
 579  132
                     facesContext.getExternalContext().getRequestMap().put(var, rowData);
 580  132
                 }
 581  
                 else
 582  
                 {
 583  2
                     facesContext.getExternalContext().getRequestMap().remove(var);
 584  
                 }
 585  
             }
 586  
         }
 587  
 
 588  182
         if (_rowIndex == -1)
 589  
         {
 590  
             // reset components to initial state
 591  
             // If no initial state, skip row restore state code
 592  20
             if (_initialDescendantComponentState != null)
 593  
             {
 594  8
                 restoreDescendantComponentStates(this, false, _initialDescendantComponentState, false);
 595  
             }
 596  
             else
 597  
             {
 598  12
                 restoreDescendantComponentWithoutRestoreState(this, false, false);
 599  
             }
 600  
         }
 601  
         else
 602  
         {
 603  162
             Object rowState = _rowStates.get(getContainerClientId(facesContext));
 604  162
             if (rowState == null)
 605  
             {
 606  
                 // We haven't been positioned on this row before, so just
 607  
                 // configure the child components of this component with
 608  
                 // the standard "initial" state
 609  
                 // If no initial state, skip row restore state code
 610  126
                 if (_initialDescendantComponentState != null)
 611  
                 {
 612  56
                     restoreDescendantComponentStates(this, false, _initialDescendantComponentState, false);
 613  
                 }
 614  
                 else
 615  
                 {
 616  70
                     restoreDescendantComponentWithoutRestoreState(this, false, false);
 617  
                 }
 618  
             }
 619  
             else
 620  
             {
 621  
                 // We have been positioned on this row before, so configure
 622  
                 // the child components of this component with the (partial)
 623  
                 // state that was previously saved. Fields not in the
 624  
                 // partial saved state are left with their original values.
 625  36
                 restoreDescendantComponentStates(this, false, rowState, false);
 626  
             }
 627  
         }
 628  182
     }
 629  
 
 630  
     private void setRowIndexPreserveComponentState(int rowIndex)
 631  
     {
 632  46
         if (rowIndex < -1)
 633  
         {
 634  0
             throw new IllegalArgumentException("rowIndex is less than -1");
 635  
         }
 636  
 
 637  46
         if (_rowIndex == rowIndex)
 638  
         {
 639  0
             return;
 640  
         }
 641  
 
 642  46
         FacesContext facesContext = getFacesContext();
 643  
 
 644  46
         if (_initialDescendantFullComponentState != null)
 645  
         {
 646  
             //Just save the row
 647  36
             Map<String, Object> sm = saveFullDescendantComponentStates(facesContext, null,
 648  
                                                                        getChildren().iterator(), false);
 649  36
             if (sm != null && !sm.isEmpty())
 650  
             {
 651  28
                 _rowDeltaStates.put(getContainerClientId(facesContext), sm);
 652  
             }
 653  36
             if (_rowIndex != -1)
 654  
             {
 655  28
                 _rowTransientStates.put(getContainerClientId(facesContext),
 656  
                         saveTransientDescendantComponentStates(facesContext, null, getChildren().iterator(), false));
 657  
             }
 658  
         }
 659  
 
 660  46
         _rowIndex = rowIndex;
 661  
 
 662  46
         DataModel dataModel = getDataModel();
 663  46
         dataModel.setRowIndex(rowIndex);
 664  
 
 665  46
         String var = (String) getStateHelper().get(PropertyKeys.var);
 666  46
         if (rowIndex == -1)
 667  
         {
 668  6
             if (var != null)
 669  
             {
 670  6
                 facesContext.getExternalContext().getRequestMap().remove(var);
 671  
             }
 672  
         }
 673  
         else
 674  
         {
 675  40
             if (var != null)
 676  
             {
 677  40
                 if (isRowAvailable())
 678  
                 {
 679  40
                     Object rowData = dataModel.getRowData();
 680  40
                     facesContext.getExternalContext().getRequestMap().put(var, rowData);
 681  40
                 }
 682  
                 else
 683  
                 {
 684  0
                     facesContext.getExternalContext().getRequestMap().remove(var);
 685  
                 }
 686  
             }
 687  
         }
 688  
 
 689  46
         if (_initialDescendantFullComponentState != null)
 690  
         {
 691  36
             Map<String, Object> rowState = _rowDeltaStates.get(getContainerClientId(facesContext));
 692  36
             if (rowState == null)
 693  
             {
 694  
                 //Restore as original
 695  20
                 restoreFullDescendantComponentStates(facesContext, getChildren().iterator(),
 696  
                         _initialDescendantFullComponentState, false);
 697  
             }
 698  
             else
 699  
             {
 700  
                 //Restore first original and then delta
 701  16
                 restoreFullDescendantComponentDeltaStates(facesContext, getChildren().iterator(),
 702  
                         rowState, _initialDescendantFullComponentState, false);
 703  
             }
 704  36
             if (_rowIndex == -1)
 705  
             {
 706  4
                 restoreTransientDescendantComponentStates(facesContext, getChildren().iterator(), null, false);
 707  
             }
 708  
             else
 709  
             {
 710  32
                 rowState = _rowTransientStates.get(getContainerClientId(facesContext));
 711  32
                 if (rowState == null)
 712  
                 {
 713  24
                     restoreTransientDescendantComponentStates(facesContext, getChildren().iterator(), null, false);
 714  
                 }
 715  
                 else
 716  
                 {
 717  8
                     restoreTransientDescendantComponentStates(facesContext, getChildren().iterator(), rowState, false);
 718  
                 }
 719  
             }
 720  
         }
 721  
 
 722  46
     }
 723  
     
 724  
 
 725  
     /**
 726  
      * Overwrite the state of the child components of this component with data previously saved by method
 727  
      * saveDescendantComponentStates.
 728  
      * <p>
 729  
      * The saved state info only covers those fields that are expected to vary between rows of a table. Other fields are
 730  
      * not modified.
 731  
      */
 732  
     @SuppressWarnings("unchecked")
 733  
     private void restoreDescendantComponentStates(UIComponent parent, boolean iterateFacets, Object state,
 734  
                                                   boolean restoreChildFacets)
 735  
     {
 736  200
         int descendantStateIndex = -1;
 737  200
         List<? extends Object[]> stateCollection = null;
 738  
         
 739  200
         if (iterateFacets && parent.getFacetCount() > 0)
 740  
         {
 741  0
             Iterator<UIComponent> childIterator = parent.getFacets().values().iterator();
 742  
             
 743  0
             while (childIterator.hasNext())
 744  
             {
 745  0
                 UIComponent component = childIterator.next();
 746  
 
 747  
                 // reset the client id (see spec 3.1.6)
 748  0
                 component.setId(component.getId());
 749  0
                 if (!component.isTransient())
 750  
                 {
 751  0
                     if (descendantStateIndex == -1)
 752  
                     {
 753  0
                         stateCollection = ((List<? extends Object[]>) state);
 754  0
                         descendantStateIndex = stateCollection.isEmpty() ? -1 : 0;
 755  
                     }
 756  
                     
 757  0
                     if (descendantStateIndex != -1 && descendantStateIndex < stateCollection.size())
 758  
                     {
 759  0
                         Object[] object = stateCollection.get(descendantStateIndex);
 760  0
                         if (object[0] != null && component instanceof EditableValueHolder)
 761  
                         {
 762  0
                             ((EditableValueHolderState) object[0]).restoreState((EditableValueHolder) component);
 763  
                         }
 764  
                         // If there is descendant state to restore, call it recursively, otherwise
 765  
                         // it is safe to skip iteration.
 766  0
                         if (object[1] != null)
 767  
                         {
 768  0
                             restoreDescendantComponentStates(component, restoreChildFacets, object[1], true);
 769  
                         }
 770  
                         else
 771  
                         {
 772  0
                             restoreDescendantComponentWithoutRestoreState(component, restoreChildFacets, true);
 773  
                         }
 774  0
                     }
 775  
                     else
 776  
                     {
 777  0
                         restoreDescendantComponentWithoutRestoreState(component, restoreChildFacets, true);
 778  
                     }
 779  0
                     descendantStateIndex++;
 780  
                 }
 781  0
             }
 782  
         }
 783  
         
 784  200
         if (parent.getChildCount() > 0)
 785  
         {
 786  464
             for (int i = 0; i < parent.getChildCount(); i++)
 787  
             {
 788  264
                 UIComponent component = parent.getChildren().get(i);
 789  
 
 790  
                 // reset the client id (see spec 3.1.6)
 791  264
                 component.setId(component.getId());
 792  264
                 if (!component.isTransient())
 793  
                 {
 794  264
                     if (descendantStateIndex == -1)
 795  
                     {
 796  200
                         stateCollection = ((List<? extends Object[]>) state);
 797  200
                         descendantStateIndex = stateCollection.isEmpty() ? -1 : 0;
 798  
                     }
 799  
                     
 800  264
                     if (descendantStateIndex != -1 && descendantStateIndex < stateCollection.size())
 801  
                     {
 802  264
                         Object[] object = stateCollection.get(descendantStateIndex);
 803  264
                         if (object[0] != null && component instanceof EditableValueHolder)
 804  
                         {
 805  100
                             ((EditableValueHolderState) object[0]).restoreState((EditableValueHolder) component);
 806  
                         }
 807  
                         // If there is descendant state to restore, call it recursively, otherwise
 808  
                         // it is safe to skip iteration.
 809  264
                         if (object[1] != null)
 810  
                         {
 811  100
                             restoreDescendantComponentStates(component, restoreChildFacets, object[1], true);
 812  
                         }
 813  
                         else
 814  
                         {
 815  164
                             restoreDescendantComponentWithoutRestoreState(component, restoreChildFacets, true);
 816  
                         }
 817  264
                     }
 818  
                     else
 819  
                     {
 820  0
                         restoreDescendantComponentWithoutRestoreState(component, restoreChildFacets, true);
 821  
                     }
 822  264
                     descendantStateIndex++;
 823  
                 }
 824  
             }
 825  
         }
 826  200
     }
 827  
 
 828  
     /**
 829  
      * Just call component.setId(component.getId()) to reset all client ids and 
 830  
      * ensure they will be calculated for the current row, but do not waste time
 831  
      * dealing with row state code.
 832  
      * 
 833  
      * @param parent
 834  
      * @param iterateFacets
 835  
      * @param restoreChildFacets 
 836  
      */
 837  
     private void restoreDescendantComponentWithoutRestoreState(UIComponent parent, boolean iterateFacets,
 838  
                                                                boolean restoreChildFacets)
 839  
     {
 840  414
         if (iterateFacets && parent.getFacetCount() > 0)
 841  
         {
 842  0
             Iterator<UIComponent> childIterator = parent.getFacets().values().iterator();
 843  
             
 844  0
             while (childIterator.hasNext())
 845  
             {
 846  0
                 UIComponent component = childIterator.next();
 847  
 
 848  
                 // reset the client id (see spec 3.1.6)
 849  0
                 component.setId(component.getId());
 850  0
                 if (!component.isTransient())
 851  
                 {
 852  0
                     restoreDescendantComponentWithoutRestoreState(component, restoreChildFacets, true);
 853  
                 }
 854  0
             }
 855  
         }
 856  
         
 857  414
         if (parent.getChildCount() > 0)
 858  
         {
 859  312
             for (int i = 0; i < parent.getChildCount(); i++)
 860  
             {
 861  168
                 UIComponent component = parent.getChildren().get(i);
 862  
 
 863  
                 // reset the client id (see spec 3.1.6)
 864  168
                 component.setId(component.getId());
 865  168
                 if (!component.isTransient())
 866  
                 {
 867  168
                     restoreDescendantComponentWithoutRestoreState(component, restoreChildFacets, true);
 868  
                 }
 869  
             }
 870  
         }
 871  414
     }
 872  
 
 873  
     /**
 874  
      * Walk the tree of child components of this UIData, saving the parts of their state that can vary between rows.
 875  
      * <p>
 876  
      * This is very similar to the process that occurs for normal components when the view is serialized. Transient
 877  
      * components are skipped (no state is saved for them).
 878  
      * <p>
 879  
      * If there are no children then null is returned. If there are one or more children, and all children are transient
 880  
      * then an empty collection is returned; this will happen whenever a table contains only read-only components.
 881  
      * <p>
 882  
      * Otherwise a collection is returned which contains an object for every non-transient child component; that object
 883  
      * may itself contain a collection of the state of that child's child components.
 884  
      */
 885  
     private Collection<Object[]> saveDescendantComponentStates(UIComponent parent, boolean iterateFacets,
 886  
                                                                boolean saveChildFacets)
 887  
     {
 888  224
         Collection<Object[]> childStates = null;
 889  
         // Index to indicate how many components has been passed without state to save.
 890  224
         int childEmptyIndex = 0;
 891  224
         int totalChildCount = 0;
 892  
                 
 893  224
         if (iterateFacets && parent.getFacetCount() > 0)
 894  
         {
 895  0
             Iterator<UIComponent> childIterator = parent.getFacets().values().iterator();
 896  
 
 897  0
             while (childIterator.hasNext())
 898  
             {
 899  0
                 UIComponent child = childIterator.next();
 900  0
                 if (!child.isTransient())
 901  
                 {
 902  
                     // Add an entry to the collection, being an array of two
 903  
                     // elements. The first element is the state of the children
 904  
                     // of this component; the second is the state of the current
 905  
                     // child itself.
 906  
 
 907  0
                     if (child instanceof EditableValueHolder)
 908  
                     {
 909  0
                         if (childStates == null)
 910  
                         {
 911  0
                             childStates = new ArrayList<Object[]>(
 912  
                                     parent.getFacetCount()
 913  
                                     + parent.getChildCount()
 914  
                                     - totalChildCount
 915  
                                     + childEmptyIndex);
 916  0
                             for (int ci = 0; ci < childEmptyIndex; ci++)
 917  
                             {
 918  0
                                 childStates.add(LEAF_NO_STATE);
 919  
                             }
 920  
                         }
 921  
                     
 922  0
                         childStates.add(child.getChildCount() > 0 ? 
 923  
                                 new Object[]{new EditableValueHolderState((EditableValueHolder) child),
 924  
                                     saveDescendantComponentStates(child, saveChildFacets, true)} :
 925  
                                 new Object[]{new EditableValueHolderState((EditableValueHolder) child),
 926  
                                     null});
 927  
                     }
 928  0
                     else if (child.getChildCount() > 0 || (saveChildFacets && child.getFacetCount() > 0))
 929  
                     {
 930  0
                         Object descendantSavedState = saveDescendantComponentStates(child, saveChildFacets, true);
 931  
                         
 932  0
                         if (descendantSavedState == null)
 933  
                         {
 934  0
                             if (childStates == null)
 935  
                             {
 936  0
                                 childEmptyIndex++;
 937  
                             }
 938  
                             else
 939  
                             {
 940  0
                                 childStates.add(LEAF_NO_STATE);
 941  
                             }
 942  
                         }
 943  
                         else
 944  
                         {
 945  0
                             if (childStates == null)
 946  
                             {
 947  0
                                 childStates = new ArrayList<Object[]>(
 948  
                                         parent.getFacetCount()
 949  
                                         + parent.getChildCount()
 950  
                                         - totalChildCount
 951  
                                         + childEmptyIndex);
 952  0
                                 for (int ci = 0; ci < childEmptyIndex; ci++)
 953  
                                 {
 954  0
                                     childStates.add(LEAF_NO_STATE);
 955  
                                 }
 956  
                             }
 957  0
                             childStates.add(new Object[]{null, descendantSavedState});
 958  
                         }
 959  0
                     }
 960  
                     else
 961  
                     {
 962  0
                         if (childStates == null)
 963  
                         {
 964  0
                             childEmptyIndex++;
 965  
                         }
 966  
                         else
 967  
                         {
 968  0
                             childStates.add(LEAF_NO_STATE);
 969  
                         }
 970  
                     }
 971  
                 }
 972  0
                 totalChildCount++;
 973  0
             }
 974  
         }
 975  
         
 976  224
         if (parent.getChildCount() > 0)
 977  
         {
 978  508
             for (int i = 0; i < parent.getChildCount(); i++)
 979  
             {
 980  288
                 UIComponent child = parent.getChildren().get(i);
 981  288
                 if (!child.isTransient())
 982  
                 {
 983  
                     // Add an entry to the collection, being an array of two
 984  
                     // elements. The first element is the state of the children
 985  
                     // of this component; the second is the state of the current
 986  
                     // child itself.
 987  
 
 988  288
                     if (child instanceof EditableValueHolder)
 989  
                     {
 990  98
                         if (childStates == null)
 991  
                         {
 992  98
                             childStates = new ArrayList<Object[]>(
 993  
                                     parent.getFacetCount()
 994  
                                     + parent.getChildCount()
 995  
                                     - totalChildCount
 996  
                                     + childEmptyIndex);
 997  160
                             for (int ci = 0; ci < childEmptyIndex; ci++)
 998  
                             {
 999  62
                                 childStates.add(LEAF_NO_STATE);
 1000  
                             }
 1001  
                         }
 1002  
                     
 1003  98
                         childStates.add(child.getChildCount() > 0 ? 
 1004  
                                 new Object[]{new EditableValueHolderState((EditableValueHolder) child),
 1005  
                                     saveDescendantComponentStates(child, saveChildFacets, true)} :
 1006  
                                 new Object[]{new EditableValueHolderState((EditableValueHolder) child),
 1007  
                                     null});
 1008  
                     }
 1009  190
                     else if (child.getChildCount() > 0 || (saveChildFacets && child.getFacetCount() > 0))
 1010  
                     {
 1011  110
                         Object descendantSavedState = saveDescendantComponentStates(child, saveChildFacets, true);
 1012  
                         
 1013  110
                         if (descendantSavedState == null)
 1014  
                         {
 1015  12
                             if (childStates == null)
 1016  
                             {
 1017  12
                                 childEmptyIndex++;
 1018  
                             }
 1019  
                             else
 1020  
                             {
 1021  0
                                 childStates.add(LEAF_NO_STATE);
 1022  
                             }
 1023  
                         }
 1024  
                         else
 1025  
                         {
 1026  98
                             if (childStates == null)
 1027  
                             {
 1028  98
                                 childStates = new ArrayList<Object[]>(
 1029  
                                         parent.getFacetCount()
 1030  
                                         + parent.getChildCount()
 1031  
                                         - totalChildCount
 1032  
                                         + childEmptyIndex);
 1033  98
                                 for (int ci = 0; ci < childEmptyIndex; ci++)
 1034  
                                 {
 1035  0
                                     childStates.add(LEAF_NO_STATE);
 1036  
                                 }
 1037  
                             }
 1038  98
                             childStates.add(new Object[]{null, descendantSavedState});
 1039  
                         }
 1040  110
                     }
 1041  
                     else
 1042  
                     {
 1043  80
                         if (childStates == null)
 1044  
                         {
 1045  80
                             childEmptyIndex++;
 1046  
                         }
 1047  
                         else
 1048  
                         {
 1049  0
                             childStates.add(LEAF_NO_STATE);
 1050  
                         }
 1051  
                     }
 1052  
                 }
 1053  288
                 totalChildCount++;
 1054  
             }
 1055  
         }
 1056  
         
 1057  224
         return childStates;
 1058  
     }
 1059  
     
 1060  
     
 1061  
     
 1062  
     @Override
 1063  
     public void markInitialState()
 1064  
     {
 1065  10
         if (isRowStatePreserved() && 
 1066  
             getFacesContext().getAttributes().containsKey(StateManager.IS_BUILDING_INITIAL_STATE))
 1067  
         {
 1068  6
             _initialDescendantFullComponentState
 1069  
                     = saveDescendantInitialComponentStates(getFacesContext(), getChildren().iterator(), false);
 1070  
         }
 1071  10
         super.markInitialState();
 1072  10
     }
 1073  
 
 1074  
     private void restoreFullDescendantComponentStates(FacesContext facesContext,
 1075  
             Iterator<UIComponent> childIterator, Object initialState,
 1076  
             boolean restoreChildFacets)
 1077  
     {
 1078  60
         Iterator<? extends Object[]> descendantStateIterator = null;
 1079  100
         while (childIterator.hasNext())
 1080  
         {
 1081  40
             if (descendantStateIterator == null && initialState != null)
 1082  
             {
 1083  40
                 descendantStateIterator = ((Collection<? extends Object[]>) initialState)
 1084  
                         .iterator();
 1085  
             }
 1086  40
             UIComponent component = childIterator.next();
 1087  
 
 1088  
             // reset the client id (see spec 3.1.6)
 1089  40
             component.setId(component.getId());
 1090  40
             if (!component.isTransient())
 1091  
             {
 1092  40
                 Object childState = null;
 1093  40
                 Object descendantState = null;
 1094  40
                 String childId = null;
 1095  40
                 if (descendantStateIterator != null
 1096  
                         && descendantStateIterator.hasNext())
 1097  
                 {
 1098  
                     do
 1099  
                     {
 1100  40
                         Object[] object = descendantStateIterator.next();
 1101  40
                         childState = object[0];
 1102  40
                         descendantState = object[1];
 1103  40
                         childId = (String) object[2];
 1104  
                     }
 1105  40
                     while(descendantStateIterator.hasNext() && !component.getId().equals(childId));
 1106  
                     
 1107  40
                     if (!component.getId().equals(childId))
 1108  
                     {
 1109  
                         // cannot apply initial state to components correctly.
 1110  0
                         throw new IllegalStateException("Cannot restore row correctly.");
 1111  
                     }
 1112  
                 }
 1113  
                 
 1114  40
                 component.clearInitialState();
 1115  40
                 component.restoreState(facesContext, childState);
 1116  40
                 component.markInitialState();
 1117  
                 
 1118  
                 Iterator<UIComponent> childsIterator;
 1119  40
                 if (restoreChildFacets)
 1120  
                 {
 1121  20
                     childsIterator = component.getFacetsAndChildren();
 1122  
                 }
 1123  
                 else
 1124  
                 {
 1125  20
                     childsIterator = component.getChildren().iterator();
 1126  
                 }
 1127  40
                 restoreFullDescendantComponentStates(facesContext, childsIterator,
 1128  
                         descendantState, true);
 1129  
             }
 1130  40
         }
 1131  60
     }
 1132  
 
 1133  
     private Collection<Object[]> saveDescendantInitialComponentStates(FacesContext facesContext,
 1134  
             Iterator<UIComponent> childIterator, boolean saveChildFacets)
 1135  
     {
 1136  18
         Collection<Object[]> childStates = null;
 1137  30
         while (childIterator.hasNext())
 1138  
         {
 1139  12
             if (childStates == null)
 1140  
             {
 1141  12
                 childStates = new ArrayList<Object[]>();
 1142  
             }
 1143  
 
 1144  12
             UIComponent child = childIterator.next();
 1145  12
             if (!child.isTransient())
 1146  
             {
 1147  
                 // Add an entry to the collection, being an array of two
 1148  
                 // elements. The first element is the state of the children
 1149  
                 // of this component; the second is the state of the current
 1150  
                 // child itself.
 1151  
 
 1152  
                 Iterator<UIComponent> childsIterator;
 1153  12
                 if (saveChildFacets)
 1154  
                 {
 1155  6
                     childsIterator = child.getFacetsAndChildren();
 1156  
                 }
 1157  
                 else
 1158  
                 {
 1159  6
                     childsIterator = child.getChildren().iterator();
 1160  
                 }
 1161  12
                 Object descendantState = saveDescendantInitialComponentStates(
 1162  
                         facesContext, childsIterator, true);
 1163  12
                 Object state = null;
 1164  12
                 if (child.initialStateMarked())
 1165  
                 {
 1166  0
                     child.clearInitialState();
 1167  0
                     state = child.saveState(facesContext); 
 1168  0
                     child.markInitialState();
 1169  
                 }
 1170  
                 else
 1171  
                 {
 1172  12
                     state = child.saveState(facesContext);
 1173  
                 }
 1174  
                 
 1175  12
                 childStates.add(new Object[] { state, descendantState, child.getId()});
 1176  
             }
 1177  12
         }
 1178  18
         return childStates;
 1179  
     }
 1180  
     
 1181  
     private Map<String,Object> saveFullDescendantComponentStates(FacesContext facesContext, Map<String,Object> stateMap,
 1182  
             Iterator<UIComponent> childIterator, boolean saveChildFacets)
 1183  
     {
 1184  180
         while (childIterator.hasNext())
 1185  
         {
 1186  72
             UIComponent child = childIterator.next();
 1187  72
             if (!child.isTransient())
 1188  
             {
 1189  
                 // Add an entry to the collection, being an array of two
 1190  
                 // elements. The first element is the state of the children
 1191  
                 // of this component; the second is the state of the current
 1192  
                 // child itself.
 1193  
 
 1194  
                 Iterator<UIComponent> childsIterator;
 1195  72
                 if (saveChildFacets)
 1196  
                 {
 1197  36
                     childsIterator = child.getFacetsAndChildren();
 1198  
                 }
 1199  
                 else
 1200  
                 {
 1201  36
                     childsIterator = child.getChildren().iterator();
 1202  
                 }
 1203  72
                 stateMap = saveFullDescendantComponentStates(facesContext, stateMap,
 1204  
                         childsIterator, true);
 1205  72
                 Object state = child.saveState(facesContext);
 1206  72
                 if (state != null)
 1207  
                 {
 1208  28
                     if (stateMap == null)
 1209  
                     {
 1210  28
                         stateMap = new HashMap<String,Object>();
 1211  
                     }
 1212  28
                     stateMap.put(child.getClientId(facesContext), state);
 1213  
                 }
 1214  
             }
 1215  72
         }
 1216  108
         return stateMap;
 1217  
     }
 1218  
     
 1219  
     private void restoreFullDescendantComponentDeltaStates(FacesContext facesContext,
 1220  
             Iterator<UIComponent> childIterator, Map<String, Object> state, Object initialState,
 1221  
             boolean restoreChildFacets)
 1222  
     {
 1223  48
         Iterator<? extends Object[]> descendantFullStateIterator = null;
 1224  80
         while (childIterator.hasNext())
 1225  
         {
 1226  32
             if (descendantFullStateIterator == null && initialState != null)
 1227  
             {
 1228  32
                 descendantFullStateIterator = ((Collection<? extends Object[]>) initialState).iterator();
 1229  
             }
 1230  32
             UIComponent component = childIterator.next();
 1231  
 
 1232  
             // reset the client id (see spec 3.1.6)
 1233  32
             component.setId(component.getId());
 1234  32
             if (!component.isTransient())
 1235  
             {
 1236  32
                 Object childInitialState = null;
 1237  32
                 Object descendantInitialState = null;
 1238  32
                 Object childState = null;
 1239  32
                 String childId = null;
 1240  32
                 childState = (state == null) ? null : state.get(component.getClientId(facesContext));
 1241  32
                 if (descendantFullStateIterator != null
 1242  
                         && descendantFullStateIterator.hasNext())
 1243  
                 {
 1244  
                     do
 1245  
                     {
 1246  32
                         Object[] object = descendantFullStateIterator.next();
 1247  32
                         childInitialState = object[0];
 1248  32
                         descendantInitialState = object[1];
 1249  32
                         childId = (String) object[2];
 1250  32
                     }while(descendantFullStateIterator.hasNext() && !component.getId().equals(childId));
 1251  
                     
 1252  32
                     if (!component.getId().equals(childId))
 1253  
                     {
 1254  
                         // cannot apply initial state to components correctly. State is corrupt
 1255  0
                         throw new IllegalStateException("Cannot restore row correctly.");
 1256  
                     }
 1257  
                 }
 1258  
                 
 1259  32
                 component.clearInitialState();
 1260  32
                 if (childInitialState != null)
 1261  
                 {
 1262  32
                     component.restoreState(facesContext, childInitialState);
 1263  32
                     component.markInitialState();
 1264  32
                     component.restoreState(facesContext, childState);
 1265  
                 }
 1266  
                 else
 1267  
                 {
 1268  0
                     component.restoreState(facesContext, childState);
 1269  0
                     component.markInitialState();
 1270  
                 }
 1271  
                 
 1272  
                 Iterator<UIComponent> childsIterator;
 1273  32
                 if (restoreChildFacets)
 1274  
                 {
 1275  16
                     childsIterator = component.getFacetsAndChildren();
 1276  
                 }
 1277  
                 else
 1278  
                 {
 1279  16
                     childsIterator = component.getChildren().iterator();
 1280  
                 }
 1281  32
                 restoreFullDescendantComponentDeltaStates(facesContext, childsIterator,
 1282  
                         state, descendantInitialState , true);
 1283  
             }
 1284  32
         }
 1285  48
     }
 1286  
     
 1287  
     /**
 1288  
      * Overwrite the state of the child components of this component with data previously saved by method
 1289  
      * saveDescendantComponentStates.
 1290  
      * <p>
 1291  
      * The saved state info only covers those fields that are expected to vary between rows of a table. Other fields are
 1292  
      * not modified.
 1293  
      */
 1294  
     @SuppressWarnings("unchecked")
 1295  
     /*
 1296  
     private void restoreTransientDescendantComponentStates(FacesContext facesContext,
 1297  
     Iterator<UIComponent> childIterator, Object state,
 1298  
                                                   boolean restoreChildFacets)
 1299  
     {
 1300  
         Iterator<? extends Object[]> descendantStateIterator = null;
 1301  
         while (childIterator.hasNext())
 1302  
         {
 1303  
             if (descendantStateIterator == null && state != null)
 1304  
             {
 1305  
                 descendantStateIterator = ((Collection<? extends Object[]>) state).iterator();
 1306  
             }
 1307  
             UIComponent component = childIterator.next();
 1308  
 
 1309  
             // reset the client id (see spec 3.1.6)
 1310  
             component.setId(component.getId());
 1311  
             if (!component.isTransient())
 1312  
             {
 1313  
                 Object childState = null;
 1314  
                 Object descendantState = null;
 1315  
                 if (descendantStateIterator != null && descendantStateIterator.hasNext())
 1316  
                 {
 1317  
                     Object[] object = descendantStateIterator.next();
 1318  
                     childState = object[0];
 1319  
                     descendantState = object[1];
 1320  
                 }
 1321  
                 component.restoreTransientState(facesContext, childState);
 1322  
                 Iterator<UIComponent> childsIterator;
 1323  
                 if (restoreChildFacets)
 1324  
                 {
 1325  
                     childsIterator = component.getFacetsAndChildren();
 1326  
                 }
 1327  
                 else
 1328  
                 {
 1329  
                     childsIterator = component.getChildren().iterator();
 1330  
                 }
 1331  
                 restoreTransientDescendantComponentStates(facesContext, childsIterator, descendantState, true);
 1332  
             }
 1333  
         }
 1334  
     }*/
 1335  
     
 1336  
     private void restoreTransientDescendantComponentStates(FacesContext facesContext,
 1337  
                                                            Iterator<UIComponent> childIterator,
 1338  
                                                            Map<String, Object> state,
 1339  
                                                            boolean restoreChildFacets)
 1340  
     {
 1341  180
         while (childIterator.hasNext())
 1342  
         {
 1343  72
             UIComponent component = childIterator.next();
 1344  
 
 1345  
             // reset the client id (see spec 3.1.6)
 1346  72
             component.setId(component.getId());
 1347  72
             if (!component.isTransient())
 1348  
             {
 1349  72
                 component.restoreTransientState(facesContext,
 1350  
                         (state == null)
 1351  
                         ? null
 1352  
                         : state.get(component.getClientId(facesContext)));
 1353  
                 
 1354  
                 Iterator<UIComponent> childsIterator;
 1355  72
                 if (restoreChildFacets)
 1356  
                 {
 1357  36
                     childsIterator = component.getFacetsAndChildren();
 1358  
                 }
 1359  
                 else
 1360  
                 {
 1361  36
                     childsIterator = component.getChildren().iterator();
 1362  
                 }
 1363  72
                 restoreTransientDescendantComponentStates(facesContext, childsIterator, state, true);
 1364  
             }
 1365  72
         }
 1366  
 
 1367  108
     }
 1368  
 
 1369  
     /**
 1370  
      * Walk the tree of child components of this UIData, saving the parts of their state that can vary between rows.
 1371  
      * <p>
 1372  
      * This is very similar to the process that occurs for normal components when the view is serialized. Transient
 1373  
      * components are skipped (no state is saved for them).
 1374  
      * <p>
 1375  
      * If there are no children then null is returned. If there are one or more children, and all children are transient
 1376  
      * then an empty collection is returned; this will happen whenever a table contains only read-only components.
 1377  
      * <p>
 1378  
      * Otherwise a collection is returned which contains an object for every non-transient child component; that object
 1379  
      * may itself contain a collection of the state of that child's child components.
 1380  
      */
 1381  
     /*
 1382  
     private Collection<Object[]> saveTransientDescendantComponentStates(FacesContext facesContext,
 1383  
                                                                Iterator<UIComponent> childIterator,
 1384  
                                                                boolean saveChildFacets)
 1385  
     {
 1386  
         Collection<Object[]> childStates = null;
 1387  
         while (childIterator.hasNext())
 1388  
         {
 1389  
             if (childStates == null)
 1390  
             {
 1391  
                 childStates = new ArrayList<Object[]>();
 1392  
             }
 1393  
             
 1394  
             UIComponent child = childIterator.next();
 1395  
             if (!child.isTransient())
 1396  
             {
 1397  
                 // Add an entry to the collection, being an array of two
 1398  
                 // elements. The first element is the state of the children
 1399  
                 // of this component; the second is the state of the current
 1400  
                 // child itself.
 1401  
 
 1402  
                 Iterator<UIComponent> childsIterator;
 1403  
                 if (saveChildFacets)
 1404  
                 {
 1405  
                     childsIterator = child.getFacetsAndChildren();
 1406  
                 }
 1407  
                 else
 1408  
                 {
 1409  
                     childsIterator = child.getChildren().iterator();
 1410  
                 }
 1411  
                 Object descendantState = saveTransientDescendantComponentStates(facesContext, childsIterator, true);
 1412  
                 Object state = null;
 1413  
                     state = child.saveTransientState(facesContext);
 1414  
                 childStates.add(new Object[] { state, descendantState });
 1415  
             }
 1416  
         }
 1417  
         return childStates;
 1418  
     }*/
 1419  
     
 1420  
     private Map<String, Object> saveTransientDescendantComponentStates(FacesContext facesContext,
 1421  
                                                                        Map<String, Object> childStates,
 1422  
                                                                        Iterator<UIComponent> childIterator,
 1423  
             boolean saveChildFacets)
 1424  
     {
 1425  140
         while (childIterator.hasNext())
 1426  
         {
 1427  56
             UIComponent child = childIterator.next();
 1428  56
             if (!child.isTransient())
 1429  
             {
 1430  
                 Iterator<UIComponent> childsIterator;
 1431  56
                 if (saveChildFacets)
 1432  
                 {
 1433  28
                     childsIterator = child.getFacetsAndChildren();
 1434  
                 }
 1435  
                 else
 1436  
                 {
 1437  28
                     childsIterator = child.getChildren().iterator();
 1438  
                 }
 1439  56
                 childStates = saveTransientDescendantComponentStates(facesContext, childStates, childsIterator, true);
 1440  56
                 Object state = child.saveTransientState(facesContext);
 1441  56
                 if (state != null)
 1442  
                 {
 1443  14
                     if (childStates == null)
 1444  
                     {
 1445  14
                         childStates = new HashMap<String, Object>();
 1446  
                     }
 1447  14
                     childStates.put(child.getClientId(facesContext), state);
 1448  
                 }
 1449  
             }
 1450  56
         }
 1451  84
         return childStates;
 1452  
     }
 1453  
 
 1454  
     @Override
 1455  
     public void restoreState(FacesContext context, Object state)
 1456  
     {
 1457  6
         if (state == null)
 1458  
         {
 1459  0
             return;
 1460  
         }
 1461  
         
 1462  6
         Object values[] = (Object[]) state;
 1463  6
         super.restoreState(context, values[0]);
 1464  6
         Object restoredRowStates = UIComponentBase.restoreAttachedState(context, values[1]);
 1465  6
         if (restoredRowStates == null)
 1466  
         {
 1467  0
             if (!_rowDeltaStates.isEmpty())
 1468  
             {
 1469  0
                 _rowDeltaStates.clear();
 1470  
             }
 1471  
         }
 1472  
         else
 1473  
         {
 1474  6
             _rowDeltaStates = (Map<String, Map<String, Object> >) restoredRowStates;
 1475  
         }
 1476  6
         if (values.length > 2)
 1477  
         {
 1478  6
             Object rs = UIComponentBase.restoreAttachedState(context, values[2]);
 1479  6
             if (rs == null)
 1480  
             {
 1481  0
                 if (!_rowStates.isEmpty())
 1482  
                 {
 1483  0
                     _rowStates.clear();
 1484  
                 }
 1485  
             }
 1486  
             else
 1487  
             {
 1488  6
                 _rowStates = (Map<String, Object>) rs;
 1489  
             }
 1490  
         }
 1491  6
         if (values.length > 3)
 1492  
         {
 1493  6
             Object rs = UIComponentBase.restoreAttachedState(context, values[3]);
 1494  6
             if (rs == null)
 1495  
             {
 1496  0
                 if (!_rowTransientStates.isEmpty())
 1497  
                 {
 1498  0
                     _rowTransientStates.clear();
 1499  
                 }
 1500  
             }
 1501  
             else
 1502  
             {
 1503  6
                 _rowTransientStates = (Map<String, Map<String, Object> >) rs;
 1504  
             }
 1505  
         }
 1506  6
     }
 1507  
 
 1508  
     @Override
 1509  
     public Object saveState(FacesContext context)
 1510  
     {
 1511  6
         if (context.getViewRoot() != null)
 1512  
         {
 1513  6
             if (context.getViewRoot().getResetSaveStateMode() == RESET_MODE_SOFT)
 1514  
             {
 1515  0
                 _dataModelMap.clear();
 1516  0
                 _isValidChilds=true;
 1517  0
                 _rowTransientStates.clear();
 1518  
             }
 1519  6
             if (context.getViewRoot().getResetSaveStateMode() == RESET_MODE_HARD)
 1520  
             {
 1521  0
                 _dataModelMap.clear();
 1522  0
                 _isValidChilds=true;
 1523  0
                 _rowTransientStates.clear();
 1524  0
                 _rowStates.clear();
 1525  0
                 _rowDeltaStates.clear();
 1526  
             }
 1527  
         }
 1528  6
         if (initialStateMarked())
 1529  
         {
 1530  4
             Object parentSaved = super.saveState(context);
 1531  4
             if (context.getCurrentPhaseId() != null && 
 1532  
                 !PhaseId.RENDER_RESPONSE.equals(context.getCurrentPhaseId()))
 1533  
             {
 1534  4
                 if (parentSaved == null &&_rowDeltaStates.isEmpty() && _rowStates.isEmpty())
 1535  
                 {
 1536  0
                     return null;
 1537  
                 }
 1538  
                 else
 1539  
                 {
 1540  4
                     Object values[] = new Object[4];
 1541  4
                     values[0] = super.saveState(context);
 1542  4
                     values[1] = UIComponentBase.saveAttachedState(context, _rowDeltaStates);
 1543  4
                     values[2] = UIComponentBase.saveAttachedState(context, _rowStates);
 1544  4
                     values[3] = UIComponentBase.saveAttachedState(context, _rowTransientStates);
 1545  4
                     return values;
 1546  
                 }
 1547  
             }
 1548  
             else
 1549  
             {
 1550  0
                 if (parentSaved == null &&_rowDeltaStates.isEmpty())
 1551  
                 {
 1552  0
                     return null;
 1553  
                 }
 1554  
                 else
 1555  
                 {
 1556  0
                     Object values[] = new Object[2];
 1557  0
                     values[0] = super.saveState(context);
 1558  0
                     values[1] = UIComponentBase.saveAttachedState(context, _rowDeltaStates);
 1559  0
                     return values; 
 1560  
                 }
 1561  
             }
 1562  
         }
 1563  
         else
 1564  
         {
 1565  2
             if (context.getCurrentPhaseId() != null && 
 1566  
                 !PhaseId.RENDER_RESPONSE.equals(context.getCurrentPhaseId()))
 1567  
             {
 1568  2
                 Object values[] = new Object[4];
 1569  2
                 values[0] = super.saveState(context);
 1570  2
                 values[1] = UIComponentBase.saveAttachedState(context, _rowDeltaStates);
 1571  2
                 values[2] = UIComponentBase.saveAttachedState(context, _rowStates);
 1572  2
                 values[3] = UIComponentBase.saveAttachedState(context, _rowTransientStates);
 1573  2
                 return values; 
 1574  
             }
 1575  
             else
 1576  
             {
 1577  0
                 Object values[] = new Object[2];
 1578  0
                 values[0] = super.saveState(context);
 1579  0
                 values[1] = UIComponentBase.saveAttachedState(context, _rowDeltaStates);
 1580  0
                 return values;
 1581  
             }
 1582  
         }
 1583  
     }
 1584  
 
 1585  
     @Override
 1586  
     public void setValueExpression(String name, ValueExpression binding)
 1587  
     {
 1588  32
         if (name == null)
 1589  
         {
 1590  2
             throw new NullPointerException("name");
 1591  
         }
 1592  30
         else if (name.equals("value"))
 1593  
         {
 1594  16
             _dataModelMap.clear();
 1595  
         }
 1596  14
         else if (name.equals("rowIndex"))
 1597  
         {
 1598  2
             throw new IllegalArgumentException("name " + name);
 1599  
         }
 1600  28
         super.setValueExpression(name, binding);
 1601  28
     }
 1602  
 
 1603  
     /*
 1604  
     @Override
 1605  
     public String getClientId(FacesContext context)
 1606  
     {
 1607  
         String clientId = super.getClientId(context);
 1608  
         int rowIndex = getRowIndex();
 1609  
         if (rowIndex == -1)
 1610  
         {
 1611  
             return clientId;
 1612  
         }
 1613  
 
 1614  
         StringBuilder bld = _getSharedStringBuilder();
 1615  
         return bld.append(clientId).append(UINamingContainer.getSeparatorChar(context)).append(rowIndex).toString();
 1616  
     }*/
 1617  
 
 1618  
     @Override
 1619  
     public String getContainerClientId(FacesContext context)
 1620  
     {
 1621  
         //MYFACES-2744 UIData.getClientId() should not append rowIndex, instead use UIData.getContainerClientId()
 1622  524
         String clientId = super.getContainerClientId(context);
 1623  
         
 1624  524
         int rowIndex = getRowIndex();
 1625  524
         if (rowIndex == -1)
 1626  
         {
 1627  24
             return clientId;
 1628  
         }
 1629  
 
 1630  500
         StringBuilder bld = _getSharedStringBuilder(context);
 1631  500
         return bld.append(clientId).append(context.getNamingContainerSeparatorChar()).append(rowIndex).toString();
 1632  
     }
 1633  
 
 1634  
     /**
 1635  
      * Modify events queued for any child components so that the UIData state will be correctly configured before the
 1636  
      * event's listeners are executed.
 1637  
      * <p>
 1638  
      * Child components or their renderers may register events against those child components. When the listener for
 1639  
      * that event is eventually invoked, it may expect the uidata's rowData and rowIndex to be referring to the same
 1640  
      * object that caused the event to fire.
 1641  
      * <p>
 1642  
      * The original queueEvent call against the child component has been forwarded up the chain of ancestors in the
 1643  
      * standard way, making it possible here to wrap the event in a new event whose source is <i>this</i> component, not
 1644  
      * the original one. When the event finally is executed, this component's broadcast method is invoked, which ensures
 1645  
      * that the UIData is set to be at the correct row before executing the original event.
 1646  
      */
 1647  
     @Override
 1648  
     public void queueEvent(FacesEvent event)
 1649  
     {
 1650  2
         if (event == null)
 1651  
         {
 1652  0
             throw new NullPointerException("event");
 1653  
         }
 1654  2
         super.queueEvent(new FacesEventWrapper(event, getRowIndex(), this));
 1655  2
     }
 1656  
 
 1657  
     /**
 1658  
      * Ensure that before the event's listeners are invoked this UIData component's "current row" is set to the row
 1659  
      * associated with the event.
 1660  
      * <p>
 1661  
      * See queueEvent for more details.
 1662  
      */
 1663  
     @Override
 1664  
     public void broadcast(FacesEvent event) throws AbortProcessingException
 1665  
     {
 1666  2
         if (event instanceof FacesEventWrapper)
 1667  
         {
 1668  2
             FacesEvent originalEvent = ((FacesEventWrapper) event).getWrappedFacesEvent();
 1669  2
             int eventRowIndex = ((FacesEventWrapper) event).getRowIndex();
 1670  2
             final int currentRowIndex = getRowIndex();
 1671  2
             UIComponent source = originalEvent.getComponent();
 1672  2
             UIComponent compositeParent = UIComponent.getCompositeComponentParent(source);
 1673  
 
 1674  2
             setRowIndex(eventRowIndex);
 1675  2
             if (compositeParent != null)
 1676  
             {
 1677  0
                 pushComponentToEL(getFacesContext(), compositeParent);
 1678  
             }
 1679  2
             pushComponentToEL(getFacesContext(), source);
 1680  
             try
 1681  
             {
 1682  2
                 source.broadcast(originalEvent);
 1683  
             }
 1684  
             finally
 1685  
             {
 1686  2
                 source.popComponentFromEL(getFacesContext());
 1687  2
                 if (compositeParent != null)
 1688  
                 {
 1689  0
                     compositeParent.popComponentFromEL(getFacesContext());
 1690  
                 }
 1691  2
                 setRowIndex(currentRowIndex);
 1692  2
             }
 1693  2
         }
 1694  
         else
 1695  
         {
 1696  0
             super.broadcast(event);
 1697  
         }
 1698  2
     }
 1699  
 
 1700  
     /**
 1701  
      * 
 1702  
      * {@inheritDoc}
 1703  
      * 
 1704  
      * @since 2.0
 1705  
      */
 1706  
     public String createUniqueId(FacesContext context, String seed)
 1707  
     {
 1708  2
         StringBuilder bld = _getSharedStringBuilder(context);
 1709  
 
 1710  
         // Generate an identifier for a component. The identifier will be prefixed with UNIQUE_ID_PREFIX,
 1711  
         // and will be unique within this UIViewRoot.
 1712  2
         if(seed==null)
 1713  
         {
 1714  2
             Long uniqueIdCounter = (Long) getStateHelper().get(PropertyKeys.uniqueIdCounter);
 1715  2
             uniqueIdCounter = (uniqueIdCounter == null) ? 0 : uniqueIdCounter;
 1716  2
             getStateHelper().put(PropertyKeys.uniqueIdCounter, (uniqueIdCounter+1L));
 1717  2
             return bld.append(UIViewRoot.UNIQUE_ID_PREFIX).append(uniqueIdCounter).toString();    
 1718  
         }
 1719  
         // Optionally, a unique seed value can be supplied by component creators
 1720  
         // which should be included in the generated unique id.
 1721  
         else
 1722  
         {
 1723  0
             return bld.append(UIViewRoot.UNIQUE_ID_PREFIX).append(seed).toString();
 1724  
         }
 1725  
     }
 1726  
 
 1727  
     /**
 1728  
      * Perform necessary actions when rendering of this component starts, before delegating to the inherited
 1729  
      * implementation which calls the associated renderer's encodeBegin method.
 1730  
      */
 1731  
     @Override
 1732  
     public void encodeBegin(FacesContext context) throws IOException
 1733  
     {
 1734  2
         _initialDescendantComponentState = null;
 1735  2
         if (_isValidChilds && !hasErrorMessages(context))
 1736  
         {
 1737  
             // Clear the data model so that when rendering code calls
 1738  
             // getDataModel a fresh model is fetched from the backing
 1739  
             // bean via the value-binding.
 1740  2
             _dataModelMap.clear();
 1741  
 
 1742  
             // When the data model is cleared it is also necessary to
 1743  
             // clear the saved row state, as there is an implicit 1:1
 1744  
             // relation between objects in the _rowStates and the
 1745  
             // corresponding DataModel element.
 1746  2
             if (!isRowStatePreserved())
 1747  
             {
 1748  2
                 _rowStates.clear();
 1749  
             }
 1750  
         }
 1751  2
         super.encodeBegin(context);
 1752  2
     }
 1753  
 
 1754  
     private boolean hasErrorMessages(FacesContext context)
 1755  
     {
 1756  
         // perf: getMessageList() return a RandomAccess instance.
 1757  
         // See org.apache.myfaces.context.servlet.FacesContextImpl.addMessage
 1758  2
         List<FacesMessage> messageList = context.getMessageList();
 1759  2
         for (int i = 0, size = messageList.size(); i < size;  i++)
 1760  
         {
 1761  0
             FacesMessage message = messageList.get(i);
 1762  0
             if (FacesMessage.SEVERITY_ERROR.compareTo(message.getSeverity()) <= 0)
 1763  
             {
 1764  0
                 return true;
 1765  
             }
 1766  
         }
 1767  2
         return false;
 1768  
     }
 1769  
 
 1770  
     /**
 1771  
      * @see javax.faces.component.UIComponentBase#encodeEnd(javax.faces.context.FacesContext)
 1772  
      */
 1773  
     @Override
 1774  
     public void encodeEnd(FacesContext context) throws IOException
 1775  
     {
 1776  
         try
 1777  
         {
 1778  0
             setCachedFacesContext(context);
 1779  0
             setRowIndex(-1);
 1780  
         }
 1781  
         finally
 1782  
         {
 1783  0
             setCachedFacesContext(null);
 1784  0
         }
 1785  0
         super.encodeEnd(context);
 1786  0
     }
 1787  
 
 1788  
     @Override
 1789  
     public void processDecodes(FacesContext context)
 1790  
     {
 1791  8
         if (context == null)
 1792  
         {
 1793  0
             throw new NullPointerException("context");
 1794  
         }
 1795  
         try
 1796  
         {
 1797  8
             setCachedFacesContext(context);
 1798  8
             pushComponentToEL(context, this);
 1799  8
             if (!isRendered())
 1800  
             {
 1801  
                 return;
 1802  
             }
 1803  6
             setRowIndex(-1);
 1804  6
             processFacets(context, PROCESS_DECODES);
 1805  6
             processColumnFacets(context, PROCESS_DECODES);
 1806  6
             processColumnChildren(context, PROCESS_DECODES);
 1807  6
             setRowIndex(-1);
 1808  
             try
 1809  
             {
 1810  6
                 decode(context);
 1811  
             }
 1812  0
             catch (RuntimeException e)
 1813  
             {
 1814  0
                 context.renderResponse();
 1815  0
                 throw e;
 1816  6
             }
 1817  
         }
 1818  
         finally
 1819  
         {
 1820  8
             popComponentFromEL(context);
 1821  8
             setCachedFacesContext(null);
 1822  6
         }
 1823  6
     }
 1824  
 
 1825  
     @Override
 1826  
     public void processValidators(FacesContext context)
 1827  
     {
 1828  4
         if (context == null)
 1829  
         {
 1830  0
             throw new NullPointerException("context");
 1831  
         }
 1832  
 
 1833  
         try
 1834  
         {
 1835  4
             setCachedFacesContext(context);
 1836  4
             pushComponentToEL(context, this);
 1837  4
             if (!isRendered())
 1838  
             {
 1839  
                 return;
 1840  
             }
 1841  
             
 1842  
             //Pre validation event dispatch for component
 1843  2
             context.getApplication().publishEvent(context,  PreValidateEvent.class, getClass(), this);
 1844  
             
 1845  
             try
 1846  
             {
 1847  2
                 setRowIndex(-1);
 1848  2
                 processFacets(context, PROCESS_VALIDATORS);
 1849  2
                 processColumnFacets(context, PROCESS_VALIDATORS);
 1850  2
                 processColumnChildren(context, PROCESS_VALIDATORS);
 1851  2
                 setRowIndex(-1);
 1852  
             }
 1853  
             finally
 1854  
             {
 1855  2
                 context.getApplication().publishEvent(context,  PostValidateEvent.class, getClass(), this);
 1856  2
             }
 1857  
             
 1858  
             // check if an validation error forces the render response for our data
 1859  2
             if (context.getRenderResponse())
 1860  
             {
 1861  0
                 _isValidChilds = false;
 1862  
             }
 1863  
         }
 1864  
         finally
 1865  
         {
 1866  4
             popComponentFromEL(context);
 1867  4
             setCachedFacesContext(null);
 1868  2
         }
 1869  2
     }
 1870  
 
 1871  
     @Override
 1872  
     public void processUpdates(FacesContext context)
 1873  
     {
 1874  4
         if (context == null)
 1875  
         {
 1876  0
             throw new NullPointerException("context");
 1877  
         }
 1878  
         try
 1879  
         {
 1880  4
             setCachedFacesContext(context);
 1881  4
             pushComponentToEL(context, this);
 1882  4
             if (!isRendered())
 1883  
             {
 1884  
                 return;
 1885  
             }
 1886  2
             setRowIndex(-1);
 1887  2
             processFacets(context, PROCESS_UPDATES);
 1888  2
             processColumnFacets(context, PROCESS_UPDATES);
 1889  2
             processColumnChildren(context, PROCESS_UPDATES);
 1890  2
             setRowIndex(-1);
 1891  
     
 1892  2
             if (context.getRenderResponse())
 1893  
             {
 1894  0
                 _isValidChilds = false;
 1895  
             }
 1896  
         }
 1897  
         finally
 1898  
         {
 1899  4
             popComponentFromEL(context);
 1900  4
             setCachedFacesContext(null);
 1901  2
         }
 1902  2
     }
 1903  
 
 1904  
     private void processFacets(FacesContext context, int processAction)
 1905  
     {
 1906  10
         if (this.getFacetCount() > 0)
 1907  
         {
 1908  0
             for (UIComponent facet : getFacets().values())
 1909  
             {
 1910  0
                 process(context, facet, processAction);
 1911  0
             }
 1912  
         }
 1913  10
     }
 1914  
 
 1915  
     /**
 1916  
      * Invoke the specified phase on all facets of all UIColumn children of this component. Note that no methods are
 1917  
      * called on the UIColumn child objects themselves.
 1918  
      * 
 1919  
      * @param context
 1920  
      *            is the current faces context.
 1921  
      * @param processAction
 1922  
      *            specifies a JSF phase: decode, validate or update.
 1923  
      */
 1924  
     private void processColumnFacets(FacesContext context, int processAction)
 1925  
     {
 1926  20
         for (int i = 0, childCount = getChildCount(); i < childCount; i++)
 1927  
         {
 1928  10
             UIComponent child = getChildren().get(i);
 1929  10
             if (child instanceof UIColumn)
 1930  
             {
 1931  10
                 if (! _ComponentUtils.isRendered(context, child))
 1932  
                 {
 1933  
                     // Column is not visible
 1934  0
                     continue;
 1935  
                 }
 1936  
                 
 1937  10
                 if (child.getFacetCount() > 0)
 1938  
                 {
 1939  0
                     for (UIComponent facet : child.getFacets().values())
 1940  
                     {
 1941  0
                         process(context, facet, processAction);
 1942  0
                     }
 1943  
                 }
 1944  
             }
 1945  
         }
 1946  10
     }
 1947  
 
 1948  
     /**
 1949  
      * Invoke the specified phase on all non-facet children of all UIColumn children of this component. Note that no
 1950  
      * methods are called on the UIColumn child objects themselves.
 1951  
      * 
 1952  
      * @param context
 1953  
      *            is the current faces context.
 1954  
      * @param processAction
 1955  
      *            specifies a JSF phase: decode, validate or update.
 1956  
      */
 1957  
     private void processColumnChildren(FacesContext context, int processAction)
 1958  
     {
 1959  10
         int first = getFirst();
 1960  10
         int rows = getRows();
 1961  
         int last;
 1962  10
         if (rows == 0)
 1963  
         {
 1964  6
             last = getRowCount();
 1965  
         }
 1966  
         else
 1967  
         {
 1968  4
             last = first + rows;
 1969  
         }
 1970  30
         for (int rowIndex = first; last == -1 || rowIndex < last; rowIndex++)
 1971  
         {
 1972  22
             setRowIndex(rowIndex);
 1973  
 
 1974  
             // scrolled past the last row
 1975  22
             if (!isRowAvailable())
 1976  
             {
 1977  2
                 break;
 1978  
             }
 1979  
             
 1980  40
             for (int i = 0, childCount = getChildCount(); i < childCount; i++)
 1981  
             {
 1982  20
                 UIComponent child = getChildren().get(i);
 1983  20
                 if (child instanceof UIColumn)
 1984  
                 {
 1985  20
                     if (! _ComponentUtils.isRendered(context, child))
 1986  
                     {
 1987  
                         // Column is not visible
 1988  0
                         continue;
 1989  
                     }
 1990  40
                     for (int j = 0, columnChildCount = child.getChildCount(); j < columnChildCount; j++)
 1991  
                     {
 1992  20
                         UIComponent columnChild = child.getChildren().get(j);
 1993  20
                         process(context, columnChild, processAction);
 1994  
                     }
 1995  
                 }
 1996  
             }
 1997  
         }
 1998  10
     }
 1999  
 
 2000  
     private void process(FacesContext context, UIComponent component, int processAction)
 2001  
     {
 2002  20
         switch (processAction)
 2003  
         {
 2004  
             case PROCESS_DECODES:
 2005  20
                 component.processDecodes(context);
 2006  20
                 break;
 2007  
             case PROCESS_VALIDATORS:
 2008  0
                 component.processValidators(context);
 2009  0
                 break;
 2010  
             case PROCESS_UPDATES:
 2011  0
                 component.processUpdates(context);
 2012  0
                 break;
 2013  
             default:
 2014  
                 // do nothing
 2015  
         }
 2016  20
     }
 2017  
 
 2018  
     /**
 2019  
      * Return the datamodel for this table, potentially fetching the data from a backing bean via a value-binding if
 2020  
      * this is the first time this method has been called.
 2021  
      * <p>
 2022  
      * This is complicated by the fact that this table may be nested within another table. In this case a different
 2023  
      * datamodel should be fetched for each row. When nested within a parent table, the parent reference won't change
 2024  
      * but parent.getContainerClientId() will, as the suffix changes
 2025  
      * depending upon the current row index. A map object on this
 2026  
      * component is therefore used to cache the datamodel for each row of the table. In the normal case where this table
 2027  
      * is not nested inside a component that changes its id (like a table does) then this map only ever has one entry.
 2028  
      */
 2029  
     protected DataModel getDataModel()
 2030  
     {
 2031  
         DataModel dataModel;
 2032  458
         String clientID = "";
 2033  
 
 2034  458
         UIComponent parent = getParent();
 2035  458
         if (parent != null)
 2036  
         {
 2037  406
             clientID = parent.getContainerClientId(getFacesContext());
 2038  
         }
 2039  458
         dataModel = _dataModelMap.get(clientID);
 2040  458
         if (dataModel == null)
 2041  
         {
 2042  44
             dataModel = createDataModel();
 2043  44
             _dataModelMap.put(clientID, dataModel);
 2044  
         }
 2045  458
         return dataModel;
 2046  
     }
 2047  
 
 2048  
     protected void setDataModel(DataModel dataModel)
 2049  
     {
 2050  0
         String clientID = "";
 2051  
 
 2052  0
         UIComponent parent = getParent();
 2053  0
         if (parent != null)
 2054  
         {
 2055  0
             clientID = parent.getContainerClientId(getFacesContext());
 2056  
         }
 2057  0
         if (dataModel == null)
 2058  
         {
 2059  0
             _dataModelMap.remove(clientID);
 2060  
         }
 2061  
         else
 2062  
         {
 2063  0
             _dataModelMap.put(clientID, dataModel);
 2064  
         }
 2065  0
     }
 2066  
 
 2067  
     /**
 2068  
      * Evaluate this object's value property and convert the result into a DataModel. Normally this object's value
 2069  
      * property will be a value-binding which will cause the value to be fetched from some backing bean.
 2070  
      * <p>
 2071  
      * The result of fetching the value may be a DataModel object, in which case that object is returned directly. If
 2072  
      * the value is of type List, Array, ResultSet, Result, other object or null then an appropriate wrapper is created
 2073  
      * and returned.
 2074  
      * <p>
 2075  
      * Null is never returned by this method.
 2076  
      */
 2077  
     private DataModel createDataModel()
 2078  
     {
 2079  44
         Object value = getValue();
 2080  
 
 2081  44
         if (value == null)
 2082  
         {
 2083  12
             return EMPTY_DATA_MODEL;
 2084  
         }
 2085  32
         else if (value instanceof DataModel)
 2086  
         {
 2087  12
             return (DataModel) value;
 2088  
         }
 2089  20
         else if (value instanceof List)
 2090  
         {
 2091  18
             return new ListDataModel((List<?>) value);
 2092  
         }
 2093  2
         else if (OBJECT_ARRAY_CLASS.isAssignableFrom(value.getClass()))
 2094  
         {
 2095  0
             return new ArrayDataModel((Object[]) value);
 2096  
         }
 2097  2
         else if (value instanceof ResultSet)
 2098  
         {
 2099  0
             return new ResultSetDataModel((ResultSet) value);
 2100  
         }
 2101  2
         else if (value instanceof Result)
 2102  
         {
 2103  0
             return new ResultDataModel((Result) value);
 2104  
         }
 2105  2
         else if (value instanceof Collection)
 2106  
         {
 2107  2
             return new CollectionDataModel((Collection) value);
 2108  
         }
 2109  
         else
 2110  
         {
 2111  0
             return new ScalarDataModel(value);
 2112  
         }
 2113  
     }
 2114  
 
 2115  
     /**
 2116  
      * An EL expression that specifies the data model that backs this table.
 2117  
      * <p>
 2118  
      * The value referenced by the EL expression can be of any type.
 2119  
      * </p>
 2120  
      * <ul>
 2121  
      * <li>A value of type DataModel is used directly.</li>
 2122  
      * <li>Array-like parameters of type array-of-Object, java.util.List, java.sql.ResultSet or
 2123  
      * javax.servlet.jsp.jstl.sql.Result are wrapped in a corresponding DataModel that knows how to iterate over the
 2124  
      * elements.</li>
 2125  
      * <li>Other values are wrapped in a DataModel as a single row.</li>
 2126  
      * </ul>
 2127  
      * <p>
 2128  
      * Note in particular that unordered collections, eg Set are not supported. Therefore if the value expression
 2129  
      * references such an object then the table will be considered to contain just one element - the collection itself.
 2130  
      * </p>
 2131  
      */
 2132  
     @JSFProperty
 2133  
     public Object getValue()
 2134  
     {
 2135  44
         return  getStateHelper().eval(PropertyKeys.value);
 2136  
     }
 2137  
 
 2138  
     public void setValue(Object value)
 2139  
     {
 2140  14
         getStateHelper().put(PropertyKeys.value, value );
 2141  14
         _dataModelMap.clear();
 2142  14
         _rowStates.clear();
 2143  14
         _isValidChilds = true;
 2144  14
     }
 2145  
 
 2146  
     /**
 2147  
      * Defines the index of the first row to be displayed, starting from 0.
 2148  
      */
 2149  
     @JSFProperty
 2150  
     public int getFirst()
 2151  
     {
 2152  16
         return (Integer) getStateHelper().eval(PropertyKeys.first,0);
 2153  
     }
 2154  
 
 2155  
     public void setFirst(int first)
 2156  
     { 
 2157  0
         if (first < 0)
 2158  
         {
 2159  0
             throw new IllegalArgumentException("Illegal value for first row: " + first);
 2160  
         }
 2161  0
         getStateHelper().put(PropertyKeys.first, first );
 2162  0
     }
 2163  
 
 2164  
     /**
 2165  
      * Defines the maximum number of rows of data to be displayed.
 2166  
      * <p>
 2167  
      * Specify zero to display all rows from the "first" row to the end of available data.
 2168  
      * </p>
 2169  
      */
 2170  
     @JSFProperty
 2171  
     public int getRows()
 2172  
     {
 2173  16
         return (Integer) getStateHelper().eval(PropertyKeys.rows,0);
 2174  
     }
 2175  
 
 2176  
     /**
 2177  
      * Set the maximum number of rows displayed in the table.
 2178  
      */
 2179  
     public void setRows(int rows)
 2180  
     {
 2181  8
         if (rows < 0)
 2182  
         {
 2183  0
             throw new IllegalArgumentException("rows: " + rows);
 2184  
         }
 2185  8
         getStateHelper().put(PropertyKeys.rows, rows ); 
 2186  8
     }
 2187  
 
 2188  
     /**
 2189  
      * Defines the name of the request-scope variable that will hold the current row during iteration.
 2190  
      * <p>
 2191  
      * During rendering of child components of this UIData, the variable with this name can be read to learn what the
 2192  
      * "rowData" object for the row currently being rendered is.
 2193  
      * </p>
 2194  
      * <p>
 2195  
      * This value must be a static value, ie an EL expression is not permitted.
 2196  
      * </p>
 2197  
      */
 2198  
     @JSFProperty(literalOnly = true)
 2199  
     public String getVar()
 2200  
     {
 2201  0
         return (String) getStateHelper().get(PropertyKeys.var);
 2202  
     }
 2203  
 
 2204  
     /**
 2205  
      * Overrides the behavior in 
 2206  
      * UIComponent.visitTree(javax.faces.component.visit.VisitContext, javax.faces.component.visit.VisitCallback)
 2207  
      * to handle iteration correctly.
 2208  
      * 
 2209  
      * @param context the visit context which handles the processing details
 2210  
      * @param callback the callback to be performed
 2211  
      * @return false if the processing is not done true if we can shortcut
 2212  
      * the visiting because we are done with everything
 2213  
      * 
 2214  
      * @since 2.0
 2215  
      */
 2216  
     @Override
 2217  
     public boolean visitTree(VisitContext context, VisitCallback callback)
 2218  
     {
 2219  
         // push the Component to EL
 2220  10
         pushComponentToEL(context.getFacesContext(), this);
 2221  
         try
 2222  
         {
 2223  10
             if (!isVisitable(context))
 2224  
             {
 2225  0
                 return false;
 2226  
             }
 2227  
 
 2228  10
             boolean isCachedFacesContext = isCachedFacesContext();
 2229  10
             if (!isCachedFacesContext)
 2230  
             {
 2231  10
                 setCachedFacesContext(context.getFacesContext());
 2232  
             }
 2233  
             // save the current row index
 2234  10
             int oldRowIndex = getRowIndex();
 2235  
             // set row index to -1 to process the facets and to get the rowless clientId
 2236  10
             setRowIndex(-1);
 2237  
             try
 2238  
             {
 2239  10
                 VisitResult visitResult = context.invokeVisitCallback(this,
 2240  
                         callback);
 2241  10
                 switch (visitResult)
 2242  
                 {
 2243  
                 //we are done nothing has to be processed anymore
 2244  
                 case COMPLETE:
 2245  0
                     return true;
 2246  
 
 2247  
                 case REJECT:
 2248  0
                     return false;
 2249  
 
 2250  
                     //accept
 2251  
                 default:
 2252  
                     // determine if we need to visit our children
 2253  10
                     Collection<String> subtreeIdsToVisit = context
 2254  
                             .getSubtreeIdsToVisit(this);
 2255  10
                     boolean doVisitChildren = subtreeIdsToVisit != null
 2256  
                             && !subtreeIdsToVisit.isEmpty();
 2257  10
                     if (doVisitChildren)
 2258  
                     {
 2259  
                         // visit the facets of the component
 2260  10
                         if (getFacetCount() > 0)
 2261  
                         {
 2262  10
                             for (UIComponent facet : getFacets().values())
 2263  
                             {
 2264  20
                                 if (facet.visitTree(context, callback))
 2265  
                                 {
 2266  0
                                     return true;
 2267  
                                 }
 2268  20
                             }
 2269  
                         }
 2270  10
                         boolean skipIterationHint = context.getHints().contains(VisitHint.SKIP_ITERATION);
 2271  10
                         if (skipIterationHint)
 2272  
                         {
 2273  
                             // If SKIP_ITERATION is enabled, do not take into account rows.
 2274  12
                             for (int i = 0, childCount = getChildCount(); i < childCount; i++ )
 2275  
                             {
 2276  8
                                 UIComponent child = getChildren().get(i);
 2277  8
                                 if (child.visitTree(context, callback))
 2278  
                                 {
 2279  0
                                     return true;
 2280  
                                 }
 2281  
                             }
 2282  
                         }
 2283  
                         else
 2284  
                         {
 2285  
                             // visit every column directly without visiting its children
 2286  
                             // (the children of every UIColumn will be visited later for
 2287  
                             // every row) and also visit the column's facets
 2288  18
                             for (int i = 0, childCount = getChildCount(); i < childCount; i++)
 2289  
                             {
 2290  12
                                 UIComponent child = getChildren().get(i);
 2291  12
                                 if (child instanceof UIColumn)
 2292  
                                 {
 2293  6
                                     VisitResult columnResult = context.invokeVisitCallback(child, callback);
 2294  6
                                     if (columnResult == VisitResult.COMPLETE)
 2295  
                                     {
 2296  0
                                         return true;
 2297  
                                     }
 2298  6
                                     if (child.getFacetCount() > 0)
 2299  
                                     {
 2300  6
                                         for (UIComponent facet : child.getFacets().values())
 2301  
                                         {
 2302  6
                                             if (facet.visitTree(context, callback))
 2303  
                                             {
 2304  0
                                                 return true;
 2305  
                                             }
 2306  6
                                         }
 2307  
                                     }
 2308  
                                 }
 2309  
                             }
 2310  
                             // iterate over the rows
 2311  6
                             int rowsToProcess = getRows();
 2312  
                             // if getRows() returns 0, all rows have to be processed
 2313  6
                             if (rowsToProcess == 0)
 2314  
                             {
 2315  6
                                 rowsToProcess = getRowCount();
 2316  
                             }
 2317  6
                             int rowIndex = getFirst();
 2318  24
                             for (int rowsProcessed = 0; rowsProcessed < rowsToProcess; rowsProcessed++, rowIndex++)
 2319  
                             {
 2320  18
                                 setRowIndex(rowIndex);
 2321  18
                                 if (!isRowAvailable())
 2322  
                                 {
 2323  0
                                     return false;
 2324  
                                 }
 2325  
                                 // visit the children of every child of the UIData that is an instance of UIColumn
 2326  54
                                 for (int i = 0, childCount = getChildCount(); i < childCount; i++)
 2327  
                                 {
 2328  36
                                     UIComponent child = getChildren().get(i);
 2329  36
                                     if (child instanceof UIColumn)
 2330  
                                     {
 2331  18
                                         for (int j = 0, grandChildCount = child.getChildCount();
 2332  54
                                              j < grandChildCount; j++)
 2333  
                                         {
 2334  18
                                             UIComponent grandchild = child.getChildren().get(j);
 2335  18
                                             if (grandchild.visitTree(context, callback))
 2336  
                                             {
 2337  0
                                                 return true;
 2338  
                                             }
 2339  
                                         }
 2340  
                                     }
 2341  
                                 }
 2342  
                             }
 2343  
                         }
 2344  
                     }
 2345  
                 }
 2346  
             }
 2347  
             finally
 2348  
             {
 2349  
                 // restore the old row index
 2350  10
                 setRowIndex(oldRowIndex);
 2351  10
                 if (!isCachedFacesContext)
 2352  
                 {
 2353  10
                     setCachedFacesContext(null);
 2354  
                 }
 2355  
             }
 2356  
         }
 2357  
         finally
 2358  
         {
 2359  
             // pop the component from EL
 2360  10
             popComponentFromEL(context.getFacesContext());
 2361  10
         }
 2362  
         // Return false to allow the visiting to continue
 2363  10
         return false;
 2364  
     }
 2365  
 
 2366  
     public void setVar(String var)
 2367  
     {
 2368  26
         getStateHelper().put(PropertyKeys.var, var ); 
 2369  26
     }
 2370  
     
 2371  
     /**
 2372  
      * Indicates whether the state for a component in each row should not be 
 2373  
      * discarded before the datatable is rendered again.
 2374  
      * 
 2375  
      * This property is similar to tomahawk t:dataTable preserveRowStates
 2376  
      * 
 2377  
      * This will only work reliable if the datamodel of the 
 2378  
      * datatable did not change either by sorting, removing or 
 2379  
      * adding rows. Default: false
 2380  
      * 
 2381  
      * @return
 2382  
      */
 2383  
     @JSFProperty(literalOnly=true, faceletsOnly=true)
 2384  
     public boolean isRowStatePreserved()
 2385  
     {
 2386  272
         Boolean b = (Boolean) getStateHelper().get(PropertyKeys.rowStatePreserved);
 2387  272
         return b == null ? false : b.booleanValue(); 
 2388  
     }
 2389  
     
 2390  
     public void setRowStatePreserved(boolean preserveComponentState)
 2391  
     {
 2392  8
         getStateHelper().put(PropertyKeys.rowStatePreserved, preserveComponentState);
 2393  8
     }
 2394  
 
 2395  16
     enum PropertyKeys
 2396  
     {
 2397  2
          value
 2398  2
         , first
 2399  2
         , rows
 2400  2
         , var
 2401  2
         , uniqueIdCounter
 2402  2
         , rowStatePreserved
 2403  
     }
 2404  
 
 2405  
     @Override
 2406  
     public String getFamily()
 2407  
     {
 2408  44
         return COMPONENT_FAMILY;
 2409  
     }
 2410  
 }