Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
   /*
    * JBoss, Home of Professional Open Source
    * Copyright ${year}, Red Hat, Inc. and individual contributors
    * by the @authors tag. See the copyright.txt in the distribution for a
    * full listing of individual contributors.
    *
    * This is free software; you can redistribute it and/or modify it
    * under the terms of the GNU Lesser General Public License as
    * published by the Free Software Foundation; either version 2.1 of
   * the License, or (at your option) any later version.
   *
   * This software is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
   * Lesser General Public License for more details.
   *
   * You should have received a copy of the GNU Lesser General Public
   * License along with this software; if not, write to the Free
   * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
   * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
   */
  package org.richfaces.component;
  
  import static org.richfaces.component.util.Strings.NamingContainerDataHolder.SEPARATOR_CHAR_JOINER;
  
  import java.util.Map;
  
  import  javax.faces.FacesException;
  import  javax.faces.application.Application;
  import  javax.faces.application.FacesMessage;
  import  javax.faces.application.FacesMessage.Severity;
  import  javax.faces.component.ContextCallback;
  import  javax.faces.component.EditableValueHolder;
  import  javax.faces.component.NamingContainer;
  import  javax.faces.component.PartialStateHolder;
  import  javax.faces.component.StateHelper;
  import  javax.faces.component.StateHolder;
  import  javax.faces.component.UIComponent;
  import  javax.faces.component.UIComponentBase;
  import  javax.faces.component.UIForm;
  import  javax.faces.component.UINamingContainer;
  import  javax.faces.component.UIViewRoot;
  import  javax.faces.component.UniqueIdVendor;
  import  javax.faces.component.visit.VisitCallback;
  import  javax.faces.component.visit.VisitContext;
  import  javax.faces.component.visit.VisitResult;
  import  javax.faces.context.FacesContext;
  import  javax.faces.convert.Converter;
  import  javax.faces.convert.ConverterException;
  import  javax.faces.event.AbortProcessingException;
  import  javax.faces.event.ComponentSystemEvent;
  import  javax.faces.event.ComponentSystemEventListener;
  import  javax.faces.event.FacesEvent;
  import  javax.faces.event.PostAddToViewEvent;
  import  javax.faces.event.PostRestoreStateEvent;
  import  javax.faces.event.PostValidateEvent;
  import  javax.faces.event.PreRenderViewEvent;
  import  javax.faces.event.PreValidateEvent;
  import  javax.faces.event.SystemEvent;
  import  javax.faces.event.SystemEventListener;
  
  import  org.ajax4jsf.component.IterationStateHolder;
  import  org.ajax4jsf.model.DataComponentState;
  import  org.ajax4jsf.model.DataVisitResult;
  import  org.ajax4jsf.model.DataVisitor;
  import  org.ajax4jsf.model.ExtendedDataModel;
  import  org.ajax4jsf.model.Range;
  import  org.richfaces.context.ExtendedVisitContext;
  import  org.richfaces.log.Logger;
  import  org.richfaces.log.RichfacesLogger;

Base class for iterable components, like dataTable, Tomahawk dataList, Facelets repeat, tree etc., with support for partial rendering on AJAX responces for one or more selected iterations.

