Author: alexsmirnov
Date: 2007-06-29 20:13:26 -0400 (Fri, 29 Jun 2007)
New Revision: 1429
Modified:
branches/refactor1/framework/impl/src/main/java/org/ajax4jsf/ajax/repeat/UIDataAdaptor.java
branches/refactor1/samples/useCases/src/main/java/org/ajax4jsf/RepeatData.java
branches/refactor1/samples/useCases/src/main/webapp/pages/repeat.xhtml
Log:
Fix RF-250
Modified:
branches/refactor1/framework/impl/src/main/java/org/ajax4jsf/ajax/repeat/UIDataAdaptor.java
===================================================================
---
branches/refactor1/framework/impl/src/main/java/org/ajax4jsf/ajax/repeat/UIDataAdaptor.java 2007-06-30
00:04:34 UTC (rev 1428)
+++
branches/refactor1/framework/impl/src/main/java/org/ajax4jsf/ajax/repeat/UIDataAdaptor.java 2007-06-30
00:13:26 UTC (rev 1429)
@@ -1,1323 +1,1328 @@
-/**
- * License Agreement.
- *
- * Ajax4jsf 1.1 - Natural Ajax for Java Server Faces (JSF)
- *
- * Copyright (C) 2007 Exadel, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License version 2.1 as published by the Free Software Foundation.
- *
- * This library 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 library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-package org.ajax4jsf.ajax.repeat;
-
-import java.io.IOException;
-import java.io.Serializable;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.Set;
-
-import javax.faces.FacesException;
-import javax.faces.application.FacesMessage;
-import javax.faces.component.EditableValueHolder;
-import javax.faces.component.NamingContainer;
-import javax.faces.component.StateHolder;
-import javax.faces.component.UIComponent;
-import javax.faces.component.UIData;
-import javax.faces.context.FacesContext;
-import javax.faces.el.ValueBinding;
-import javax.faces.event.AbortProcessingException;
-import javax.faces.event.FacesEvent;
-import javax.faces.event.FacesListener;
-import javax.faces.event.PhaseId;
-import javax.faces.model.DataModel;
-import javax.faces.model.ListDataModel;
-import javax.faces.render.Renderer;
-
-import org.ajax4jsf.framework.renderer.AjaxChildrenRenderer;
-import org.ajax4jsf.framework.renderer.AjaxRenderer;
-
-/**
- * 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 shura
- *
- */
-public abstract class UIDataAdaptor extends UIData implements AjaxDataEncoder {
-
- /**
- *
- */
- public static final String COMPONENT_STATE_ATTRIBUTE = "componentState";
-
- public final static DataModel EMPTY_MODEL = new ListDataModel(
- Collections.EMPTY_LIST);
-
- /**
- * Base class for visit data model at phases decode, validation and
- * update model
- *
- * @author shura
- *
- */
- protected abstract class ComponentVisitor implements DataVisitor {
-
- public void process(FacesContext context, Object rowKey, Object argument)
- throws IOException {
- setRowKey(context, rowKey);
- if (isRowAvailable()) {
- Iterator childIterator = dataChildren();
- while (childIterator.hasNext()) {
- UIComponent component = (UIComponent) childIterator.next();
- processComponent(context, component, argument);
- }
-
- }
- }
-
- public abstract void processComponent(FacesContext context,
- UIComponent c, Object argument) throws IOException;
-
- }
-
- /**
- * Visitor for process decode on children components.
- */
- protected ComponentVisitor decodeVisitor = new ComponentVisitor() {
-
- public void processComponent(FacesContext context, UIComponent c,
- Object argument) {
- c.processDecodes(context);
- }
-
- };
-
- /**
- * Visitor for process validation phase
- */
- protected ComponentVisitor validateVisitor = new ComponentVisitor() {
-
- public void processComponent(FacesContext context, UIComponent c,
- Object argument) {
- c.processValidators(context);
- }
-
- };
-
- /**
- * Visitor for process update model phase.
- */
- protected ComponentVisitor updateVisitor = new ComponentVisitor() {
-
- public void processComponent(FacesContext context, UIComponent c,
- Object argument) {
- c.processUpdates(context);
- }
-
- };
-
- /**
- * Base client id's of this component, for wich invoked encode...
- * methods. Component will save state and serialisable models for this
- * keys only.
- */
- private Set _encoded;
-
- /**
- * Storage for data model instances with different client id's of this
- * component. In case of child for UIData component, this map will keep
- * data models for different iterations between phases.
- */
- private Map _modelsMap = new HashMap();
-
- /**
- * Reference for curent data model
- */
- private ExtendedDataModel _currentModel = null;
-
- /**
- * States of this component for diferent iterations, same as for models.
- */
- private Map _statesMap = new HashMap();
-
- /**
- * Reference for current component state.
- */
- private DataComponentState _currentState = null;
-
- /**
- * Name of EL variable for current component state.
- */
- private String _stateVar;
-
- private String _rowKeyVar;
-
- /**
- * Key for current value in model.
- */
- private Object _rowKey = null;
-
- /**
- * Values of row keys, encoded on ajax response rendering.
- */
- private Set _ajaxKeys = null;
-
- private Object _ajaxRowKey = null;
-
- private Map _ajaxRowKeysMap = new HashMap();
-
- /**
- * Get name of EL variable for component state.
- *
- * @return the varState
- */
- public String getStateVar() {
- return _stateVar;
- }
-
- /**
- * @param varStatus
- * the varStatus to set
- */
- public void setStateVar(String varStatus) {
- this._stateVar = varStatus;
- }
-
- /**
- * @return the rowKeyVar
- */
- public String getRowKeyVar() {
- return this._rowKeyVar;
- }
-
- /**
- * @param rowKeyVar
- * the rowKeyVar to set
- */
- public void setRowKeyVar(String rowKeyVar) {
- this._rowKeyVar = rowKeyVar;
- }
-
- /*
- * (non-Javadoc)
- *
- * @see javax.faces.component.UIData#getRowCount()
- */
- public int getRowCount() {
- return getExtendedDataModel().getRowCount();
- }
-
- /*
- * (non-Javadoc)
- *
- * @see javax.faces.component.UIData#getRowData()
- */
- public Object getRowData() {
- return getExtendedDataModel().getRowData();
- }
-
- /*
- * (non-Javadoc)
- *
- * @see javax.faces.component.UIData#isRowAvailable()
- */
- public boolean isRowAvailable() {
- return this.getExtendedDataModel().isRowAvailable();
- }
-
- /*
- * (non-Javadoc)
- *
- * @see javax.faces.component.UIData#setRowIndex(int)
- */
- public void setRowIndex(int index) {
- FacesContext faces = FacesContext.getCurrentInstance();
- ExtendedDataModel localModel = getExtendedDataModel();
- // if(key == localModel.getRowIndex()){
- // return;
- // }
- // save child state
- this.saveChildState(faces);
- // Set current model row by int, but immediately get value from model.
- // for compability, complex models must provide values map between
- // integer and key value.
- localModel.setRowIndex(index);
- this._rowKey = localModel.getRowKey();
- this._clientId = null;
- boolean rowSelected = this._rowKey != null;
-
- setupVariable(faces, localModel, rowSelected);
- // restore child state
- this.restoreChildState(faces);
- }
-
- /*
- * (non-Javadoc)
- *
- * @see javax.faces.component.UIData#getRowIndex()
- */
- public int getRowIndex() {
- return getExtendedDataModel().getRowIndex();
- }
-
- /**
- * Same as for int index, but for complex model key.
- *
- * @return
- */
- public Object getRowKey() {
- return this._rowKey;
- }
-
- public void setRowKey(Object key) {
- setRowKey(FacesContext.getCurrentInstance(), key);
- }
-
- /**
- * Setup current roy by key. Perform same functionality as
- * {@link 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.
- *
- * @param faces -
- * current FacesContext
- * @param key
- * new key value.
- */
- public void setRowKey(FacesContext faces, Object key) {
- ExtendedDataModel localModel = getExtendedDataModel();
- // save child state
- this.saveChildState(faces);
- this._rowKey = key;
- this._clientId = null;
- localModel.setRowKey(key);
-
- boolean rowSelected = key != null;
-
- setupVariable(faces, localModel, rowSelected);
- // restore child state
- this.restoreChildState(faces);
-
- }
-
- /*
- * (non-Javadoc)
- *
- * @see org.ajax4jsf.ajax.repeat.AjaxDataEncoder#getAjaxKeys()
- */
- public Set getAjaxKeys() {
- Set keys = null;
- if (this._ajaxKeys != null) {
- keys = (this._ajaxKeys);
- } else {
- ValueBinding vb = getValueBinding("ajaxKeys");
- if (vb != null) {
- keys = (Set) (vb.getValue(getFacesContext()));
- } else if(null != _ajaxRowKey){
- // If none of above exist , use row with submitted AjaxComponent
- keys = new HashSet(1);
- keys.add(_ajaxRowKey);
- }
- }
- return keys;
- }
-
- /*
- * (non-Javadoc)
- *
- * @see org.ajax4jsf.ajax.repeat.AjaxDataEncoder#setAjaxKeys(java.util.Set)
- */
- public void setAjaxKeys(Set ajaxKeys) {
- this._ajaxKeys = ajaxKeys;
- }
-
- /*
- * (non-Javadoc)
- *
- * @see
org.ajax4jsf.framework.ajax.AjaxChildrenEncoder#encodeAjaxChild(javax.faces.context.FacesContext,
- * java.lang.String, java.util.Set, java.util.Set)
- */
- public void encodeAjaxChild(FacesContext context, String path,
- final Set ids, final Set renderedAreas) throws IOException {
- resetDataModel();
-
- Renderer renderer = getRenderer(context);
- if (null != renderer && renderer instanceof AjaxRenderer) {
- // If renderer support partial encoding - call them.
- AjaxRenderer childrenRenderer = (AjaxRenderer) renderer;
- childrenRenderer.encodeAjaxChildren(context, this, path, ids,
- renderedAreas);
- }
- else {
- // Use simple ajax children encoding for iterate other keys.
- final AjaxRenderer childrenRenderer = getChildrenRenderer();
- final String childrenPath = path + getId() + NamingContainer.SEPARATOR_CHAR;
- ComponentVisitor ajaxVisitor = new ComponentVisitor() {
-
- public void processComponent(FacesContext context,
- UIComponent c, Object argument) throws IOException {
- childrenRenderer.encodeAjaxComponent(context, c, childrenPath,
- ids, renderedAreas);
- }
-
- };
- Set ajaxKeys = getAjaxKeys();
- if (null != ajaxKeys) {
- captureOrigValue();
- Object savedKey = getRowKey();
- setRowKey(context, null);
- Iterator fixedChildren = fixedChildren();
- while (fixedChildren.hasNext()) {
- UIComponent component = (UIComponent) fixedChildren.next();
- ajaxVisitor.processComponent(context, component, null);
- }
- for (Iterator iter = ajaxKeys.iterator(); iter.hasNext();) {
- Object key = (Object) iter.next();
- ajaxVisitor.process(context, key, null);
- }
- setRowKey(savedKey);
- restoreOrigValue();
- } else {
- iterate(context, ajaxVisitor, null);
- }
- }
- }
-
- /**
- * Instance of default renderer in ajax responses.
- */
- private AjaxRenderer _childrenRenderer = null;
-
- /**
- * getter for simple {@link AjaxChildrenRenderer} instance in case of
- * ajax responses. If default renderer not support search of children
- * for encode in ajax response, component will use this instance by
- * default.
- *
- * @return
- */
- protected AjaxRenderer getChildrenRenderer() {
- if (_childrenRenderer == null) {
- _childrenRenderer = new AjaxChildrenRenderer() {
-
- protected Class getComponentClass() {
- return UIDataAdaptor.class;
- }
-
- };
-
- }
-
- return _childrenRenderer;
- }
-
- /**
- * @return Set of values for clientId's of this component, for wich was
- * invoked "encode" methods.
- */
- protected Set getEncodedIds() {
- if (_encoded == null) {
- _encoded = new HashSet();
- }
-
- return _encoded;
- }
-
- /**
- * 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.
- *
- * @param faces
- * current faces context
- * @param localModel
- * @param rowSelected
- */
- protected void setupVariable(FacesContext faces, DataModel localModel,
- boolean rowSelected) {
- Map attrs = faces.getExternalContext().getRequestMap();
- if (rowSelected && isRowAvailable()) {
- // Current row data.
- setupVariable(getVar(), attrs, localModel.getRowData());
- // Component state variable.
- setupVariable(getStateVar(), attrs, getComponentState());
- // Row key Data variable.
- setupVariable(getRowKeyVar(), attrs, getRowKey());
-
- } else {
- removeVariable(getVar(), attrs);
- removeVariable(getStateVar(), attrs);
- removeVariable(getRowKeyVar(), attrs);
- }
- }
-
- /**
- * @param var
- * @param attrs
- * @param rowData
- */
- private void setupVariable(String var, Map attrs, Object rowData) {
- if (var != null) {
- attrs.put(var, rowData);
- }
- }
-
- /**
- * @param var
- * @param attrs
- * @param rowData
- */
- private void removeVariable(String var, Map attrs) {
- if (var != null) {
- attrs.remove(var);
- }
- }
-
- /**
- * Reset data model. this method must be called twice per request -
- * before decode phase and before component encoding.
- */
- protected void resetDataModel() {
- this.setExtendedDataModel(null);
- }
-
- /**
- * Set data model. Model value will be stored in Map with key as current
- * clientId for this component, to keep models between phases for same
- * iteration in case if this component child for other UIData
- *
- * @param model
- */
- protected void setExtendedDataModel(ExtendedDataModel model) {
- this._currentModel = model;
- this._modelsMap.put(getBaseClientId(getFacesContext()), model);
- }
-
- /**
- * Get current data model, or create it by {@link #createDataModel()}
- * method. For different iterations in ancestor UIData ( if present )
- * will be returned different models.
- *
- * @return current data model.
- */
- protected ExtendedDataModel getExtendedDataModel() {
- if (this._currentModel == null) {
- String baseClientId = getBaseClientId(getFacesContext());
- ExtendedDataModel model = (ExtendedDataModel) this._modelsMap
- .get(baseClientId);
- if (null == model) {
- model = createDataModel();
- this._modelsMap.put(baseClientId, model);
- }
- this._currentModel = model;
- }
- return this._currentModel;
- }
-
- /**
- * Hook mathod for create data model in concrete implementations.
- *
- * @return
- */
- protected abstract ExtendedDataModel createDataModel();
-
- /**
- * Set current state ( at most cases, visual representation ) of this
- * component. Same as for DataModel, component will keep states for
- * different iterations.
- *
- * @param state
- */
- public void setComponentState(DataComponentState state) {
- this._currentState = state;
- this._statesMap.put(getBaseClientId(getFacesContext()),
- this._currentState);
- }
-
- /**
- * @return current state of this component.
- */
- public DataComponentState getComponentState() {
- DataComponentState state = null;
- if (this._currentState == null) {
- // Check for binding state to user bean.
- ValueBinding valueBinding =
getValueBinding(UIDataAdaptor.COMPONENT_STATE_ATTRIBUTE);
- FacesContext facesContext = getFacesContext();
- if (null != valueBinding) {
- state = (DataComponentState) valueBinding
- .getValue(facesContext);
- if (null == state) {
- // Create default state
- state = createComponentState();
- if (!valueBinding.isReadOnly(facesContext)) {
- // Store created state in user bean.
- valueBinding.setValue(facesContext, state);
- }
- }
- } else {
- // Check for stored state in map for parent iterations
- String baseClientId = getBaseClientId(facesContext);
- state = (DataComponentState) this._statesMap.get(baseClientId);
- if (null == state) {
- // Create default component state
- state = createComponentState();
- this._statesMap.put(baseClientId, state);
- }
- this._currentState = state;
- }
- } else {
- state = this._currentState;
- }
- return state;
- }
-
- /**
- * Hook method for create default state in concrete implementations.
- *
- * @return
- */
- protected abstract DataComponentState createComponentState();
-
- private String _clientId = null;
-
- public String getClientId(FacesContext faces) {
- if (null == _clientId) {
- StringBuffer id = new StringBuffer(getBaseClientId(faces));
- Object rowKey = getRowKey();
- if (rowKey != null) {
- id.append(NamingContainer.SEPARATOR_CHAR).append(
- rowKey.toString());
- }
- Renderer renderer;
- if (null != (renderer = getRenderer(faces))) {
- _clientId = renderer.convertClientId(faces, id.toString());
- } else {
- _clientId = id.toString();
- }
-
- }
- return _clientId;
- }
-
- private String _baseClientId = null;
-
- /**
- * Get base clietntId of this component ( withowt iteration part )
- *
- * @param faces
- * @return
- */
- public String getBaseClientId(FacesContext faces) {
- // Return any previously cached client identifier
- if (_baseClientId == null) {
-
- // Search for an ancestor that is a naming container
- UIComponent ancestorContainer = this;
- StringBuffer parentIds = new StringBuffer();
- while (null != (ancestorContainer = ancestorContainer.getParent())) {
- if (ancestorContainer instanceof NamingContainer) {
- parentIds.append(ancestorContainer.getClientId(faces))
- .append(NamingContainer.SEPARATOR_CHAR);
- break;
- }
- }
- String id = getId();
- if (null != id) {
- _baseClientId = parentIds.append(id).toString();
- } else {
- _baseClientId = parentIds.append(
- faces.getViewRoot().createUniqueId()).toString();
- }
- }
- return (_baseClientId);
-
- }
-
- /*
- * (non-Javadoc)
- *
- * @see javax.faces.component.UIComponentBase#setId(java.lang.String)
- */
- public void setId(String id) {
- // If component created by restoring tree or JSP, initial Id is null.
- boolean haveId = null != super.getId();
- super.setId(id);
- _baseClientId = null;
- _clientId = null;
- if (haveId) {
- // parent UIData ( if present ) will be set same Id at iteration
- // -
- // we use it for
- // switch to different model and state.
- String baseClientId = getBaseClientId(getFacesContext());
- this._currentState = (DataComponentState) this._statesMap
- .get(baseClientId);
- this._currentModel = (ExtendedDataModel) this._modelsMap
- .get(baseClientId);
- if (null != this._currentModel) {
- this._rowKey = this._currentModel.getRowKey();
- // restoreChildState();
- }
- // Restore value for row with submitted AjaxComponent.
- this._ajaxRowKey = _ajaxRowKeysMap.get(baseClientId);
- }
- }
-
- private Object origValue;
-
- /**
- * Save current state of data variable.
- */
- public void captureOrigValue() {
- captureOrigValue(FacesContext.getCurrentInstance());
- }
-
- /**
- * Save current state of data variable.
- *
- * @param faces
- * current faces context
- */
- public void captureOrigValue(FacesContext faces) {
- String var = getVar();
- if (var != null) {
- Map attrs = faces.getExternalContext().getRequestMap();
- this.origValue = attrs.get(var);
- }
- }
-
- /**
- * Restore value of data variable after processing phase.
- */
- public void restoreOrigValue() {
- restoreOrigValue(FacesContext.getCurrentInstance());
- }
-
- /**
- * Restore value of data variable after processing phase.
- *
- * @param faces
- * current faces context
- */
- public void restoreOrigValue(FacesContext faces) {
- String var = getVar();
- if (var != null) {
- Map attrs = faces.getExternalContext().getRequestMap();
- if (this.origValue != null) {
- attrs.put(var, this.origValue);
- } else {
- attrs.remove(var);
- }
- }
- }
-
- /**
- * Saved values of {@link EditableValueHolder} fields per iterations.
- */
- private Map childState;
-
- /**
- * @param faces
- * @return Saved values of {@link EditableValueHolder} fields per
- * iterations.
- */
- protected Map getChildState(FacesContext faces) {
- if (this.childState == null) {
- this.childState = new HashMap();
- }
- String baseClientId = getBaseClientId(faces);
- Map currentChildState = (Map) childState.get(baseClientId);
- if (null == currentChildState) {
- currentChildState = new HashMap();
- childState.put(baseClientId, currentChildState);
- }
- return currentChildState;
- }
-
- /**
- * Save values of {@link EditableValueHolder} fields before change
- * current row.
- *
- * @param faces
- */
- protected void saveChildState(FacesContext faces) {
-
- Iterator itr = dataChildren();
- while (itr.hasNext()) {
- Map childState = this.getChildState(faces);
- this.saveChildState(faces, (UIComponent) itr.next(), childState);
- }
- }
-
- /**
- * Recursive method for Iterate on children for save
- * {@link EditableValueHolder} fields states.
- *
- * @param faces
- * @param c
- * @param childState
- */
- private void saveChildState(FacesContext faces, UIComponent c,
- Map childState) {
-
- if (c instanceof EditableValueHolder && !c.isTransient()) {
- String clientId = c.getClientId(faces);
- SavedState ss = (SavedState) childState.get(clientId);
- if (ss == null) {
- ss = new SavedState();
- childState.put(clientId, ss);
- }
- ss.populate((EditableValueHolder) c);
- }
-
- // continue hack
- Iterator itr = c.getChildren().iterator();
- while (itr.hasNext()) {
- saveChildState(faces, (UIComponent) itr.next(), childState);
- }
- itr = c.getFacets().values().iterator();
- while (itr.hasNext()) {
- saveChildState(faces, (UIComponent) itr.next(), childState);
- }
- }
-
- /**
- * Restore values of {@link EditableValueHolder} fields after change
- * current row.
- *
- * @param faces
- */
- protected void restoreChildState(FacesContext faces) {
-
- Iterator itr = dataChildren();
- while (itr.hasNext()) {
- Map childState = this.getChildState(faces);
- this.restoreChildState(faces, (UIComponent) itr.next(), childState);
- }
- }
-
- /**
- * Recursive part of
- * {@link #restoreChildState(FacesContext, UIComponent, Map)}
- *
- * @param faces
- * @param c
- * @param childState
- *
- */
- private void restoreChildState(FacesContext faces, UIComponent c,
- Map childState) {
- // reset id
- String id = c.getId();
- c.setId(id);
-
- // hack
- if (c instanceof EditableValueHolder) {
- EditableValueHolder evh = (EditableValueHolder) c;
- String clientId = c.getClientId(faces);
- SavedState ss = (SavedState) childState.get(clientId);
- if (ss != null) {
- ss.apply(evh);
- } else {
- NullState.apply(evh);
- }
- }
-
- // continue hack
- Iterator itr = c.getChildren().iterator();
- while (itr.hasNext()) {
- restoreChildState(faces, (UIComponent) itr.next(), childState);
- }
- itr = c.getFacets().values().iterator();
- while (itr.hasNext()) {
- restoreChildState(faces, (UIComponent) itr.next(), childState);
- }
- }
-
- /**
- * Check for validation errors on children components. If true, saved
- * values must be keep on render phase
- *
- * @param context
- * @return
- */
- private boolean keepSaved(FacesContext context) {
-
- Iterator clientIds = this.getChildState(context).keySet().iterator();
- while (clientIds.hasNext()) {
- String clientId = (String) clientIds.next();
- Iterator messages = context.getMessages(clientId);
- while (messages.hasNext()) {
- FacesMessage message = (FacesMessage) messages.next();
- if (message.getSeverity()
- .compareTo(FacesMessage.SEVERITY_ERROR) >= 0) {
- return (true);
- }
- }
- }
- return false;
- }
-
- /**
- * Perform iteration on all children components and all data rows with
- * given visitor.
- *
- * @param faces
- * @param visitor
- */
- protected void iterate(FacesContext faces, ComponentVisitor visitor,
- Object argument) {
-
- // stop if not rendered
- if (!this.isRendered()) {
- return;
- }
- // reset rowIndex
- this.captureOrigValue(faces);
- this.setRowKey(faces, null);
- try {
- Iterator fixedChildren = fixedChildren();
- while (fixedChildren.hasNext()) {
- UIComponent component = (UIComponent) fixedChildren.next();
- visitor.processComponent(faces, component, argument);
- }
-
- walk(faces, visitor, argument);
- } catch (Exception e) {
- throw new FacesException(e);
- } finally {
- this.setRowKey(faces, null);
- this.restoreOrigValue(faces);
- }
- }
-
- /**
- * Walk ( visit ) this component on all data-avare children for each
- * row.
- *
- * @param faces
- * @param visitor
- * @throws IOException
- */
- public void walk(FacesContext faces, DataVisitor visitor, Object argument)
- throws IOException {
- getExtendedDataModel().walk(faces, visitor,
- getComponentState().getRange(), argument);
- }
-
- protected void processDecodes(FacesContext faces, Object argument) {
- if (!this.isRendered())
- return;
- this.resetComponent(faces);
- this.iterate(faces, decodeVisitor, argument);
- this.decode(faces);
- }
-
- /*
- * (non-Javadoc)
- *
- * @see
javax.faces.component.UIData#processDecodes(javax.faces.context.FacesContext)
- */
- public void processDecodes(FacesContext faces) {
- processDecodes(faces, null);
- }
-
- /**
- * Reset per-request fields in component.
- *
- * @param faces
- *
- */
- protected void resetComponent(FacesContext faces) {
- // resetDataModel();
- if (null != this.childState) {
- childState.remove(getBaseClientId(faces));
- }
- this._encoded = null;
- }
-
- protected void processUpdates(FacesContext faces, Object argument) {
- if (!this.isRendered())
- return;
- this.iterate(faces, updateVisitor, argument);
- ExtendedDataModel dataModel = getExtendedDataModel();
- // If no validation errors, update values for serializable model,
- // restored from view.
- if (dataModel instanceof SerializableDataModel && (!keepSaved(faces))) {
- SerializableDataModel serializableModel = (SerializableDataModel) dataModel;
- serializableModel.update();
- }
- }
-
- public void processUpdates(FacesContext faces) {
- processUpdates(faces, null);
- }
-
- protected void processValidators(FacesContext faces, Object argument) {
- if (!this.isRendered())
- return;
- this.iterate(faces, validateVisitor, argument);
- }
-
- public void processValidators(FacesContext faces) {
- processValidators(faces, null);
- }
-
- public void encodeBegin(FacesContext context) throws IOException {
- resetDataModel();
- // if(!keepSaved(context)){
- // childState.remove(getBaseClientId(context));
- // }
- // Mark component as used, if parent UIData change own range states not
- // accessed at
- // encode phase must be unsaved.
- getEncodedIds().add(getBaseClientId(context));
- // getComponentState().setUsed(true);
- super.encodeBegin(context);
- }
-
- /**
- * This method must create iterator for all non-data avare children of
- * this component ( header/footer facets for components and columns in
- * dataTable, facets for tree etc.
- *
- * @return iterator for all components not sensitive for row data.
- */
- protected abstract Iterator fixedChildren();
-
- /**
- * This method must create iterator for all children components,
- * processed "per row" It can be children of UIColumn in dataTable,
- * nodes in tree
- *
- * @return iterator for all components processed per row.
- */
- protected abstract Iterator dataChildren();
-
- private final static SavedState NullState = new SavedState();
-
- // from RI
- /**
- * This class keep values of {@link EditableValueHolder} row-sensitive
- * fields.
- *
- * @author shura
- *
- */
- private final static class SavedState implements Serializable {
-
- private Object submittedValue;
-
- private static final long serialVersionUID = 2920252657338389849L;
-
- Object getSubmittedValue() {
- return (this.submittedValue);
- }
-
- void setSubmittedValue(Object submittedValue) {
- this.submittedValue = submittedValue;
- }
-
- private boolean valid = true;
-
- boolean isValid() {
- return (this.valid);
- }
-
- void setValid(boolean valid) {
- this.valid = valid;
- }
-
- private Object value;
-
- Object getValue() {
- return (this.value);
- }
-
- public void setValue(Object value) {
- this.value = value;
- }
-
- private boolean localValueSet;
-
- boolean isLocalValueSet() {
- return (this.localValueSet);
- }
-
- public void setLocalValueSet(boolean localValueSet) {
- this.localValueSet = localValueSet;
- }
-
- public String toString() {
- return ("submittedValue: " + submittedValue + " value: " +
value
- + " localValueSet: " + localValueSet);
- }
-
- public void populate(EditableValueHolder evh) {
- this.value = evh.getLocalValue();
- this.valid = evh.isValid();
- this.submittedValue = evh.getSubmittedValue();
- this.localValueSet = evh.isLocalValueSet();
- }
-
- public void apply(EditableValueHolder evh) {
- evh.setValue(this.value);
- evh.setValid(this.valid);
- evh.setSubmittedValue(this.submittedValue);
- evh.setLocalValueSet(this.localValueSet);
- }
-
- }
-
- /*
- * (non-Javadoc)
- *
- * @see javax.faces.component.UIData#queueEvent(javax.faces.event.FacesEvent)
- */
- public void queueEvent(FacesEvent event) {
- if (event.getComponent() != this) {
- event = new IndexedEvent(this, event, getRowKey());
- }
- // Send event directly to parent, to avoid wrapping in superclass.
- UIComponent parent = getParent();
- if (parent == null) {
- throw new IllegalStateException(
- "No parent component for queue event");
- } else {
- parent.queueEvent(event);
- }
- }
-
- public void broadcast(FacesEvent event) throws AbortProcessingException {
-
- if (!(event instanceof IndexedEvent)) {
- if (!broadcastLocal(event)) {
- super.broadcast(event);
- }
- return;
- }
-
- // Set up the correct context and fire our wrapped event
- IndexedEvent revent = (IndexedEvent) event;
- Object oldRowKey = getRowKey();
- FacesContext faces = FacesContext.getCurrentInstance();
- captureOrigValue(faces);
- Object eventRowKey = revent.getKey();
- setRowKey(faces, eventRowKey);
- FacesEvent rowEvent = revent.getTarget();
- rowEvent.getComponent().broadcast(rowEvent);
- // For Ajax events, keep row value.
- if (!(rowEvent.getPhaseId() == PhaseId.RENDER_RESPONSE)) {
- this._ajaxRowKey = eventRowKey;
- this._ajaxRowKeysMap.put(getBaseClientId(faces), eventRowKey);
- }
- setRowKey(faces, oldRowKey);
- restoreOrigValue(faces);
- // }
- return;
- }
-
- /**
- * Process events targetted for concrete implementation. Hook method
- * called from {@link #broadcast(FacesEvent)}
- *
- * @param event -
- * processed event.
- * @return true if event processed, false if component must continue
- * processing.
- */
- protected boolean broadcastLocal(FacesEvent event) {
- return false;
- }
-
- /**
- * Wrapper for event from child component, with value of current row
- * key.
- *
- * @author shura
- *
- */
- protected static final class IndexedEvent extends FacesEvent {
-
- private static final long serialVersionUID = -8318895390232552385L;
-
- private final FacesEvent target;
-
- private final Object key;
-
- public IndexedEvent(UIDataAdaptor owner, FacesEvent target, Object key) {
- super(owner);
- this.target = target;
- this.key = key;
- }
-
- public PhaseId getPhaseId() {
- return (this.target.getPhaseId());
- }
-
- public void setPhaseId(PhaseId phaseId) {
- this.target.setPhaseId(phaseId);
- }
-
- public boolean isAppropriateListener(FacesListener listener) {
- return this.target.isAppropriateListener(listener);
- }
-
- public void processListener(FacesListener listener) {
- UIDataAdaptor owner = (UIDataAdaptor) this.getComponent();
- Object prevIndex = owner._rowKey;
- try {
- owner.setRowKey(this.key);
- this.target.processListener(listener);
- } finally {
- owner.setRowKey(prevIndex);
- }
- }
-
- public Object getKey() {
- return key;
- }
-
- public FacesEvent getTarget() {
- return target;
- }
-
- }
-
- /**
- * "memento" pattern class for state of component.
- *
- * @author shura
- *
- */
- private static class DataState implements Serializable {
-
- /**
- *
- */
- private static final long serialVersionUID = 17070532L;
-
- private Object superState;
-
- private Map componentStates = new HashMap();
-
- private Set ajaxKeys;
-
- public String rowKeyVar;
-
- public String stateVar;
-
- }
-
- /**
- * Serialisable model and component state per iteration of parent
- * UIData.
- *
- * @author shura
- *
- */
- private static class PerIdState implements Serializable {
- /**
- *
- */
- private static final long serialVersionUID = 9037454770537726418L;
-
- /**
- * Flag setted to true if componentState implements StateHolder
- */
- private boolean stateInHolder = false;
-
- /**
- * Serializable componentState or
- */
- private Object componentState;
-
- private SerializableDataModel model;
- }
-
- public void restoreState(FacesContext faces, Object object) {
- DataState state = (DataState) object;
- super.restoreState(faces, state.superState);
- this._ajaxKeys = state.ajaxKeys;
- this._statesMap = new HashMap();
- this._rowKeyVar = state.rowKeyVar;
- this._stateVar = state.stateVar;
- // Restore serializable models and component states for all rows of
- // parent UIData ( single if this
- // component not child of iterable )
- for (Iterator iter = state.componentStates.entrySet().iterator(); iter
- .hasNext();) {
- Map.Entry stateEntry = (Map.Entry) iter.next();
- PerIdState idState = (PerIdState) stateEntry.getValue();
- DataComponentState compState;
- if (idState.stateInHolder) {
- // TODO - change RichFaces Tree component, for remove reference
- // to component from state.
- compState = createComponentState();
- ((StateHolder) compState).restoreState(faces,
- idState.componentState);
- } else {
- compState = (DataComponentState) idState.componentState;
- }
- Object key = stateEntry.getKey();
- this._statesMap.put(key, compState);
- this._modelsMap.put(key, idState.model);
- }
- }
-
- public Object saveState(FacesContext faces) {
- DataState state = new DataState();
- state.superState = super.saveState(faces);
- state.ajaxKeys = this._ajaxKeys;
- state.rowKeyVar = this._rowKeyVar;
- state.stateVar = this._stateVar;
- Set encodedIds = getEncodedIds();
- // Save all states of component and data model for all valies of
- // clientId, encoded in this request.
- for (Iterator iter = this._statesMap.entrySet().iterator(); iter
- .hasNext();) {
- Map.Entry stateEntry = (Map.Entry) iter.next();
- DataComponentState dataComponentState = ((DataComponentState) stateEntry
- .getValue());
- Object stateKey = stateEntry.getKey();
- if (encodedIds.isEmpty() || encodedIds.contains(stateKey)) {
- PerIdState idState = new PerIdState();
- idState.model = getExtendedDataModel().getSerializableModel(
- dataComponentState.getRange());
- // Save component state , depended if implemented interfaces.
- if (null == dataComponentState) {
- idState.componentState = null;
- } else if (dataComponentState instanceof Serializable) {
- idState.componentState = dataComponentState;
- } else if (dataComponentState instanceof StateHolder) {
- // TODO - change RichFaces Tree component, for remove
- // reference to component from state.
- // Change this code to reference for saveAttachedState.
- idState.componentState = ((StateHolder) dataComponentState)
- .saveState(faces);
- idState.stateInHolder = true;
- }
- if (null != idState.model || null != idState.componentState) {
- state.componentStates.put(stateKey, idState);
- }
- }
- }
- return state;
- }
-
-}
+/**
+ * License Agreement.
+ *
+ * Ajax4jsf 1.1 - Natural Ajax for Java Server Faces (JSF)
+ *
+ * Copyright (C) 2007 Exadel, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation.
+ *
+ * This library 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 library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+package org.ajax4jsf.ajax.repeat;
+
+import java.io.IOException;
+import java.io.Serializable;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+import javax.faces.FacesException;
+import javax.faces.application.FacesMessage;
+import javax.faces.component.EditableValueHolder;
+import javax.faces.component.NamingContainer;
+import javax.faces.component.StateHolder;
+import javax.faces.component.UIComponent;
+import javax.faces.component.UIData;
+import javax.faces.context.FacesContext;
+import javax.faces.el.ValueBinding;
+import javax.faces.event.AbortProcessingException;
+import javax.faces.event.FacesEvent;
+import javax.faces.event.FacesListener;
+import javax.faces.event.PhaseId;
+import javax.faces.model.DataModel;
+import javax.faces.model.ListDataModel;
+import javax.faces.render.Renderer;
+
+import org.ajax4jsf.framework.renderer.AjaxChildrenRenderer;
+
+/**
+ * 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 shura
+ *
+ */
+public abstract class UIDataAdaptor extends UIData implements AjaxDataEncoder {
+
+ /**
+ *
+ */
+ public static final String COMPONENT_STATE_ATTRIBUTE = "componentState";
+
+ public final static DataModel EMPTY_MODEL = new ListDataModel(
+ Collections.EMPTY_LIST);
+
+ /**
+ * Base class for visit data model at phases decode, validation and
+ * update model
+ *
+ * @author shura
+ *
+ */
+ protected abstract class ComponentVisitor implements DataVisitor {
+
+ public void process(FacesContext context, Object rowKey, Object argument)
+ throws IOException {
+ setRowKey(context, rowKey);
+ if (isRowAvailable()) {
+ Iterator childIterator = dataChildren();
+ while (childIterator.hasNext()) {
+ UIComponent component = (UIComponent) childIterator.next();
+ processComponent(context, component, argument);
+ }
+
+ }
+ }
+
+ public abstract void processComponent(FacesContext context,
+ UIComponent c, Object argument) throws IOException;
+
+ }
+
+ /**
+ * Visitor for process decode on children components.
+ */
+ protected ComponentVisitor decodeVisitor = new ComponentVisitor() {
+
+ public void processComponent(FacesContext context, UIComponent c,
+ Object argument) {
+ c.processDecodes(context);
+ }
+
+ };
+
+ /**
+ * Visitor for process validation phase
+ */
+ protected ComponentVisitor validateVisitor = new ComponentVisitor() {
+
+ public void processComponent(FacesContext context, UIComponent c,
+ Object argument) {
+ c.processValidators(context);
+ }
+
+ };
+
+ /**
+ * Visitor for process update model phase.
+ */
+ protected ComponentVisitor updateVisitor = new ComponentVisitor() {
+
+ public void processComponent(FacesContext context, UIComponent c,
+ Object argument) {
+ c.processUpdates(context);
+ }
+
+ };
+
+ /**
+ * Base client id's of this component, for wich invoked encode...
+ * methods. Component will save state and serialisable models for this
+ * keys only.
+ */
+ private Set _encoded;
+
+ /**
+ * Storage for data model instances with different client id's of this
+ * component. In case of child for UIData component, this map will keep
+ * data models for different iterations between phases.
+ */
+ private Map _modelsMap = new HashMap();
+
+ /**
+ * Reference for curent data model
+ */
+ private ExtendedDataModel _currentModel = null;
+
+ /**
+ * States of this component for diferent iterations, same as for models.
+ */
+ private Map _statesMap = new HashMap();
+
+ /**
+ * Reference for current component state.
+ */
+ private DataComponentState _currentState = null;
+
+ /**
+ * Name of EL variable for current component state.
+ */
+ private String _stateVar;
+
+ private String _rowKeyVar;
+
+ /**
+ * Key for current value in model.
+ */
+ private Object _rowKey = null;
+
+ /**
+ * Values of row keys, encoded on ajax response rendering.
+ */
+ private Set _ajaxKeys = null;
+
+ private Object _ajaxRowKey = null;
+
+ private Map _ajaxRowKeysMap = new HashMap();
+
+ /**
+ * Get name of EL variable for component state.
+ *
+ * @return the varState
+ */
+ public String getStateVar() {
+ return _stateVar;
+ }
+
+ /**
+ * @param varStatus
+ * the varStatus to set
+ */
+ public void setStateVar(String varStatus) {
+ this._stateVar = varStatus;
+ }
+
+ /**
+ * @return the rowKeyVar
+ */
+ public String getRowKeyVar() {
+ return this._rowKeyVar;
+ }
+
+ /**
+ * @param rowKeyVar
+ * the rowKeyVar to set
+ */
+ public void setRowKeyVar(String rowKeyVar) {
+ this._rowKeyVar = rowKeyVar;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see javax.faces.component.UIData#getRowCount()
+ */
+ public int getRowCount() {
+ return getExtendedDataModel().getRowCount();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see javax.faces.component.UIData#getRowData()
+ */
+ public Object getRowData() {
+ return getExtendedDataModel().getRowData();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see javax.faces.component.UIData#isRowAvailable()
+ */
+ public boolean isRowAvailable() {
+ return this.getExtendedDataModel().isRowAvailable();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see javax.faces.component.UIData#setRowIndex(int)
+ */
+ public void setRowIndex(int index) {
+ FacesContext faces = FacesContext.getCurrentInstance();
+ ExtendedDataModel localModel = getExtendedDataModel();
+ // if(key == localModel.getRowIndex()){
+ // return;
+ // }
+ // save child state
+ this.saveChildState(faces);
+ // Set current model row by int, but immediately get value from model.
+ // for compability, complex models must provide values map between
+ // integer and key value.
+ localModel.setRowIndex(index);
+ this._rowKey = localModel.getRowKey();
+ this._clientId = null;
+ boolean rowSelected = this._rowKey != null;
+
+ setupVariable(faces, localModel, rowSelected);
+ // restore child state
+ this.restoreChildState(faces);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see javax.faces.component.UIData#getRowIndex()
+ */
+ public int getRowIndex() {
+ return getExtendedDataModel().getRowIndex();
+ }
+
+ /**
+ * Same as for int index, but for complex model key.
+ *
+ * @return
+ */
+ public Object getRowKey() {
+ return this._rowKey;
+ }
+
+ public void setRowKey(Object key) {
+ setRowKey(FacesContext.getCurrentInstance(), key);
+ }
+
+ /**
+ * Setup current roy by key. Perform same functionality as
+ * {@link 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.
+ *
+ * @param faces -
+ * current FacesContext
+ * @param key
+ * new key value.
+ */
+ public void setRowKey(FacesContext faces, Object key) {
+ ExtendedDataModel localModel = getExtendedDataModel();
+ // save child state
+ this.saveChildState(faces);
+ this._rowKey = key;
+ this._clientId = null;
+ localModel.setRowKey(key);
+
+ boolean rowSelected = key != null;
+
+ setupVariable(faces, localModel, rowSelected);
+ // restore child state
+ this.restoreChildState(faces);
+
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.ajax4jsf.ajax.repeat.AjaxDataEncoder#getAjaxKeys()
+ */
+ public Set getAjaxKeys() {
+ Set keys = null;
+ if (this._ajaxKeys != null) {
+ keys = (this._ajaxKeys);
+ } else {
+ ValueBinding vb = getValueBinding("ajaxKeys");
+ if (vb != null) {
+ keys = (Set) (vb.getValue(getFacesContext()));
+ } else if(null != _ajaxRowKey){
+ // If none of above exist , use row with submitted AjaxComponent
+ keys = new HashSet(1);
+ keys.add(_ajaxRowKey);
+ }
+ }
+ return keys;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.ajax4jsf.ajax.repeat.AjaxDataEncoder#setAjaxKeys(java.util.Set)
+ */
+ public void setAjaxKeys(Set ajaxKeys) {
+ this._ajaxKeys = ajaxKeys;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
org.ajax4jsf.framework.ajax.AjaxChildrenEncoder#encodeAjaxChild(javax.faces.context.FacesContext,
+ * java.lang.String, java.util.Set, java.util.Set)
+ */
+ public void encodeAjaxChild(FacesContext context, String path,
+ final Set ids, final Set renderedAreas) throws IOException {
+ resetDataModel();
+
+ Renderer renderer = getRenderer(context);
+ if (null != renderer && renderer instanceof AjaxChildrenRenderer) {
+ // If renderer support partial encoding - call them.
+ AjaxChildrenRenderer childrenRenderer = (AjaxChildrenRenderer) renderer;
+ childrenRenderer.encodeAjaxChildren(context, this, path, ids,
+ renderedAreas);
+ } else {
+ // Use simple ajax children encoding for iterate other keys.
+ final AjaxChildrenRenderer childrenRenderer = getChildrenRenderer();
+ final String childrenPath = path + getId() + NamingContainer.SEPARATOR_CHAR;
+ ComponentVisitor ajaxVisitor = new ComponentVisitor() {
+
+ public void processComponent(FacesContext context,
+ UIComponent c, Object argument) throws IOException {
+ childrenRenderer.encodeAjaxComponent(context, c, childrenPath,
+ ids, renderedAreas);
+ }
+
+ };
+ Set ajaxKeys = getAjaxKeys();
+ if (null != ajaxKeys) {
+ captureOrigValue();
+ Object savedKey = getRowKey();
+ setRowKey(context, null);
+ Iterator fixedChildren = fixedChildren();
+ while (fixedChildren.hasNext()) {
+ UIComponent component = (UIComponent) fixedChildren.next();
+ ajaxVisitor.processComponent(context, component, null);
+ }
+ for (Iterator iter = ajaxKeys.iterator(); iter.hasNext();) {
+ Object key = (Object) iter.next();
+ ajaxVisitor.process(context, key, null);
+ }
+ setRowKey(savedKey);
+ restoreOrigValue();
+ } else {
+ iterate(context, ajaxVisitor, null);
+ }
+ }
+ }
+
+ /**
+ * Instance of default renderer in ajax responses.
+ */
+ private AjaxChildrenRenderer _childrenRenderer = null;
+
+ /**
+ * getter for simple {@link AjaxChildrenRenderer} instance in case of
+ * ajax responses. If default renderer not support search of children
+ * for encode in ajax response, component will use this instance by
+ * default.
+ *
+ * @return
+ */
+ protected AjaxChildrenRenderer getChildrenRenderer() {
+ if (_childrenRenderer == null) {
+ _childrenRenderer = new AjaxChildrenRenderer() {
+
+ protected Class getComponentClass() {
+ return UIDataAdaptor.class;
+ }
+
+ };
+
+ }
+
+ return _childrenRenderer;
+ }
+
+ /**
+ * @return Set of values for clientId's of this component, for wich was
+ * invoked "encode" methods.
+ */
+ protected Set getEncodedIds() {
+ if (_encoded == null) {
+ _encoded = new HashSet();
+ }
+
+ return _encoded;
+ }
+
+ /**
+ * 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.
+ *
+ * @param faces
+ * current faces context
+ * @param localModel
+ * @param rowSelected
+ */
+ protected void setupVariable(FacesContext faces, DataModel localModel,
+ boolean rowSelected) {
+ Map attrs = faces.getExternalContext().getRequestMap();
+ if (rowSelected && isRowAvailable()) {
+ // Current row data.
+ setupVariable(getVar(), attrs, localModel.getRowData());
+ // Component state variable.
+ setupVariable(getStateVar(), attrs, getComponentState());
+ // Row key Data variable.
+ setupVariable(getRowKeyVar(), attrs, getRowKey());
+
+ } else {
+ removeVariable(getVar(), attrs);
+ removeVariable(getStateVar(), attrs);
+ removeVariable(getRowKeyVar(), attrs);
+ }
+ }
+
+ /**
+ * @param var
+ * @param attrs
+ * @param rowData
+ */
+ private void setupVariable(String var, Map attrs, Object rowData) {
+ if (var != null) {
+ attrs.put(var, rowData);
+ }
+ }
+
+ /**
+ * @param var
+ * @param attrs
+ * @param rowData
+ */
+ private void removeVariable(String var, Map attrs) {
+ if (var != null) {
+ attrs.remove(var);
+ }
+ }
+
+ /**
+ * Reset data model. this method must be called twice per request -
+ * before decode phase and before component encoding.
+ */
+ protected void resetDataModel() {
+ this.setExtendedDataModel(null);
+ }
+
+ /**
+ * Set data model. Model value will be stored in Map with key as current
+ * clientId for this component, to keep models between phases for same
+ * iteration in case if this component child for other UIData
+ *
+ * @param model
+ */
+ protected void setExtendedDataModel(ExtendedDataModel model) {
+ this._currentModel = model;
+ this._modelsMap.put(getBaseClientId(getFacesContext()), model);
+ }
+
+ /**
+ * Get current data model, or create it by {@link #createDataModel()}
+ * method. For different iterations in ancestor UIData ( if present )
+ * will be returned different models.
+ *
+ * @return current data model.
+ */
+ protected ExtendedDataModel getExtendedDataModel() {
+ if (this._currentModel == null) {
+ String baseClientId = getBaseClientId(getFacesContext());
+ ExtendedDataModel model = (ExtendedDataModel) this._modelsMap
+ .get(baseClientId);
+ if (null == model) {
+ model = createDataModel();
+ this._modelsMap.put(baseClientId, model);
+ }
+ this._currentModel = model;
+ }
+ return this._currentModel;
+ }
+
+ /**
+ * Hook mathod for create data model in concrete implementations.
+ *
+ * @return
+ */
+ protected abstract ExtendedDataModel createDataModel();
+
+ /**
+ * Set current state ( at most cases, visual representation ) of this
+ * component. Same as for DataModel, component will keep states for
+ * different iterations.
+ *
+ * @param state
+ */
+ public void setComponentState(DataComponentState state) {
+ this._currentState = state;
+ this._statesMap.put(getBaseClientId(getFacesContext()),
+ this._currentState);
+ }
+
+ /**
+ * @return current state of this component.
+ */
+ public DataComponentState getComponentState() {
+ DataComponentState state = null;
+ if (this._currentState == null) {
+ // Check for binding state to user bean.
+ ValueBinding valueBinding =
getValueBinding(UIDataAdaptor.COMPONENT_STATE_ATTRIBUTE);
+ FacesContext facesContext = getFacesContext();
+ if (null != valueBinding) {
+ state = (DataComponentState) valueBinding
+ .getValue(facesContext);
+ if (null == state) {
+ // Create default state
+ state = createComponentState();
+ if (!valueBinding.isReadOnly(facesContext)) {
+ // Store created state in user bean.
+ valueBinding.setValue(facesContext, state);
+ }
+ }
+ } else {
+ // Check for stored state in map for parent iterations
+ String baseClientId = getBaseClientId(facesContext);
+ state = (DataComponentState) this._statesMap.get(baseClientId);
+ if (null == state) {
+ // Create default component state
+ state = createComponentState();
+ this._statesMap.put(baseClientId, state);
+ }
+ this._currentState = state;
+ }
+ } else {
+ state = this._currentState;
+ }
+ return state;
+ }
+
+ /**
+ * Hook method for create default state in concrete implementations.
+ *
+ * @return
+ */
+ protected abstract DataComponentState createComponentState();
+
+ private String _clientId = null;
+
+ public String getClientId(FacesContext faces) {
+ if (null == _clientId) {
+ StringBuffer id = new StringBuffer(getBaseClientId(faces));
+ Object rowKey = getRowKey();
+ if (rowKey != null) {
+ id.append(NamingContainer.SEPARATOR_CHAR).append(
+ rowKey.toString());
+ }
+ Renderer renderer;
+ if (null != (renderer = getRenderer(faces))) {
+ _clientId = renderer.convertClientId(faces, id.toString());
+ } else {
+ _clientId = id.toString();
+ }
+
+ }
+ return _clientId;
+ }
+
+ private String _baseClientId = null;
+
+ /**
+ * Get base clietntId of this component ( withowt iteration part )
+ *
+ * @param faces
+ * @return
+ */
+ public String getBaseClientId(FacesContext faces) {
+ // Return any previously cached client identifier
+ if (_baseClientId == null) {
+
+ // Search for an ancestor that is a naming container
+ UIComponent ancestorContainer = this;
+ StringBuffer parentIds = new StringBuffer();
+ while (null != (ancestorContainer = ancestorContainer.getParent())) {
+ if (ancestorContainer instanceof NamingContainer) {
+ parentIds.append(ancestorContainer.getClientId(faces))
+ .append(NamingContainer.SEPARATOR_CHAR);
+ break;
+ }
+ }
+ String id = getId();
+ if (null != id) {
+ _baseClientId = parentIds.append(id).toString();
+ } else {
+ _baseClientId = parentIds.append(
+ faces.getViewRoot().createUniqueId()).toString();
+ }
+ }
+ return (_baseClientId);
+
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see javax.faces.component.UIComponentBase#setId(java.lang.String)
+ */
+ public void setId(String id) {
+ // If component created by restoring tree or JSP, initial Id is null.
+ boolean haveId = null != super.getId();
+ super.setId(id);
+ _baseClientId = null;
+ _clientId = null;
+ if (haveId) {
+ // parent UIData ( if present ) will be set same Id at iteration
+ // -
+ // we use it for
+ // switch to different model and state.
+ String baseClientId = getBaseClientId(getFacesContext());
+ this._currentState = (DataComponentState) this._statesMap
+ .get(baseClientId);
+ this._currentModel = (ExtendedDataModel) this._modelsMap
+ .get(baseClientId);
+ if (null != this._currentModel) {
+ this._rowKey = this._currentModel.getRowKey();
+ // restoreChildState();
+ }
+ // Restore value for row with submitted AjaxComponent.
+ this._ajaxRowKey = _ajaxRowKeysMap.get(baseClientId);
+ }
+ }
+
+ private Object origValue;
+
+ /**
+ * Save current state of data variable.
+ */
+ public void captureOrigValue() {
+ captureOrigValue(FacesContext.getCurrentInstance());
+ }
+
+ /**
+ * Save current state of data variable.
+ *
+ * @param faces
+ * current faces context
+ */
+ public void captureOrigValue(FacesContext faces) {
+ String var = getVar();
+ if (var != null) {
+ Map attrs = faces.getExternalContext().getRequestMap();
+ this.origValue = attrs.get(var);
+ }
+ }
+
+ /**
+ * Restore value of data variable after processing phase.
+ */
+ public void restoreOrigValue() {
+ restoreOrigValue(FacesContext.getCurrentInstance());
+ }
+
+ /**
+ * Restore value of data variable after processing phase.
+ *
+ * @param faces
+ * current faces context
+ */
+ public void restoreOrigValue(FacesContext faces) {
+ String var = getVar();
+ if (var != null) {
+ Map attrs = faces.getExternalContext().getRequestMap();
+ if (this.origValue != null) {
+ attrs.put(var, this.origValue);
+ } else {
+ attrs.remove(var);
+ }
+ }
+ }
+
+ /**
+ * Saved values of {@link EditableValueHolder} fields per iterations.
+ */
+ private Map childState;
+
+ /**
+ * @param faces
+ * @return Saved values of {@link EditableValueHolder} fields per
+ * iterations.
+ */
+ protected Map getChildState(FacesContext faces) {
+ if (this.childState == null) {
+ this.childState = new HashMap();
+ }
+ String baseClientId = getBaseClientId(faces);
+ Map currentChildState = (Map) childState.get(baseClientId);
+ if (null == currentChildState) {
+ currentChildState = new HashMap();
+ childState.put(baseClientId, currentChildState);
+ }
+ return currentChildState;
+ }
+
+ /**
+ * Save values of {@link EditableValueHolder} fields before change
+ * current row.
+ *
+ * @param faces
+ */
+ protected void saveChildState(FacesContext faces) {
+
+ Iterator itr = dataChildren();
+ while (itr.hasNext()) {
+ Map childState = this.getChildState(faces);
+ this.saveChildState(faces, (UIComponent) itr.next(), childState);
+ }
+ }
+
+ /**
+ * Recursive method for Iterate on children for save
+ * {@link EditableValueHolder} fields states.
+ *
+ * @param faces
+ * @param c
+ * @param childState
+ */
+ private void saveChildState(FacesContext faces, UIComponent c,
+ Map childState) {
+
+ if (c instanceof EditableValueHolder && !c.isTransient()) {
+ String clientId = c.getClientId(faces);
+ SavedState ss = (SavedState) childState.get(clientId);
+ if (ss == null) {
+ ss = new SavedState();
+ childState.put(clientId, ss);
+ }
+ ss.populate((EditableValueHolder) c);
+ }
+
+ // continue hack
+ Iterator itr = c.getChildren().iterator();
+ while (itr.hasNext()) {
+ saveChildState(faces, (UIComponent) itr.next(), childState);
+ }
+ itr = c.getFacets().values().iterator();
+ while (itr.hasNext()) {
+ saveChildState(faces, (UIComponent) itr.next(), childState);
+ }
+ }
+
+ /**
+ * Restore values of {@link EditableValueHolder} fields after change
+ * current row.
+ *
+ * @param faces
+ */
+ protected void restoreChildState(FacesContext faces) {
+
+ Iterator itr = dataChildren();
+ while (itr.hasNext()) {
+ Map childState = this.getChildState(faces);
+ this.restoreChildState(faces, (UIComponent) itr.next(), childState);
+ }
+ }
+
+ /**
+ * Recursive part of
+ * {@link #restoreChildState(FacesContext, UIComponent, Map)}
+ *
+ * @param faces
+ * @param c
+ * @param childState
+ *
+ */
+ private void restoreChildState(FacesContext faces, UIComponent c,
+ Map childState) {
+ // reset id
+ String id = c.getId();
+ c.setId(id);
+
+ // hack
+ if (c instanceof EditableValueHolder) {
+ EditableValueHolder evh = (EditableValueHolder) c;
+ String clientId = c.getClientId(faces);
+ SavedState ss = (SavedState) childState.get(clientId);
+ if (ss != null) {
+ ss.apply(evh);
+ } else {
+ NullState.apply(evh);
+ }
+ }
+
+ // continue hack
+ Iterator itr = c.getChildren().iterator();
+ while (itr.hasNext()) {
+ restoreChildState(faces, (UIComponent) itr.next(), childState);
+ }
+ itr = c.getFacets().values().iterator();
+ while (itr.hasNext()) {
+ restoreChildState(faces, (UIComponent) itr.next(), childState);
+ }
+ }
+
+ /**
+ * Check for validation errors on children components. If true, saved
+ * values must be keep on render phase
+ *
+ * @param context
+ * @return
+ */
+ private boolean keepSaved(FacesContext context) {
+
+ Iterator clientIds = this.getChildState(context).keySet().iterator();
+ while (clientIds.hasNext()) {
+ String clientId = (String) clientIds.next();
+ Iterator messages = context.getMessages(clientId);
+ while (messages.hasNext()) {
+ FacesMessage message = (FacesMessage) messages.next();
+ if (message.getSeverity()
+ .compareTo(FacesMessage.SEVERITY_ERROR) >= 0) {
+ return (true);
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Perform iteration on all children components and all data rows with
+ * given visitor.
+ *
+ * @param faces
+ * @param visitor
+ */
+ protected void iterate(FacesContext faces, ComponentVisitor visitor,
+ Object argument) {
+
+ // stop if not rendered
+ if (!this.isRendered()) {
+ return;
+ }
+ // reset rowIndex
+ this.captureOrigValue(faces);
+ this.setRowKey(faces, null);
+ try {
+ Iterator fixedChildren = fixedChildren();
+ while (fixedChildren.hasNext()) {
+ UIComponent component = (UIComponent) fixedChildren.next();
+ visitor.processComponent(faces, component, argument);
+ }
+
+ walk(faces, visitor, argument);
+ } catch (Exception e) {
+ throw new FacesException(e);
+ } finally {
+ this.setRowKey(faces, null);
+ this.restoreOrigValue(faces);
+ }
+ }
+
+ /**
+ * Walk ( visit ) this component on all data-avare children for each
+ * row.
+ *
+ * @param faces
+ * @param visitor
+ * @throws IOException
+ */
+ public void walk(FacesContext faces, DataVisitor visitor, Object argument)
+ throws IOException {
+ getExtendedDataModel().walk(faces, visitor,
+ getComponentState().getRange(), argument);
+ }
+
+ protected void processDecodes(FacesContext faces, Object argument) {
+ if (!this.isRendered())
+ return;
+ this.resetComponent(faces);
+ this.iterate(faces, decodeVisitor, argument);
+ this.decode(faces);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
javax.faces.component.UIData#processDecodes(javax.faces.context.FacesContext)
+ */
+ public void processDecodes(FacesContext faces) {
+ processDecodes(faces, null);
+ }
+
+ /**
+ * Reset per-request fields in component.
+ *
+ * @param faces
+ *
+ */
+ protected void resetComponent(FacesContext faces) {
+ // resetDataModel();
+ if (null != this.childState) {
+ childState.remove(getBaseClientId(faces));
+ }
+ this._encoded = null;
+ }
+
+ protected void processUpdates(FacesContext faces, Object argument) {
+ if (!this.isRendered())
+ return;
+ this.iterate(faces, updateVisitor, argument);
+ ExtendedDataModel dataModel = getExtendedDataModel();
+ // If no validation errors, update values for serializable model,
+ // restored from view.
+ if (dataModel instanceof SerializableDataModel && (!keepSaved(faces))) {
+ SerializableDataModel serializableModel = (SerializableDataModel) dataModel;
+ serializableModel.update();
+ }
+ }
+
+ public void processUpdates(FacesContext faces) {
+ processUpdates(faces, null);
+ }
+
+ protected void processValidators(FacesContext faces, Object argument) {
+ if (!this.isRendered())
+ return;
+ this.iterate(faces, validateVisitor, argument);
+ }
+
+ public void processValidators(FacesContext faces) {
+ processValidators(faces, null);
+ }
+
+ public void encodeBegin(FacesContext context) throws IOException {
+ resetDataModel();
+ // if(!keepSaved(context)){
+ // childState.remove(getBaseClientId(context));
+ // }
+ // Mark component as used, if parent UIData change own range states not
+ // accessed at
+ // encode phase must be unsaved.
+ getEncodedIds().add(getBaseClientId(context));
+ // getComponentState().setUsed(true);
+ super.encodeBegin(context);
+ }
+
+ /**
+ * This method must create iterator for all non-data avare children of
+ * this component ( header/footer facets for components and columns in
+ * dataTable, facets for tree etc.
+ *
+ * @return iterator for all components not sensitive for row data.
+ */
+ protected abstract Iterator fixedChildren();
+
+ /**
+ * This method must create iterator for all children components,
+ * processed "per row" It can be children of UIColumn in dataTable,
+ * nodes in tree
+ *
+ * @return iterator for all components processed per row.
+ */
+ protected abstract Iterator dataChildren();
+
+ private final static SavedState NullState = new SavedState();
+
+ // from RI
+ /**
+ * This class keep values of {@link EditableValueHolder} row-sensitive
+ * fields.
+ *
+ * @author shura
+ *
+ */
+ private final static class SavedState implements Serializable {
+
+ private Object submittedValue;
+
+ private static final long serialVersionUID = 2920252657338389849L;
+
+ Object getSubmittedValue() {
+ return (this.submittedValue);
+ }
+
+ void setSubmittedValue(Object submittedValue) {
+ this.submittedValue = submittedValue;
+ }
+
+ private boolean valid = true;
+
+ boolean isValid() {
+ return (this.valid);
+ }
+
+ void setValid(boolean valid) {
+ this.valid = valid;
+ }
+
+ private Object value;
+
+ Object getValue() {
+ return (this.value);
+ }
+
+ public void setValue(Object value) {
+ this.value = value;
+ }
+
+ private boolean localValueSet;
+
+ boolean isLocalValueSet() {
+ return (this.localValueSet);
+ }
+
+ public void setLocalValueSet(boolean localValueSet) {
+ this.localValueSet = localValueSet;
+ }
+
+ public String toString() {
+ return ("submittedValue: " + submittedValue + " value: " +
value
+ + " localValueSet: " + localValueSet);
+ }
+
+ public void populate(EditableValueHolder evh) {
+ this.value = evh.getLocalValue();
+ this.valid = evh.isValid();
+ this.submittedValue = evh.getSubmittedValue();
+ this.localValueSet = evh.isLocalValueSet();
+ }
+
+ public void apply(EditableValueHolder evh) {
+ evh.setValue(this.value);
+ evh.setValid(this.valid);
+ evh.setSubmittedValue(this.submittedValue);
+ evh.setLocalValueSet(this.localValueSet);
+ }
+
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see javax.faces.component.UIData#queueEvent(javax.faces.event.FacesEvent)
+ */
+ public void queueEvent(FacesEvent event) {
+ if (event.getComponent() != this) {
+ event = new IndexedEvent(this, event, getRowKey());
+ }
+ // Send event directly to parent, to avoid wrapping in superclass.
+ UIComponent parent = getParent();
+ if (parent == null) {
+ throw new IllegalStateException(
+ "No parent component for queue event");
+ } else {
+ parent.queueEvent(event);
+ }
+ }
+
+ public void broadcast(FacesEvent event) throws AbortProcessingException {
+
+ if (!(event instanceof IndexedEvent)) {
+ if (!broadcastLocal(event)) {
+ super.broadcast(event);
+ }
+ return;
+ }
+
+ // Set up the correct context and fire our wrapped event
+ IndexedEvent revent = (IndexedEvent) event;
+ Object oldRowKey = getRowKey();
+ FacesContext faces = FacesContext.getCurrentInstance();
+ captureOrigValue(faces);
+ Object eventRowKey = revent.getKey();
+ setRowKey(faces, eventRowKey);
+ FacesEvent rowEvent = revent.getTarget();
+ rowEvent.getComponent().broadcast(rowEvent);
+ // For Ajax events, keep row value.
+ if (!(rowEvent.getPhaseId() == PhaseId.RENDER_RESPONSE)) {
+ this._ajaxRowKey = eventRowKey;
+ this._ajaxRowKeysMap.put(getBaseClientId(faces), eventRowKey);
+ }
+ setRowKey(faces, oldRowKey);
+ restoreOrigValue(faces);
+ // }
+ return;
+ }
+
+ /**
+ * Process events targetted for concrete implementation. Hook method
+ * called from {@link #broadcast(FacesEvent)}
+ *
+ * @param event -
+ * processed event.
+ * @return true if event processed, false if component must continue
+ * processing.
+ */
+ protected boolean broadcastLocal(FacesEvent event) {
+ return false;
+ }
+
+ /**
+ * Wrapper for event from child component, with value of current row
+ * key.
+ *
+ * @author shura
+ *
+ */
+ protected static final class IndexedEvent extends FacesEvent {
+
+ private static final long serialVersionUID = -8318895390232552385L;
+
+ private final FacesEvent target;
+
+ private final Object key;
+
+ public IndexedEvent(UIDataAdaptor owner, FacesEvent target, Object key) {
+ super(owner);
+ this.target = target;
+ this.key = key;
+ }
+
+ public PhaseId getPhaseId() {
+ return (this.target.getPhaseId());
+ }
+
+ public void setPhaseId(PhaseId phaseId) {
+ this.target.setPhaseId(phaseId);
+ }
+
+ public boolean isAppropriateListener(FacesListener listener) {
+ return this.target.isAppropriateListener(listener);
+ }
+
+ public void processListener(FacesListener listener) {
+ UIDataAdaptor owner = (UIDataAdaptor) this.getComponent();
+ Object prevIndex = owner._rowKey;
+ try {
+ owner.setRowKey(this.key);
+ this.target.processListener(listener);
+ } finally {
+ owner.setRowKey(prevIndex);
+ }
+ }
+
+ public Object getKey() {
+ return key;
+ }
+
+ public FacesEvent getTarget() {
+ return target;
+ }
+
+ }
+
+ /**
+ * "memento" pattern class for state of component.
+ *
+ * @author shura
+ *
+ */
+ private static class DataState implements Serializable {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 17070532L;
+
+ private Object superState;
+
+ private Map componentStates = new HashMap();
+
+ private Set ajaxKeys;
+
+ public String rowKeyVar;
+
+ public String stateVar;
+
+ }
+
+ /**
+ * Serialisable model and component state per iteration of parent
+ * UIData.
+ *
+ * @author shura
+ *
+ */
+ private static class PerIdState implements Serializable {
+ /**
+ *
+ */
+ private static final long serialVersionUID = 9037454770537726418L;
+
+ /**
+ * Flag setted to true if componentState implements StateHolder
+ */
+ private boolean stateInHolder = false;
+
+ /**
+ * Serializable componentState or
+ */
+ private Object componentState;
+
+ private SerializableDataModel model;
+ }
+
+ public void restoreState(FacesContext faces, Object object) {
+ DataState state = (DataState) object;
+ super.restoreState(faces, state.superState);
+ this._ajaxKeys = state.ajaxKeys;
+ this._statesMap = new HashMap();
+ this._rowKeyVar = state.rowKeyVar;
+ this._stateVar = state.stateVar;
+ // Restore serializable models and component states for all rows of
+ // parent UIData ( single if this
+ // component not child of iterable )
+ for (Iterator iter = state.componentStates.entrySet().iterator(); iter
+ .hasNext();) {
+ Map.Entry stateEntry = (Map.Entry) iter.next();
+ PerIdState idState = (PerIdState) stateEntry.getValue();
+ DataComponentState compState;
+ if (idState.stateInHolder) {
+ // TODO - change RichFaces Tree component, for remove reference
+ // to component from state.
+ compState = createComponentState();
+ ((StateHolder) compState).restoreState(faces,
+ idState.componentState);
+ } else {
+ compState = (DataComponentState) idState.componentState;
+ }
+ Object key = stateEntry.getKey();
+ this._statesMap.put(key, compState);
+ this._modelsMap.put(key, idState.model);
+ }
+ }
+
+ public Object saveState(FacesContext faces) {
+ DataState state = new DataState();
+ state.superState = super.saveState(faces);
+ state.ajaxKeys = this._ajaxKeys;
+ state.rowKeyVar = this._rowKeyVar;
+ state.stateVar = this._stateVar;
+ Set encodedIds = getEncodedIds();
+ // Save all states of component and data model for all valies of
+ // clientId, encoded in this request.
+ for (Iterator iter = this._statesMap.entrySet().iterator(); iter
+ .hasNext();) {
+ Map.Entry stateEntry = (Map.Entry) iter.next();
+ DataComponentState dataComponentState = ((DataComponentState) stateEntry
+ .getValue());
+ Object stateKey = stateEntry.getKey();
+ if (encodedIds.isEmpty() || encodedIds.contains(stateKey)) {
+ PerIdState idState = new PerIdState();
+ idState.model = getExtendedDataModel().getSerializableModel(
+ dataComponentState.getRange());
+ // Save component state , depended if implemented interfaces.
+ if (null == dataComponentState) {
+ idState.componentState = null;
+ } else if (dataComponentState instanceof Serializable) {
+ idState.componentState = dataComponentState;
+ } else if (dataComponentState instanceof StateHolder) {
+ // TODO - change RichFaces Tree component, for remove
+ // reference to component from state.
+ // Change this code to reference for saveAttachedState.
+ idState.componentState = ((StateHolder) dataComponentState)
+ .saveState(faces);
+ idState.stateInHolder = true;
+ }
+ if (null != idState.model || null != idState.componentState) {
+ state.componentStates.put(stateKey, idState);
+ }
+ }
+ }
+ return state;
+ }
+
+ public void setParent(UIComponent parent) {
+ super.setParent(parent);
+ this._clientId = null;
+ this._baseClientId = null;
+ }
+
+
+}
Modified: branches/refactor1/samples/useCases/src/main/java/org/ajax4jsf/RepeatData.java
===================================================================
---
branches/refactor1/samples/useCases/src/main/java/org/ajax4jsf/RepeatData.java 2007-06-30
00:04:34 UTC (rev 1428)
+++
branches/refactor1/samples/useCases/src/main/java/org/ajax4jsf/RepeatData.java 2007-06-30
00:13:26 UTC (rev 1429)
@@ -39,6 +39,11 @@
}
}
+ public String ok(){
+ System.out.println("Row command pressed");
+ return null;
+ }
+
/**
* @return the data
*/
Modified: branches/refactor1/samples/useCases/src/main/webapp/pages/repeat.xhtml
===================================================================
--- branches/refactor1/samples/useCases/src/main/webapp/pages/repeat.xhtml 2007-06-30
00:04:34 UTC (rev 1428)
+++ branches/refactor1/samples/useCases/src/main/webapp/pages/repeat.xhtml 2007-06-30
00:13:26 UTC (rev 1429)
@@ -31,8 +31,8 @@
<ol>
<a4j:repeat value="#{row.data}" var="row1"
id="r1">
<li><h:inputText value="#{row1.text}"></h:inputText>
<h:outputText
- id="text1" value="#{row1.text}"></h:outputText>
<a4j:commandButton
- value="Up"
reRender="text1"></a4j:commandButton></li>
+ id="text1" value="#{row1.text}"></h:outputText>
<a4j:commandLink
+ value="Up" action="#{row1.ok}"
reRender="text1"></a4j:commandLink></li>
</a4j:repeat>
</ol>
</li>