Author(s):
shura
Lukas Fryc
  
  public abstract class UIDataAdaptor extends UIComponentBase implements NamingContainer, UniqueIdVendor, IterationStateHolder,
          ComponentSystemEventListener, SystemEventListener {
    

The standard component family for this component.

  
      public static final String COMPONENT_FAMILY = "org.richfaces.Data";
    

The standard component type for this component.

  
      public static final String COMPONENT_TYPE = "org.richfaces.Data";
  
     private String PRE_RENDER_VIEW_EVENT_REGISTERED = UIDataAdaptor.class.getName() + ":preRenderViewEventRegistered";
 
     private static final VisitCallback STUB_CALLBACK = new VisitCallback() {
         public VisitResult visit(VisitContext context, UIComponent target) {
             return VisitResult.ACCEPT;
         }
     };
     private static final Logger LOG = RichfacesLogger.COMPONENTS.getLogger();
    
Visitor for process decode on children components.
 
     protected ComponentVisitor decodeVisitor = new ComponentVisitor() {
         @Override
         public void processComponent(FacesContext context, UIComponent cObject argument) {
             c.processDecodes(context);
         }
     };
    
Visitor for process validation phase
 
     protected ComponentVisitor validateVisitor = new ComponentVisitor() {
         @Override
         public void processComponent(FacesContext context, UIComponent cObject argument) {
             c.processValidators(context);
         }
     };
    
Visitor for process update model phase.
 
     protected ComponentVisitor updateVisitor = new ComponentVisitor() {
         @Override
         public void processComponent(FacesContext context, UIComponent cObject argument) {
             c.processUpdates(context);
         }
     };
     // TODO nick - PSH support?
     private DataComponentState componentState = null;
     private ExtendedDataModel<?> extendedDataModel = null;
     private Object rowKey = null;
     private String containerClientId;
     private Object originalVarValue;
     private Converter rowKeyConverter;

    

Author(s):
Nick Belaevski
 
     private final class DataVisitorForVisitTree implements DataVisitor {
        
 
         private final VisitCallback callback;
        
 
         private final VisitContext visitContext;
        
 
         private boolean visitResult;

        

Parameters:
callback
visitContext
 
         private DataVisitorForVisitTree(VisitCallback callback, VisitContext visitContext) {
             this. = callback;
             this. = visitContext;
         }
 
         public DataVisitResult process(FacesContext contextObject rowKeyObject argument) {
             setRowKey(contextrowKey);
 
             if (isRowAvailable()) {
                 VisitResult result = VisitResult.ACCEPT;
 
                 if ( instanceof ExtendedVisitContext) {
                     result = .invokeVisitCallback(UIDataAdaptor.this);
                     if (VisitResult.COMPLETE.equals(result)) {
                          = true;
 
                         return DataVisitResult.STOP;
                     }
 
                     if (result == VisitResult.ACCEPT) {
                         result = visitDataChildrenMetaComponents((ExtendedVisitContext) );
                         if (VisitResult.COMPLETE.equals(result)) {
                              = true;
 
                             return DataVisitResult.STOP;
                         }
                     }
                 }
 
                 if (VisitResult.ACCEPT.equals(result)) {
                     Iterator<UIComponent> dataChildrenItr = dataChildren();
 
                     while (dataChildrenItr.hasNext()) {
                         UIComponent dataChild = dataChildrenItr.next();
 
                         if (dataChild.visitTree()) {
                              = true;
 
                             return DataVisitResult.STOP;
                         }
                     }
                 }
             }
 
             return DataVisitResult.CONTINUE;
         }
 
         public boolean getVisitResult() {
             return ;
         }
     }
 
     private enum PropertyKeys {
         lastId, var, rowKeyVar, stateVar, childState, rowKeyConverter, rowKeyConverterSet, keepSaved
     }
 
     public UIDataAdaptor() {
         super();
         subscribeToEvents();
     }
 
     protected Map<StringObjectgetVariablesMap(FacesContext facesContext) {
         return facesContext.getExternalContext().getRequestMap();
     }
 
     /*
      * (non-Javadoc)
      *
      * @see javax.faces.component.UIComponent#getFamily()
      */
     @Override
     public String getFamily() {
         return ;
     }
 
     /*
      * (non-Javadoc)
      *
      * @see javax.faces.component.UniqueIdVendor#createUniqueId(javax.faces.context.FacesContext, java.lang.String)
      */
     public String createUniqueId(FacesContext contextString seed) {
         Integer i = (IntegergetStateHelper().get(.);
         int lastId = (i != null) ? i : 0;
 
         getStateHelper().put(., ++lastId);
 
         return UIViewRoot.UNIQUE_ID_PREFIX + ((seed == null) ? lastId : seed);
     }

    
The attribute provides access to a row key in a Request scope
 
     public Object getRowKey() {
         return ;
     }

    
Setup current row by key. Perform same functionality as javax.faces.component.UIData.setRowIndex(int), but for key object - it may be not only row number in sequence data, but, for example - path to current node in tree.

Parameters:
facesContext - current FacesContext
rowKey new key value.
 
     public void setRowKey(FacesContext facesContextObject rowKey) {
         this.saveChildState(facesContext);
 
         this. = rowKey;
 
         getExtendedDataModel().setRowKey(rowKey);
 
         this. = null;
 
         boolean rowSelected = (rowKey != null) && isRowAvailable();
 
         setupVariable(facesContextrowSelected);
 
         this.restoreChildState(facesContext);
     }

    
Save values of EditableValueHolder fields before change current row.

Parameters:
facesContext
 
     protected void saveChildState(FacesContext facesContext) {
         Iterator<UIComponent> itr = dataChildren();
 
         while (itr.hasNext()) {
             this.saveChildState(facesContext, (UIComponent) itr.next());
         }
     }

    

Parameters:
facesContext
 
     protected void saveChildState(FacesContext facesContext, UIComponent component) {
 
         // TODO - is it right?
         if (component.isTransient()) {
             return;
         }
 
         SavedState state = null;
 
         if (component instanceof IterationStateHolder) {
             IterationStateHolder ish = (IterationStateHolder) component;
 
             state = new SavedState(ish);
         } else if (component instanceof EditableValueHolder) {
             EditableValueHolder evh = (EditableValueHolder) component;
 
             state = new SavedState(evh);
         } else if (component instanceof UIForm) {
             UIForm form = (UIForm) component;
 
             state = new SavedState(form);
         }
 
         if (state != null) {
 
             // TODO - use local map - children save their state themselves using visitors
             getStateHelper().put(.component.getClientId(facesContext), state);
         }
 
         if (component.getChildCount() > 0) {
             for (UIComponent child : component.getChildren()) {
                 saveChildState(facesContextchild);
             }
         }
 
         if (component.getFacetCount() > 0) {
             for (UIComponent facet : component.getFacets().values()) {
                 saveChildState(facesContextfacet);
             }
         }
     }
 
     protected Iterator<UIComponent> dataChildren() {
         if (getChildCount() > 0) {
             return getChildren().iterator();
         } else {
             return Collections.<UIComponent> emptyList().iterator();
         }
     }
 
     protected Iterator<UIComponent> fixedChildren() {
         if (getFacetCount() > 0) {
             return getFacets().values().iterator();
         } else {
             return Collections.<UIComponent> emptyList().iterator();
         }
     }
 
     protected Iterator<UIComponent> allFixedChildren() {
         if (getFacetCount() > 0) {
             return getFacets().values().iterator();
         } else {
             return Collections.<UIComponent> emptyList().iterator();
         }
     }

    

Parameters:
facesContext
 
     protected void restoreChildState(FacesContext facesContext) {
         Iterator<UIComponent> itr = dataChildren();
 
         while (itr.hasNext()) {
             this.restoreChildState(facesContext, (UIComponent) itr.next());
         }
     }

    
Restore values of EditableValueHolder fields after change current row.

Parameters:
facesContext
 
     protected void restoreChildState(FacesContext facesContext, UIComponent component) {
         String id = component.getId();
 
         component.setId(id); // Forces client id to be reset
 
         SavedState savedState = null;
         @SuppressWarnings("unchecked")
         Map<StringSavedStatesavedStatesMap = (Map<StringSavedState>) getStateHelper().get(.);
 
         if (savedStatesMap != null) {
             savedState = savedStatesMap.get(component.getClientId(facesContext));
         }
 
         if (savedState == null) {
             savedState = .;
         }
 
         if (component instanceof IterationStateHolder) {
             IterationStateHolder ish = (IterationStateHolder) component;
 
             savedState.apply(ish);
         } else if (component instanceof EditableValueHolder) {
             EditableValueHolder evh = (EditableValueHolder) component;
 
             savedState.apply(evh);
         } else if (component instanceof UIForm) {
             UIForm form = (UIForm) component;
 
             savedState.apply(form);
         }
 
         if (component.getChildCount() > 0) {
             for (UIComponent child : component.getChildren()) {
                 restoreChildState(facesContextchild);
             }
         }
 
         if (component.getFacetCount() > 0) {
             for (UIComponent facet : component.getFacets().values()) {
                 restoreChildState(facesContextfacet);
             }
         }
     }
 
     public void setRowKey(Object rowKey) {
         setRowKey(getFacesContext(), rowKey);
     }
 
     protected FacesEvent wrapEvent(FacesEvent event) {
         return new RowKeyContextEventWrapper(thiseventgetRowKey());
     }
 
     @Override
     public void queueEvent(FacesEvent event) {
         super.queueEvent(wrapEvent(event));
     }
 
     /*
      * (non-Javadoc)
      *
      * @see javax.faces.component.UIComponentBase#broadcast(javax.faces.event.FacesEvent)
      */
     @Override
     public void broadcast(FacesEvent eventthrows AbortProcessingException {
         if (event instanceof RowKeyContextEventWrapper) {
             RowKeyContextEventWrapper eventWrapper = (RowKeyContextEventWrapperevent;
 
             eventWrapper.broadcast(getFacesContext());
         } else {
             super.broadcast(event);
         }
     }

    

Returns:
the extendedDataModel
 
     protected ExtendedDataModel<?> getExtendedDataModel() {
         if ( == null) {
              = createExtendedDataModel();
         }
 
         return ;
     }
 
     protected abstract ExtendedDataModel<?> createExtendedDataModel();
 
     public void clearExtendedDataModel() {
         setExtendedDataModel(null);
     }

    

Parameters:
extendedDataModel the extendedDataModel to set
 
     protected void setExtendedDataModel(ExtendedDataModel<?> extendedDataModel) {
         this. = extendedDataModel;
     }
 
     @Attribute
     public String getVar() {
         return (StringgetStateHelper().get(.);
     }
 
     public void setVar(String var) {
         getStateHelper().put(.var);
     }
 
     @Attribute
     public String getRowKeyVar() {
         return (StringgetStateHelper().get(.);
     }
 
     public void setRowKeyVar(String rowKeyVar) {
         getStateHelper().put(.rowKeyVar);
     }

    
The attribute provides access to a component state on the client side
 
     @Attribute
     public String getStateVar() {
         return (StringgetStateHelper().get(.);
     }
 
     public void setStateVar(String stateVar) {
         getStateHelper().put(.stateVar);
     }
 
     // XXX - review and probably remove - useful method, should be left
     public int getRowCount() {
         return getExtendedDataModel().getRowCount();
     }
 
     public Object getRowData() {
         return getExtendedDataModel().getRowData();
     }
 
     public boolean isRowAvailable() {
         return getExtendedDataModel().isRowAvailable();
     }

    
Boolean attribute that defines whether this iteration component will reset saved children's state before rendering. By default state is reset if there are no faces messages with severity error or higher.
 
     @Attribute
     public boolean isKeepSaved() {
         Object value = getStateHelper().eval(.);
 
         if (value == null) {
             return keepSaved(getFacesContext());
         } else {
             return Boolean.valueOf(value.toString());
         }
     }
 
     public void setKeepSaved(boolean keepSaved) {
         getStateHelper().put(.keepSaved);
     }

    
Setup EL variable for different iteration. Value of row data and component state will be put into request scope attributes with names given by "var" and "varState" bean properties.

Changed: does not check for row availability now

Parameters:
faces current faces context
rowSelected
 
     protected void setupVariable(FacesContext facesboolean rowSelected) {
         Map<StringObjectattrs = getVariablesMap(faces);
 
         if (rowSelected) {
 
             // Current row data.
             setupVariable(getVar(), attrsgetRowData());
 
             // Component state variable.
             setupVariable(getStateVar(), attrsgetComponentState());
 
             // Row key Data variable.
             setupVariable(getRowKeyVar(), attrsgetRowKey());
         } else {
             removeVariable(getVar(), attrs);
             removeVariable(getStateVar(), attrs);
             removeVariable(getRowKeyVar(), attrs);
         }
     }
 
     public DataComponentState getComponentState() {
         if ( != null) {
             return ;
         }
 
         ValueExpression componentStateExpression = getValueExpression("componentState");
 
         if (componentStateExpression != null) {
              = (DataComponentState) componentStateExpression.getValue(getFacesContext().getELContext());
         }
 
         if ( == null) {
              = createComponentState();
 
             if ((componentStateExpression != null) && !componentStateExpression.isReadOnly(getFacesContext().getELContext())) {
                 componentStateExpression.setValue(getFacesContext().getELContext(), );
             }
         }
 
         return ;
     }
 
     protected abstract DataComponentState createComponentState();

    

Parameters:
var
attrs
rowData
 
     private void setupVariable(String varMap<StringObjectattrsObject rowData) {
         if (var != null) {
             attrs.put(varrowData);
         }
     }

    

Parameters:
var
attrs
 
     private void removeVariable(String varMap<StringObjectattrs) {
         if (var != null) {
             attrs.remove(var);
         }
     }
 
     @Attribute
     public Converter getRowKeyConverter() {
         if (this. != null) {
             return this.;
         }
 
         return (Converter) getStateHelper().eval(.);
     }
 
     public void setRowKeyConverter(Converter converter) {
         StateHelper stateHelper = getStateHelper();
         if (initialStateMarked()) {
             stateHelper.put(..);
         }
 
         this. = converter;
     }
 
     private boolean isSetRowKeyConverter() {
         Boolean value = (BooleangetStateHelper().get(.);
         return ..equals(value);
     }
 
     private String getRowKeyAsString(FacesContext facesContextObject rowKey) {
         assert rowKey != null;
 
         Converter rowKeyConverter = getRowKeyConverter();
         if (rowKeyConverter == null) {
             // Create default converter for a row key.
             rowKeyConverter = facesContext.getApplication().createConverter(rowKey.getClass());
 
             // Store converter for a invokeOnComponents call.
             if (rowKeyConverter != null) {
                 // TODO - review
                 setRowKeyConverter(rowKeyConverter);
             }
         }
 
         if (rowKeyConverter != null) {
             return rowKeyConverter.getAsString(facesContextthisrowKey);
         } else {
             return rowKey.toString();
         }
     }
 
     public String getContainerClientId() {
         return getContainerClientId(getFacesContext());
     }
 
     @Override
     public String getContainerClientId(FacesContext facesContext) {
         if (facesContext == null) {
             throw new NullPointerException("context");
         }
 
         if (null == ) {
              = super.getContainerClientId(facesContext);
 
             Object rowKey = getRowKey();
 
             if (rowKey != null) {
                 String rowKeyString = getRowKeyAsString(facesContextrowKey);
                  = .join(rowKeyString);
             }
         }
 
         return ;
     }

    
Save current state of data variable.

Parameters:
faces current faces context
 
 
     // TODO move into walk() method body
     public void captureOrigValue(FacesContext faces) {
         String var = getVar();
 
         if (var != null) {
             Map<StringObjectattrs = getVariablesMap(faces);
 
             this. = attrs.get(var);
         }
 
         // TODO add support for another variables
     }

    
Restore value of data variable after processing phase.

Parameters:
faces current faces context
 
     public void restoreOrigValue(FacesContext faces) {
         String var = getVar();
 
         if (var != null) {
             Map<StringObjectattrs = getVariablesMap(faces);
 
             if (this. != null) {
                 attrs.put(varthis.);
             } else {
                 attrs.remove(var);
             }
         }
     }
 
     /*
      * (non-Javadoc)
      *
      * @see javax.faces.component.UIComponent#setValueExpression(java.lang.String, javax.el.ValueExpression)
      */
     @Override
     public void setValueExpression(String nameValueExpression binding) {
         if ("var".equals(name) || "rowKeyVar".equals(name) || "stateVar".equals(name)) {
             throw new IllegalArgumentException(MessageFormat.format("{0} cannot be EL-expression"name));
         }
 
         super.setValueExpression(namebinding);
     }

    

Check for validation errors on children components. If true, saved values must be keep on render phase

(State is reset if there are no faces messages with severity error or higher.)

Returns:
true if there are faces messages with severity error or higher
 
     protected boolean keepSaved(FacesContext context) {
 
         // For an any validation errors, children components state should be preserved
         FacesMessage.Severity sev = context.getMaximumSeverity();
 
         return (sev != null) && (isErrorOrHigher(sev));
     }

    
Returns true if given severity is equal to FacesMessage.SEVERITY_ERROR or higher.
 
     private boolean isErrorOrHigher(Severity severity) {
         return FacesMessage.SEVERITY_ERROR.compareTo(severity) <= 0;
     }

    
Perform iteration on all children components and all data rows with given visitor.

Parameters:
faces
visitor
 
     protected void iterate(FacesContext facesComponentVisitor visitor) {
 
         // stop if not rendered
         if (!this.isRendered()) {
             return;
         }
 
         // reset rowIndex
         this.captureOrigValue(faces);
         this.setRowKey(facesnull);
 
         try {
             Iterator<UIComponent> fixedChildren = fixedChildren();
 
             while (fixedChildren.hasNext()) {
                 UIComponent component = fixedChildren.next();
 
                 visitor.processComponent(facescomponentnull);
             }
 
             walk(facesvisitornull);
         } catch (Exception e) {
             throw new FacesException(e);
         } finally {
             this.setRowKey(facesnull);
             this.restoreOrigValue(faces);
         }
     }

    
Walk ( visit ) this component on all data-aware children for each row.

Parameters:
faces
visitor
 
     public void walk(FacesContext faces, DataVisitor visitorObject argument) {
         Object key = getRowKey();
         captureOrigValue(faces);
 
         Range range = null;
         DataComponentState componentState = getComponentState();
 
         if (componentState != null) {
             range = componentState.getRange();
         }
 
         getExtendedDataModel().walk(facesvisitorrangeargument);
 
         setRowKey(faceskey);
         restoreOrigValue(faces);
     }
 
     public void processDecodes(FacesContext faces) {
         if (!this.isRendered()) {
             return;
         }
 
         pushComponentToEL(facesthis);
         processDecodesChildren(faces);
         this.decode(faces);
         popComponentFromEL(faces);
     }
 
     public void processValidators(FacesContext faces) {
         if (!this.isRendered()) {
             return;
         }
 
         pushComponentToEL(facesthis);
         Application app = faces.getApplication();
         app.publishEvent(faces, PreValidateEvent.classthis);
         preValidate(faces);
         processValidatesChildren(faces);
         app.publishEvent(faces, PostValidateEvent.classthis);
         popComponentFromEL(faces);
     }
 
     public void processUpdates(FacesContext faces) {
         if (!this.isRendered()) {
             return;
         }
 
         pushComponentToEL(facesthis);
         preUpdate(faces);
         processUpdatesChildren(faces);
 
         doUpdate();
 
         popComponentFromEL(faces);
     }
 
     protected void doUpdate() {
 
     }
 
     protected void processDecodesChildren(FacesContext faces) {
         this.iterate(faces);
     }
 
     protected void processValidatesChildren(FacesContext faces) {
         this.iterate(faces);
     }
 
     protected void processUpdatesChildren(FacesContext faces) {
         this.iterate(faces);
     }
 
     @Override
     public void setId(String id) {
         super.setId(id);
         this. = null;
     }
 
     /*
      * (non-Javadoc)
      *
      * @see org.ajax4jsf.component.IterationStateHolder#getIterationState()
      */
     public Object getIterationState() {
         assert  == null;
 
         return new DataAdaptorIterationState(this.this.);
     }
 
     /*
      * (non-Javadoc)
      *
      * @see org.ajax4jsf.component.IterationStateHolder#setIterationState(java.lang.Object)
      */
     public void setIterationState(Object stateObject) {
         assert  == null;
 
         // TODO - ?
         // restoreChildState(getFacesContext());
         if (stateObject != null) {
             DataAdaptorIterationState iterationState = (DataAdaptorIterationStatestateObject;
             iterationState.restoreComponentState(this);
 
             this. = iterationState.getComponentState();
             this. = iterationState.getDataModel();
         } else {
             this. = null;
             this. = null;
         }
     }
 
     protected void resetDataModel() {
         this. = null;
     }
 
     protected void resetChildState() {
         getStateHelper().remove(.);
     }
 
     private void resetState() {
         DataComponentsContextUtil.resetDataModelOncePerPhase(getFacesContext(), this);
 
         if (!isKeepSaved()) {
             resetChildState();
         }
     }
 
     protected void preDecode(FacesContext context) {
         resetState();
     }
 
     // TODO - do we need this method?
     protected void preValidate(FacesContext context) {
     }
 
     // TODO - do we need this method?
     protected void preUpdate(FacesContext context) {
     }
 
     protected void preEncodeBegin(FacesContext context) {
         resetState();
     }
 
     @Override
     public void markInitialState() {
         super.markInitialState();
 
         if ( instanceof PartialStateHolder) {
             ((PartialStateHolder) ).markInitialState();
         }
     }
 
     @Override
     public void clearInitialState() {
         super.clearInitialState();
 
         if ( instanceof PartialStateHolder) {
             ((PartialStateHolder) ).clearInitialState();
         }
     }
 
     /*
      * (non-Javadoc)
      *
      * @see javax.faces.component.UIComponentBase#saveState(javax.faces.context.FacesContext)
      */
     @Override
     public Object saveState(FacesContext context) {
         Object parentState = super.saveState(context);
         Object savedComponentState = new DataAdaptorIterationState().saveState(context);
 
         Object converterState = null;
         boolean nullDelta = true;
 
         boolean converterHasPartialState = false;
 
         if (initialStateMarked()) {
             if (!isSetRowKeyConverter() &&  != null &&  instanceof PartialStateHolder) {
                 // Delta
                 StateHolder holder = (StateHolder) ;
                 if (!holder.isTransient()) {
                     Object attachedState = holder.saveState(context);
                     if (attachedState != null) {
                         nullDelta = false;
                         converterState = attachedState;
                     }
                     converterHasPartialState = true;
                 } else {
                     converterState = null;
                 }
             } else if (isSetRowKeyConverter() ||  != null) {
                 // Full
                 converterState = saveAttachedState(context);
                 nullDelta = false;
             }
 
             if (parentState == null && savedComponentState == null && nullDelta) {
                 // No values
                 return null;
             }
         } else {
             converterState = saveAttachedState(context);
        }
        return new Object[] { parentStatesavedComponentStateconverterHasPartialStateconverterState };
    }
    /*
     * (non-Javadoc)
     *
     * @see javax.faces.component.UIComponentBase#restoreState(javax.faces.context.FacesContext, java.lang.Object)
     */
    @Override
    public void restoreState(FacesContext contextObject stateObject) {
        if (stateObject == null) {
            return;
        }
        Object[] state = (Object[]) stateObject;
        super.restoreState(context, state[0]);
        if (state[1] != null) {
            DataAdaptorIterationState iterationState = new DataAdaptorIterationState();
            iterationState.restoreState(contextstate[1]);
            iterationState.restoreComponentState(this);
            // TODO update state model binding
             = iterationState.getComponentState();
             = iterationState.getDataModel();
        }
        boolean converterHasPartialState = ..equals(state[2]);
        Object savedConverterState = state[3];
        if (converterHasPartialState) {
            ((StateHolder) ).restoreState(contextsavedConverterState);
        } else {
             = (Converter) UIComponentBase.restoreAttachedState(contextsavedConverterState);
        }
    }
    private boolean matchesBaseId(String clientIdString baseIdchar separatorChar) {
        if (clientId.equals(baseId)) {
            return true;
        }
        // if clientId.startsWith(baseId + separatorChar)
        if (clientId.startsWith(baseId) && (clientId.length() > baseId.length())
                && (clientId.charAt(baseId.length()) == separatorChar)) {
            return true;
        }
        return false;
    }
    @Override
    public boolean invokeOnComponent(FacesContext contextString clientId, ContextCallback callbackthrows FacesException {
        if ((null == context) || (null == clientId) || (null == callback)) {
            throw new NullPointerException();
        }
        String baseId = getClientId(context);
        if (!matchesBaseId(clientIdbaseId, UINamingContainer.getSeparatorChar(context))) {
            return false;
        }
        boolean found = false;
        Object oldRowKey = getRowKey();
        // TODO - this does not seem right
        captureOrigValue(context);
        try {
            // TODO - ?
            // if (null != oldRowKey) {
            setRowKey(contextnull);
            // }
            if (clientId.equals(baseId)) {
                callback.invokeContextCallback(contextthis);
                found = true;
            } else {
                Iterator<UIComponent> fixedChildrenItr = fixedChildren();
                while (fixedChildrenItr.hasNext() && !found) {
                    UIComponent fixedChild = fixedChildrenItr.next();
                    found = fixedChild.invokeOnComponent(contextclientIdcallback);
                }
            }
            if (!found) {
                Object newRowKey = null;
                // Call for a child component - try to detect row key
                // baseId.length() + 1 expression skips SEPARATOR_CHAR
                // TODO - convertKeyString
                String rowKeyString = extractKeySegment(contextclientId.substring(baseId.length() + 1));
                if (rowKeyString != null) {
                    Converter keyConverter = getRowKeyConverter();
                    if (null != keyConverter) {
                        try {
                            // TODO: review
                            newRowKey = keyConverter.getAsObject(contextthisrowKeyString);
                        } catch (ConverterException e) {
                            // TODO: LOG error
                        }
                    }
                }
                setRowKey(contextnewRowKey);
                if (isRowAvailable()) {
                    Iterator<UIComponent> dataChildrenItr = dataChildren();
                    while (dataChildrenItr.hasNext() && !found) {
                        UIComponent dataChild = dataChildrenItr.next();
                        found = dataChild.invokeOnComponent(contextclientIdcallback);
                    }
                }
            }
        } catch (Exception e) {
            throw new FacesException(e);
        } finally {
            // if (null != oldRowKey) {
            try {
                setRowKey(contextoldRowKey);
                restoreOrigValue(context);
            } catch (Exception e) {
                .error(e.getMessage(), e);
            }
            // }
        }
        return found;
    }
    public boolean invokeOnRow(FacesContext contextString clientId, ContextCallback callback) {
        if ((null == context) || (null == clientId) || (null == callback)) {
            throw new NullPointerException();
        }
        String baseId = getClientId(context);
        if (!matchesBaseId(clientIdbaseId, UINamingContainer.getSeparatorChar(context))) {
            return false;
        }
        String rowId = clientId.substring(baseId.length() + 1);
        if (rowId.indexOf(UINamingContainer.getSeparatorChar(context)) >= 0) {
            return false;
        }
        Object oldRowKey = getRowKey();
        captureOrigValue(context);
        try {
            setRowKey(contextnull);
            Iterator<UIComponent> fixedChildrenItr = fixedChildren();
            while (fixedChildrenItr.hasNext()) {
                if (checkAllFixedChildren(fixedChildrenItr.next(), rowId)) {
                    return false;
                }
            }
            Object newRowKey = null;
            if (rowId != null) {
                Converter keyConverter = getRowKeyConverter();
                if (null != keyConverter) {
                    try {
                        newRowKey = keyConverter.getAsObject(contextthisrowId);
                    } catch (ConverterException e) {
                        .warn(e);
                    }
                }
            }
            setRowKey(contextnewRowKey);
            callback.invokeContextCallback(contextthis);
        } catch (Exception e) {
            throw new FacesException(e);
        } finally {
            try {
                setRowKey(contextoldRowKey);
                restoreOrigValue(context);
            } catch (Exception e) {
                .error(e.getMessage(), e);
            }
        }
        return true;
    }
    private boolean checkAllFixedChildren(UIComponent fixedChildString id) {
        if (fixedChild.getId().equals(id)) {
            return true;
        }
        if (fixedChild instanceof NamingContainer) {
            return false;
        }
        for (UIComponent uiComponent : fixedChild.getChildren()) {
            if (checkAllFixedChildren(uiComponentid)) {
                return true;
            }
        }
        for (UIComponent uiComponent : fixedChild.getFacets().values()) {
            if (checkAllFixedChildren(uiComponentid)) {
                return true;
            }
        }
        return false;
    }
    // Tests whether we need to visit our children as part of
    // a tree visit
    private boolean doVisitChildren(VisitContext contextboolean visitRows) {
        // Just need to check whether there are any ids under this
        // subtree. Make sure row index is cleared out since
        // getSubtreeIdsToVisit() needs our row-less client id.
        // TODO check this
        if (visitRows) {
            setRowKey(context.getFacesContext(), null);
        }
        // TODO optimize for returned IDs
        Collection<StringidsToVisit = context.getSubtreeIdsToVisit(this);
        assert idsToVisit != null;
        if (idsToVisit == VisitContext.ALL_IDS) {
            // TODO
        }
        // All ids or non-empty collection means we need to visit our children.
        return !idsToVisit.isEmpty();
    }
    private boolean visitComponents(Iterator<UIComponent> components, VisitContext context, VisitCallback callback) {