Author: nbelaevski
Date: 2009-09-27 19:21:24 -0400 (Sun, 27 Sep 2009)
New Revision: 15673
Added:
root/framework/trunk/api/src/main/java/org/ajax4jsf/model/DataVisitResult.java
root/framework/trunk/impl/src/main/java/org/richfaces/component/RowKeyContextEventWrapper.java
root/framework/trunk/impl/src/main/java/org/richfaces/component/SavedState.java
root/framework/trunk/impl/src/main/java/org/richfaces/component/UIDataAdaptor.java
root/framework/trunk/impl/src/main/java/org/richfaces/component/UISequence.java
Removed:
root/framework/trunk/impl/src/main/java/org/ajax4jsf/component/RenderPhaseUIDataAdaptorVisitor.java
root/framework/trunk/impl/src/main/java/org/ajax4jsf/component/SequenceDataAdaptor.java
root/framework/trunk/impl/src/main/java/org/ajax4jsf/component/UIDataAdaptor.java
root/framework/trunk/impl/src/main/resources/META-INF/services/org.richfaces.component.RenderPhaseComponentVisitor
Modified:
root/framework/trunk/api/src/main/java/org/ajax4jsf/model/DataVisitor.java
root/framework/trunk/api/src/main/java/org/ajax4jsf/model/ExtendedDataModel.java
root/framework/trunk/api/src/main/java/org/ajax4jsf/model/RepeatState.java
root/framework/trunk/api/src/main/java/org/ajax4jsf/model/SequenceDataModel.java
root/framework/trunk/impl/src/main/java/org/ajax4jsf/webapp/taglib/RowKeyConverterRule.java
root/framework/trunk/impl/src/main/java/org/richfaces/component/UISwitchablePanel.java
root/framework/trunk/impl/src/main/java/org/richfaces/webapp/taglib/UIComponentELTagBase.java
root/framework/trunk/impl/src/main/resources/META-INF/faces-config.xml
Log:
UIData implementation initial check-in
Added: root/framework/trunk/api/src/main/java/org/ajax4jsf/model/DataVisitResult.java
===================================================================
--- root/framework/trunk/api/src/main/java/org/ajax4jsf/model/DataVisitResult.java
(rev 0)
+++
root/framework/trunk/api/src/main/java/org/ajax4jsf/model/DataVisitResult.java 2009-09-27
23:21:24 UTC (rev 15673)
@@ -0,0 +1,31 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2009, 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.ajax4jsf.model;
+
+/**
+ * @author Nick Belaevski
+ *
+ */
+public enum DataVisitResult {
+
+ CONTINUE, STOP;
+}
Modified: root/framework/trunk/api/src/main/java/org/ajax4jsf/model/DataVisitor.java
===================================================================
--- root/framework/trunk/api/src/main/java/org/ajax4jsf/model/DataVisitor.java 2009-09-25
16:50:56 UTC (rev 15672)
+++ root/framework/trunk/api/src/main/java/org/ajax4jsf/model/DataVisitor.java 2009-09-27
23:21:24 UTC (rev 15673)
@@ -21,8 +21,6 @@
package org.ajax4jsf.model;
-import java.io.IOException;
-
import javax.faces.context.FacesContext;
/**
@@ -38,8 +36,7 @@
* @param context current JSF context.
* @param rowKey current row key of DataModel
* @param argument Implementation-specific argument
- * @throws IOException
*/
- public void process(FacesContext context,Object rowKey, Object argument) throws
IOException;
+ public DataVisitResult process(FacesContext context,Object rowKey, Object argument);
}
Modified:
root/framework/trunk/api/src/main/java/org/ajax4jsf/model/ExtendedDataModel.java
===================================================================
---
root/framework/trunk/api/src/main/java/org/ajax4jsf/model/ExtendedDataModel.java 2009-09-25
16:50:56 UTC (rev 15672)
+++
root/framework/trunk/api/src/main/java/org/ajax4jsf/model/ExtendedDataModel.java 2009-09-27
23:21:24 UTC (rev 15673)
@@ -33,7 +33,7 @@
* @author shura
*
*/
-public abstract class ExtendedDataModel extends DataModel {
+public abstract class ExtendedDataModel<E> extends DataModel<E> {
/**
* <p>Instead of simple <code>int</code> for current state selection,
this model can use any object for
@@ -71,7 +71,7 @@
* @param argument Implementation-specific argument
* @throws IOException
*/
- public abstract void walk(FacesContext context,DataVisitor visitor,Range range, Object
argument) throws IOException;
+ public abstract void walk(FacesContext context,DataVisitor visitor,Range range, Object
argument);
/**
* Create Iterator on all row keys for given range.
Modified: root/framework/trunk/api/src/main/java/org/ajax4jsf/model/RepeatState.java
===================================================================
--- root/framework/trunk/api/src/main/java/org/ajax4jsf/model/RepeatState.java 2009-09-25
16:50:56 UTC (rev 15672)
+++ root/framework/trunk/api/src/main/java/org/ajax4jsf/model/RepeatState.java 2009-09-27
23:21:24 UTC (rev 15673)
@@ -21,59 +21,19 @@
package org.ajax4jsf.model;
-import java.io.Serializable;
/**
* @author shura
*
*/
-public class RepeatState implements DataComponentState,Serializable {
-
- /**
- *
- */
- private static final long serialVersionUID = -5552520123654180445L;
+public abstract class RepeatState implements DataComponentState {
- private int _rows = -1;
+ public abstract int getFirst();
- private int _first = 0;
+ public abstract int getRows();
-
- /**
- * @return the first
- */
- public int getFirst() {
- return _first;
- }
-
- /**
- * @param first the first to set
- */
- public void setFirst(int first) {
- this._first = first;
- }
-
- /**
- * @return the rows
- */
- public int getRows() {
- return _rows;
- }
-
- /**
- * @param rows the rows to set
- */
- public void setRows(int rows) {
- this._rows = rows;
- }
-
- /* (non-Javadoc)
- * @see org.ajax4jsf.ajax.repeat.DataComponentState#getRange()
- */
public Range getRange() {
- // TODO Auto-generated method stub
- return new SequenceRange(getFirst(),getRows());
+ return new SequenceRange(getFirst(), getRows());
}
-
}
Modified:
root/framework/trunk/api/src/main/java/org/ajax4jsf/model/SequenceDataModel.java
===================================================================
---
root/framework/trunk/api/src/main/java/org/ajax4jsf/model/SequenceDataModel.java 2009-09-25
16:50:56 UTC (rev 15672)
+++
root/framework/trunk/api/src/main/java/org/ajax4jsf/model/SequenceDataModel.java 2009-09-27
23:21:24 UTC (rev 15673)
@@ -21,8 +21,6 @@
package org.ajax4jsf.model;
-import java.io.IOException;
-
import javax.faces.context.FacesContext;
import javax.faces.model.DataModel;
@@ -80,7 +78,7 @@
};
}
*/
- public void walk(FacesContext context, DataVisitor visitor, Range range, Object
argument) throws IOException {
+ public void walk(FacesContext context, DataVisitor visitor, Range range, Object
argument) {
final SequenceRange seqRange = (SequenceRange) range;
int rows = seqRange.getRows();
int rowCount = wrappedModel.getRowCount();
@@ -95,10 +93,17 @@
} else {
rows = -1;
}
+
+ DataVisitResult visitResult = null;
+
while (rows < 0 || currentRow < rows) {
wrappedModel.setRowIndex(currentRow);
- if(wrappedModel.isRowAvailable()){
- visitor.process(context, new Integer(currentRow), argument);
+ if (wrappedModel.isRowAvailable()) {
+ visitResult = visitor.process(context, new Integer(currentRow), argument);
+
+ if (DataVisitResult.STOP.equals(visitResult)) {
+ break;
+ }
} else {
break;
}
Deleted:
root/framework/trunk/impl/src/main/java/org/ajax4jsf/component/RenderPhaseUIDataAdaptorVisitor.java
===================================================================
---
root/framework/trunk/impl/src/main/java/org/ajax4jsf/component/RenderPhaseUIDataAdaptorVisitor.java 2009-09-25
16:50:56 UTC (rev 15672)
+++
root/framework/trunk/impl/src/main/java/org/ajax4jsf/component/RenderPhaseUIDataAdaptorVisitor.java 2009-09-27
23:21:24 UTC (rev 15673)
@@ -1,37 +0,0 @@
-/**
- * License Agreement.
- *
- * Rich Faces - 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.component;
-
-import javax.faces.context.FacesContext;
-import javax.faces.event.AbortProcessingException;
-import javax.faces.event.SystemEvent;
-import javax.faces.event.SystemEventListener;
-
-public class RenderPhaseUIDataAdaptorVisitor implements SystemEventListener {
-
- public boolean isListenerForSource(Object source) {
- return source instanceof UIDataAdaptor;
- }
-
- public void processEvent(SystemEvent event) throws AbortProcessingException {
- ((UIDataAdaptor)
event.getSource()).beforeRenderResponse(FacesContext.getCurrentInstance());
- }
-}
Deleted:
root/framework/trunk/impl/src/main/java/org/ajax4jsf/component/SequenceDataAdaptor.java
===================================================================
---
root/framework/trunk/impl/src/main/java/org/ajax4jsf/component/SequenceDataAdaptor.java 2009-09-25
16:50:56 UTC (rev 15672)
+++
root/framework/trunk/impl/src/main/java/org/ajax4jsf/component/SequenceDataAdaptor.java 2009-09-27
23:21:24 UTC (rev 15673)
@@ -1,100 +0,0 @@
-/**
- * License Agreement.
- *
- * Rich Faces - 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.component;
-
-import java.sql.ResultSet;
-import java.util.Collections;
-import java.util.List;
-
-import javax.faces.model.ArrayDataModel;
-import javax.faces.model.DataModel;
-import javax.faces.model.ListDataModel;
-import javax.faces.model.ResultDataModel;
-import javax.faces.model.ResultSetDataModel;
-import javax.faces.model.ScalarDataModel;
-import javax.servlet.jsp.jstl.sql.Result;
-
-import org.ajax4jsf.model.DataComponentState;
-import org.ajax4jsf.model.ExtendedDataModel;
-import org.ajax4jsf.model.Range;
-import org.ajax4jsf.model.SequenceDataModel;
-import org.ajax4jsf.model.SequenceRange;
-
-/**
- * @author asmirnov
- *
- */
-public abstract class SequenceDataAdaptor extends UIDataAdaptor {
-
- protected DataComponentState createComponentState() {
- // Create component state based on this instance.
- return new DataComponentState(){
-
- public Range getRange() {
- return new SequenceRange(getFirst(),getRows());
- }
- };
-
- }
-
- protected ExtendedDataModel createDataModel() {
- return (ExtendedDataModel) getDataModel();
- }
-
- protected DataModel getDataModel() {
- // Synthesize a DataModel around our current value if possible
- // TODO - for jsf 1.2 use method from superclass ?
- Object current = getValue();
- DataModel model;
- if (current == null) {
- model = new SequenceDataModel(new ListDataModel(Collections.EMPTY_LIST));
- } else if (current instanceof ExtendedDataModel) {
- model = (DataModel) current;
- } else if (current instanceof DataModel) {
- model = new SequenceDataModel((DataModel) current);
- } else if (current instanceof List) {
- model = new SequenceDataModel(new ListDataModel((List<?>) current));
- } else if (Object[].class.isAssignableFrom(current.getClass())) {
- model = new SequenceDataModel(new ArrayDataModel((Object[]) current));
- } else if (current instanceof ResultSet) {
- model = new SequenceDataModel(new ResultSetDataModel((ResultSet) current));
- } else if (current instanceof Result) {
- model = new SequenceDataModel(new ResultDataModel((Result) current));
- } else {
- model = new SequenceDataModel(new ScalarDataModel(current));
- }
- return (model);
- }
-
- protected void setDataModel(DataModel model) {
- ExtendedDataModel iterableModel;
- if( null == model){
- iterableModel = null;
- } else if (model instanceof ExtendedDataModel) {
- iterableModel = (ExtendedDataModel) model;
- } else {
- iterableModel = new SequenceDataModel(model);
- }
- setExtendedDataModel(iterableModel);
- }
-
-
-}
Deleted:
root/framework/trunk/impl/src/main/java/org/ajax4jsf/component/UIDataAdaptor.java
===================================================================
---
root/framework/trunk/impl/src/main/java/org/ajax4jsf/component/UIDataAdaptor.java 2009-09-25
16:50:56 UTC (rev 15672)
+++
root/framework/trunk/impl/src/main/java/org/ajax4jsf/component/UIDataAdaptor.java 2009-09-27
23:21:24 UTC (rev 15673)
@@ -1,1639 +0,0 @@
-/**
- * License Agreement.
- *
- * Rich Faces - 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.component;
-
-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 java.util.Map.Entry;
-
-import javax.el.ELContext;
-import javax.el.ValueExpression;
-import javax.faces.FacesException;
-import javax.faces.application.FacesMessage;
-import javax.faces.component.ContextCallback;
-import javax.faces.component.EditableValueHolder;
-import javax.faces.component.NamingContainer;
-import javax.faces.component.StateHolder;
-import javax.faces.component.UIColumn;
-import javax.faces.component.UIComponent;
-import javax.faces.component.UIData;
-import javax.faces.context.FacesContext;
-import javax.faces.convert.Converter;
-import javax.faces.convert.ConverterException;
-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.model.DataComponentState;
-import org.ajax4jsf.model.DataVisitor;
-import org.ajax4jsf.model.ExtendedDataModel;
-import org.ajax4jsf.model.SerializableDataModel;
-import org.ajax4jsf.renderkit.AjaxChildrenRenderer;
-import org.richfaces.log.RichfacesLogger;
-import org.slf4j.Logger;
-
-/**
- * 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);
-
- private static final Logger _log = RichfacesLogger.COMPONENTS.getLogger();
-
- /**
- * 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<UIComponent> childIterator = dataChildren();
- while (childIterator.hasNext()) {
- UIComponent component = childIterator.next();
- if (UIColumn.class.equals(component.getClass())) {
- for (UIComponent children : component.getChildren()) {
- processComponent(context, children, argument);
- }
- } else {
- 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<String> _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<String, ExtendedDataModel> _modelsMap = new HashMap<String,
ExtendedDataModel>();
-
- /**
- * Reference for curent data model
- */
- private ExtendedDataModel _currentModel = null;
-
- /**
- * States of this component for diferent iterations, same as for models.
- */
- private Map<String, DataComponentState> _statesMap = new HashMap<String,
DataComponentState>();
-
- /**
- * 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;
-
-
- private Converter _rowKeyConverter = null;
-
- /**
- * Values of row keys, encoded on ajax response rendering.
- */
- private Set<Object> _ajaxKeys = null;
-
- /**
- * Internal set of row keys, encoded on ajax response rendering and cleared after
response complete
- */
- private Set<Object> _ajaxRequestKeys = null;
-
- private Object _ajaxRowKey = null;
-
- private Map<String, Object> _ajaxRowKeysMap = new HashMap<String,
Object>();
-
- /**
- * 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();
-
- boolean rowAvailable = isRowAvailable();
-
-
-// if (rowAvailable) {
- // 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);
-
- rowAvailable = isRowAvailable();
- this._rowKey = localModel.getRowKey();
- this._clientId = null;
-
- boolean rowSelected = this._rowKey != null && rowAvailable;
-
- setupVariable(faces, localModel, rowSelected);
-
-// if (rowAvailable ) {
- // 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 row 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();
-
- boolean rowAvailable = isRowAvailable();
-
-// if (rowAvailable) {
- // save child state
- this.saveChildState(faces);
-// }
-
- this._rowKey = key;
- this._clientId = null;
-
- localModel.setRowKey(key);
-
- rowAvailable = isRowAvailable();
- boolean rowSelected = key != null && rowAvailable;
-
- //XXX check for row availability
- setupVariable(faces, localModel, rowSelected);
-
-// if (rowAvailable ) {
- // restore child state
- this.restoreChildState(faces);
-// }
- }
-
- /**
- * @return the rowKeyConverter
- */
- public Converter getRowKeyConverter() {
- Converter converter = _rowKeyConverter;
- if (null == converter) {
- ValueExpression ve = getValueExpression("rowKeyConverter");
- if (null != ve) {
- converter = (Converter) ve.getValue(getFacesContext().getELContext());
- }
- }
- return converter;
- }
-
- /**
- * @param rowKeyConverter the rowKeyConverter to set
- */
- public void setRowKeyConverter(Converter rowKeyConverter) {
- _rowKeyConverter = rowKeyConverter;
- }
-
- /*
- * (non-Javadoc)
- *
- * @see org.ajax4jsf.ajax.repeat.AjaxDataEncoder#getAjaxKeys()
- */
- @SuppressWarnings("unchecked")
- public Set<Object> getAjaxKeys() {
- Set<Object> keys = null;
- if (this._ajaxKeys != null) {
- keys = (this._ajaxKeys);
- } else {
- ValueExpression vb = getValueExpression("ajaxKeys");
- if (vb != null) {
- keys = (Set<Object>) (vb.getValue(getFacesContext().getELContext()));
- } else if (null != _ajaxRowKey) {
- // If none of above exist , use row with submitted AjaxComponent
- keys = new HashSet<Object>(1);
- keys.add(_ajaxRowKey);
- }
- }
- return keys;
- }
-
- public Set<Object> getAllAjaxKeys() {
- Set<Object> ajaxKeys = getAjaxKeys();
-
- Set<Object> allAjaxKeys = null;
- if (ajaxKeys != null) {
- allAjaxKeys = new HashSet<Object>();
- allAjaxKeys.addAll(ajaxKeys);
- }
-
- if (_ajaxRequestKeys != null) {
- if (allAjaxKeys == null) {
- allAjaxKeys = new HashSet<Object>();
- }
-
- allAjaxKeys.addAll(_ajaxRequestKeys);
- }
-
- return allAjaxKeys;
- }
-
- /*
- * (non-Javadoc)
- *
- * @see org.ajax4jsf.ajax.repeat.AjaxDataEncoder#setAjaxKeys(java.util.Set)
- */
- public void setAjaxKeys(Set<Object> 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<String> ids, final Set<String> renderedAreas) throws IOException
{
-
- Renderer renderer = getRenderer(context);
- if (null != renderer && renderer instanceof AjaxChildrenRenderer) {
- // If renderer support partial encoding - call them.
- if(_log.isDebugEnabled()){
- _log.debug("Component "+getClientId(context)+" has delegated Encode
children components by AjaxChildrenRenderer for path "+path);
- }
- AjaxChildrenRenderer childrenRenderer = (AjaxChildrenRenderer) renderer;
- childrenRenderer.encodeAjaxChildren(context, this, path, ids,
- renderedAreas);
- } else {
- if(_log.isDebugEnabled()){
- _log.debug("Component "+getClientId(context)+" do Encode children
components for path "+path);
- }
- // 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<Object> ajaxKeys = getAllAjaxKeys();
- if (null != ajaxKeys) {
- if(_log.isDebugEnabled()){
- _log.debug("Component "+getClientId(context)+" Encode children
components for a keys "+ajaxKeys);
- }
- captureOrigValue();
- Object savedKey = getRowKey();
- setRowKey(context, null);
- Iterator<UIComponent> fixedChildren = fixedChildren();
- while (fixedChildren.hasNext()) {
- UIComponent component = fixedChildren.next();
- ajaxVisitor.processComponent(context, component, null);
- }
- for (Iterator<Object> iter = ajaxKeys.iterator(); iter.hasNext();) {
- Object key = iter.next();
- ajaxVisitor.process(context, key, null);
- }
- setRowKey(context,savedKey);
- restoreOrigValue(context);
- } else {
- if(_log.isDebugEnabled()){
- _log.debug("Component "+getClientId(context)+" children components
for all rows");
- }
- iterate(context, ajaxVisitor, null);
- }
- }
- }
-
- /**
- * Instance of default renderer in ajax responses.
- */
- private static final AjaxChildrenRenderer _childrenRenderer = new AjaxChildrenRenderer()
{
-
- protected Class<? extends UIComponent> getComponentClass() {
- return UIDataAdaptor.class;
- }
-
- };
-
- /**
- * 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() {
- return _childrenRenderer;
- }
-
- /**
- * @return Set of values for clientId's of this component, for wich was
- * invoked "encode" methods.
- */
- protected Set<String> getEncodedIds() {
- if (_encoded == null) {
- _encoded = new HashSet<String>();
- }
-
- 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.
- *
- * Changed: does not check for row availability now
- *
- * @param faces
- * current faces context
- * @param localModel
- * @param rowSelected
- */
- protected void setupVariable(FacesContext faces, DataModel localModel,
- boolean rowSelected) {
- Map<String, Object> 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<String, Object> attrs, Object rowData)
{
- if (var != null) {
- attrs.put(var, rowData);
- }
- }
-
- /**
- * @param var
- * @param attrs
- * @param rowData
- */
- private void removeVariable(String var, Map<String, Object> 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._currentModel = null;
- _modelsMap.clear();
- }
-
- /**
- * 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;
- 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.
- ValueExpression valueBinding =
getValueExpression(UIDataAdaptor.COMPONENT_STATE_ATTRIBUTE);
- FacesContext facesContext = getFacesContext();
- ELContext elContext = facesContext.getELContext();
- if (null != valueBinding) {
- state = (DataComponentState) valueBinding
- .getValue(elContext);
- if (null == state) {
- // Create default state
- state = createComponentState();
- if (!valueBinding.isReadOnly(elContext)) {
- // Store created state in user bean.
- valueBinding.setValue(elContext, 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) {
- StringBuilder id = new StringBuilder(getBaseClientId(faces));
- Object rowKey = getRowKey();
- if (rowKey != null) {
- // Use converter to get String representation ot the row key.
- Converter rowKeyConverter = getRowKeyConverter();
- if(null == rowKeyConverter){
- // Create default converter for a row key.
- rowKeyConverter = faces.getApplication().createConverter(rowKey.getClass());
- // Store converter for a invokeOnComponents call.
- if(null != rowKeyConverter){
- setRowKeyConverter(rowKeyConverter);
- }
- }
- String rowKeyString;
- if (null !=rowKeyConverter) {
- // Temporary set clientId, to avoid infinite calls from converter.
- _clientId = id.toString();
- rowKeyString = rowKeyConverter.getAsString(faces, this, rowKey);
- } else {
- rowKeyString = rowKey.toString();
- }
- id.append(NamingContainer.SEPARATOR_CHAR).append(
- rowKeyString);
- }
- 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;
- StringBuilder parentIds = new StringBuilder();
- while (null != (ancestorContainer = ancestorContainer.getParent())) {
- if (ancestorContainer instanceof NamingContainer) {
- String containerClientId = ancestorContainer.getContainerClientId(faces);
- // skip case when clientId of ancestor container is null
- if(containerClientId != null) {
- parentIds.append(containerClientId).append(NamingContainer.SEPARATOR_CHAR);
- }
- break;
- }
- }
- String id = getId();
- if (null != id) {
- _baseClientId = parentIds.append(id).toString();
- } else {
- id = faces.getViewRoot().createUniqueId();
- super.setId(id);
- _baseClientId = parentIds.append(
- getId()).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();
- String baseClientId;
-// baseClientId = haveId ? getBaseClientId(getFacesContext())
-// : null;
- 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.
- // Step one - save old values.
-// this._statesMap.put(baseClientId, this._currentState);
-// this._modelsMap.put(baseClientId, this._currentModel);
-// this._ajaxRowKeysMap.put(baseClientId, this._ajaxRowKey);
- // Step two - restore values for a new clientId.
- 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<String, Object> 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<String, Object> 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<String, Map<String, SavedState>> childState;
-
- /**
- * @param faces
- * @return Saved values of {@link EditableValueHolder} fields per
- * iterations.
- */
- protected Map<String, SavedState> getChildState(FacesContext faces) {
- if (this.childState == null) {
- this.childState = new HashMap<String, Map<String,SavedState>>();
- }
- String baseClientId = getBaseClientId(faces);
- Map<String, SavedState> currentChildState = childState.get(baseClientId);
- if (null == currentChildState) {
- currentChildState = new HashMap<String, SavedState>();
- childState.put(baseClientId, currentChildState);
- }
- return currentChildState;
- }
-
- /**
- * Save values of {@link EditableValueHolder} fields before change current
- * row.
- *
- * @param faces
- */
- protected void saveChildState(FacesContext faces) {
-
- Iterator<UIComponent> itr = dataChildren();
- Map<String, SavedState> childState = this.getChildState(faces);
- while (itr.hasNext()) {
- 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<String, SavedState> childState) {
-
- if (!c.isTransient() && (c instanceof EditableValueHolder||c instanceof
IterationStateHolder)) {
- String clientId = c.getClientId(faces);
- SavedState ss = childState.get(clientId);
- if (ss == null) {
- ss = new SavedState();
- childState.put(clientId, ss);
- }
- if (c instanceof EditableValueHolder) {
- ss.populate((EditableValueHolder) c);
- }
- if(c instanceof IterationStateHolder){
- ss.populate((IterationStateHolder) c);
- }
- }
- // continue hack
- Iterator<UIComponent> 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<UIComponent> itr = dataChildren();
- Map<String, SavedState> childState = this.getChildState(faces);
- while (itr.hasNext()) {
- 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<String, SavedState> childState) {
- // reset id
- String id = c.getId();
- c.setId(id);
-
- // hack
- if (c instanceof EditableValueHolder || c instanceof IterationStateHolder) {
- String clientId = c.getClientId(faces);
- SavedState ss = childState.get(clientId);
- if (ss == null) {
- ss=NullState;
- }
- if (c instanceof EditableValueHolder) {
- EditableValueHolder evh = (EditableValueHolder) c;
- ss.apply(evh);
- }
- if (c instanceof IterationStateHolder) {
- IterationStateHolder ish = (IterationStateHolder) c;
- ss.apply(ish);
- }
- }
-
- // continue hack
- for (UIComponent child : c.getChildren()) {
- restoreChildState(faces, child, childState);
- }
- for (UIComponent facet : c.getFacets().values()) {
- restoreChildState(faces, facet, childState);
- }
- }
-
- /**
- * Check for validation errors on children components. If true, saved values
- * must be keep on render phase
- *
- * @param context
- * @return
- */
- protected boolean keepSaved(FacesContext context) {
- // For an any validation errors, children components state should be preserved
- FacesMessage.Severity sev = context.getMaximumSeverity();
- return (sev != null && (FacesMessage.SEVERITY_ERROR.compareTo(sev) >= 0));
- }
-
- /**
- * 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<UIComponent> fixedChildren = fixedChildren();
- while (fixedChildren.hasNext()) {
- UIComponent component = 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);
- }
- }
-
- /**
- * Extracts segment of component client identifier containing row key
- *
- * @param context current faces context
- * @param tailId substring of component client identifier with base client identifier
removed
- * @return segment containing row key or <code>null</code>
- */
- protected String extractKeySegment(FacesContext context, String tailId) {
- int indexOfSecondColon = tailId.indexOf(NamingContainer.SEPARATOR_CHAR);
-
- return (indexOfSecondColon > 0 ? tailId.substring(0, indexOfSecondColon) : null);
- }
-
- /**
- * Returns iterator of components to search through
- * in {@link #invokeOnComponent(FacesContext, String, ContextCallback)}.
- *
- * @return
- */
- protected Iterator<UIComponent> invocableChildren() {
- return getFacetsAndChildren();
- }
-
- @Override
- public boolean invokeOnComponent(FacesContext context, String clientId,
- ContextCallback callback) throws FacesException {
- if( null == context || null == clientId || null == callback){
- throw new NullPointerException();
- }
- boolean found = false;
- Object oldRowKey = getRowKey();
- String baseClientId = getBaseClientId(context);
- if (clientId.equals(baseClientId)) {
- // This is call for a same data component.
- try {
- if (null != oldRowKey) {
- captureOrigValue(context);
- setRowKey(context,null);
- }
- callback.invokeContextCallback(context, this);
- found = true;
- } catch (Exception e) {
- throw new FacesException(e);
- } finally {
- if (null != oldRowKey) {
- try {
- setRowKey(context,oldRowKey);
- restoreOrigValue(context);
- } catch (Exception e) {
- context.getExternalContext().log(e.getMessage(), e);
- }
- }
- }
- } else {
- String baseId = baseClientId + NamingContainer.SEPARATOR_CHAR;
- if (clientId.startsWith(baseId)) {
- Object newRowKey = null;
- // Call for a child component - try to detect row key
- String rowKeyString = extractKeySegment(context,
- clientId.substring(baseId.length()));
- if (rowKeyString != null) {
- Converter keyConverter = getRowKeyConverter();
- if (null != keyConverter) {
- try {
- newRowKey = keyConverter.getAsObject(context, this,
- rowKeyString);
- } catch (ConverterException e) {
- // TODO: log error
- }
- }
- }
- if( null != oldRowKey || null != newRowKey){
- captureOrigValue(context);
- setRowKey(newRowKey);
- }
- Iterator<UIComponent> itr = invocableChildren();
- while (itr.hasNext() && !found) {
- found = itr.next().invokeOnComponent(context, clientId,
- callback);
- }
- if( null != oldRowKey || null != newRowKey){
- setRowKey(oldRowKey);
- restoreOrigValue(context);
- }
- }
- }
-
- return found;
- }
-
- /**
- * 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.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);
- // resetComponent(faces);
- }
-
- 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 {
- // 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<UIComponent> 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<UIComponent> 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 Object iterationState;
-
- 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 Object getIterationState() {
- return iterationState;
- }
-
- public void setIterationState(Object iterationState) {
- this.iterationState = iterationState;
- }
-
- 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 populate(IterationStateHolder ish) {
- this.iterationState = ish.getIterationState();
- }
-
- public void apply(EditableValueHolder evh) {
- evh.setValue(this.value);
- evh.setValid(this.valid);
- evh.setSubmittedValue(this.submittedValue);
- evh.setLocalValueSet(this.localValueSet);
- }
-
- public void apply(IterationStateHolder ish) {
- ish.setIterationState(this.iterationState);
- }
-
- }
-
- protected void addAjaxKeyEvent(FacesEvent event) {
- Object eventRowKey = getRowKey();
- if (null != eventRowKey) {
- this._ajaxRowKey = eventRowKey;
- this._ajaxRowKeysMap.put(getBaseClientId(getFacesContext()),
- eventRowKey);
- }
- }
-
- /*
- * (non-Javadoc)
- *
- * @see javax.faces.component.UIData#queueEvent(javax.faces.event.FacesEvent)
- */
- public void queueEvent(FacesEvent event) {
- if (event.getComponent() != this) {
- // For Ajax events, keep row value.
- if (event.getPhaseId() == PhaseId.RENDER_RESPONSE) {
- addAjaxKeyEvent(event);
- }
- 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);
-
- setRowKey(faces, oldRowKey);
- restoreOrigValue(faces);
- }
-
- /**
- * 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<String, PerIdState> componentStates = new HashMap<String,
PerIdState>();
-
- private Set<Object> ajaxKeys;
-
- public String rowKeyVar;
-
- public String stateVar;
-
- private Map<String, Map<String, SavedState>> childStates;
-
- public Object rowKeyConverter;
-
- }
-
- /**
- * 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<String, DataComponentState>();
- this._rowKeyVar = state.rowKeyVar;
- this._stateVar = state.stateVar;
- this.childState = state.childStates;
- if (null != state.rowKeyConverter) {
- this._rowKeyConverter = (Converter) restoreAttachedState(faces,
- state.rowKeyConverter);
- }
- // Restore serializable models and component states for all rows of
- // parent UIData ( single if this
- // component not child of iterable )
- for (Iterator<Entry<String, PerIdState>> iter =
state.componentStates.entrySet().iterator(); iter
- .hasNext();) {
- Entry<String, PerIdState> stateEntry = iter.next();
- PerIdState idState = 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;
- }
- String 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;
- state.childStates = this.childState;
- if (null != this._rowKeyConverter) {
- state.rowKeyConverter = saveAttachedState(faces,this._rowKeyConverter);
- }
- Set<String> encodedIds = getEncodedIds();
- // Save all states of component and data model for all valies of
- // clientId, encoded in this request.
-// this._statesMap.put(getBaseClientId(faces), this._currentState);
-// this._modelsMap.put(getBaseClientId(faces), this._currentModel);
- for (Iterator<Entry<String, DataComponentState>> iter =
this._statesMap.entrySet().iterator(); iter
- .hasNext();) {
- Entry<String, DataComponentState> stateEntry = iter.next();
- DataComponentState dataComponentState = stateEntry.getValue();
- String stateKey = stateEntry.getKey();
- if (encodedIds.isEmpty() || encodedIds.contains(stateKey)) {
- PerIdState idState = new PerIdState();
- // 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) {
- idState.componentState = ((StateHolder) dataComponentState)
- .saveState(faces);
- idState.stateInHolder = true;
- }
- ExtendedDataModel extendedDataModel = (ExtendedDataModel) this._modelsMap
- .get(stateKey);
- if (null != extendedDataModel) {
- idState.model = extendedDataModel
- .getSerializableModel(dataComponentState
- .getRange());
-
- }
- }
- 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;
- }
-
- /**
- * Adds argument key to AJAX internal request keys set
- * @param key key to add
- */
- public void addRequestKey(Object key) {
- if (_ajaxRequestKeys == null) {
- _ajaxRequestKeys = new HashSet<Object>();
- }
-
- _ajaxRequestKeys.add(key);
- }
-
- /**
- * Removes argument key from AJAX internal request keys set
- * @param key key to remove
- */
- public void removeRequestKey(Object key) {
- if (_ajaxRequestKeys != null && key != null) {
- _ajaxRequestKeys.remove(key);
- }
- }
-
- /**
- * Checks whether AJAX internal request keys set contains argument key
- * @param key key to check
- * @return <code>true</code> if set contains key,
<code>false</code> - otherwise
- */
- public boolean containsRequestKey(Object key) {
- if (_ajaxRequestKeys != null && key != null) {
- return _ajaxRequestKeys.contains(key);
- }
-
- return false;
- }
-
- /**
- * Clears AJAX internal request keys set
- */
- public void clearRequestKeysSet() {
- _ajaxRequestKeys = null;
- }
-
- public Object getValue() {
- return super.getValue();
- }
-
- public void setValue(Object value) {
- setExtendedDataModel(null);
- super.setValue(value);
- }
-
- public void beforeRenderResponse(FacesContext context) {
- resetDataModel();
- this._encoded = null;
- if (null != childState && !keepSaved(context)) {
- childState.clear();
- }
- }
-}
Modified:
root/framework/trunk/impl/src/main/java/org/ajax4jsf/webapp/taglib/RowKeyConverterRule.java
===================================================================
---
root/framework/trunk/impl/src/main/java/org/ajax4jsf/webapp/taglib/RowKeyConverterRule.java 2009-09-25
16:50:56 UTC (rev 15672)
+++
root/framework/trunk/impl/src/main/java/org/ajax4jsf/webapp/taglib/RowKeyConverterRule.java 2009-09-27
23:21:24 UTC (rev 15673)
@@ -27,7 +27,7 @@
import javax.faces.view.facelets.MetadataTarget;
import javax.faces.view.facelets.TagAttribute;
-import org.ajax4jsf.component.UIDataAdaptor;
+import org.richfaces.component.UIDataAdaptor;
/**
* Apply rowKeyConverter to component
Added:
root/framework/trunk/impl/src/main/java/org/richfaces/component/RowKeyContextEventWrapper.java
===================================================================
---
root/framework/trunk/impl/src/main/java/org/richfaces/component/RowKeyContextEventWrapper.java
(rev 0)
+++
root/framework/trunk/impl/src/main/java/org/richfaces/component/RowKeyContextEventWrapper.java 2009-09-27
23:21:24 UTC (rev 15673)
@@ -0,0 +1,79 @@
+/*
+ * 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 javax.faces.component.UIComponent;
+import javax.faces.event.FacesEvent;
+import javax.faces.event.FacesListener;
+import javax.faces.event.PhaseId;
+
+/**
+ * @author Nick Belaevski
+ *
+ */
+class RowKeyContextEventWrapper extends FacesEvent {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = -869970815228914529L;
+
+ private FacesEvent event;
+
+ private Object rowKey;
+
+ public RowKeyContextEventWrapper(UIComponent component, FacesEvent event, Object
rowKey) {
+ super(component);
+
+ this.event = event;
+ this.rowKey = rowKey;
+ }
+
+ public FacesEvent getFacesEvent() {
+ return this.event;
+ }
+
+ public PhaseId getPhaseId() {
+ return this.event.getPhaseId();
+ }
+
+ public void setPhaseId(PhaseId phaseId) {
+ this.event.setPhaseId(phaseId);
+ }
+
+ public boolean isAppropriateListener(FacesListener listener) {
+ return false;
+ }
+
+ public void processListener(FacesListener listener) {
+ throw new IllegalStateException();
+ }
+
+ /**
+ * @return the rowKey
+ */
+ public Object getRowKey() {
+ return rowKey;
+ }
+
+}
Added: root/framework/trunk/impl/src/main/java/org/richfaces/component/SavedState.java
===================================================================
--- root/framework/trunk/impl/src/main/java/org/richfaces/component/SavedState.java
(rev 0)
+++
root/framework/trunk/impl/src/main/java/org/richfaces/component/SavedState.java 2009-09-27
23:21:24 UTC (rev 15673)
@@ -0,0 +1,146 @@
+/*
+ * 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 java.io.Serializable;
+
+import javax.faces.component.EditableValueHolder;
+import javax.faces.component.UIForm;
+
+import org.ajax4jsf.component.IterationStateHolder;
+
+// from RI
+/**
+ * This class keep values of {@link EditableValueHolder} row-sensitive
+ * fields.
+ *
+ * @author shura
+ *
+ */
+final class SavedState implements Serializable {
+
+ private Object submittedValue;
+
+ private Object iterationState;
+
+ private Object value;
+
+ private boolean localValueSet;
+
+ private boolean submitted;
+
+ private static final long serialVersionUID = 2920252657338389849L;
+
+ public static final SavedState EMPTY = new SavedState();
+
+ public SavedState() {
+ super();
+ }
+
+ public SavedState(EditableValueHolder evh) {
+ super();
+
+ this.value = evh.getLocalValue();
+ this.valid = evh.isValid();
+ this.submittedValue = evh.getSubmittedValue();
+ this.localValueSet = evh.isLocalValueSet();
+ }
+
+ public SavedState(IterationStateHolder ish) {
+ super();
+
+ this.iterationState = ish.getIterationState();
+ }
+
+ public SavedState(UIForm form) {
+ super();
+
+ this.submitted = form.isSubmitted();
+ }
+
+ 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;
+ }
+
+ Object getValue() {
+ return (this.value);
+ }
+
+ public void setValue(Object value) {
+ this.value = value;
+ }
+
+ boolean isLocalValueSet() {
+ return (this.localValueSet);
+ }
+
+ public void setLocalValueSet(boolean localValueSet) {
+ this.localValueSet = localValueSet;
+ }
+
+ public Object getIterationState() {
+ return iterationState;
+ }
+
+ public void setIterationState(Object iterationState) {
+ this.iterationState = iterationState;
+ }
+
+ public String toString() {
+ if (iterationState != null) {
+ return "iterationState: " + iterationState;
+ } else {
+ return "submittedValue: " + submittedValue + " value: " + value
+ + " localValueSet: " + localValueSet + " submitted: " +
submitted;
+ }
+ }
+
+ public void apply(EditableValueHolder evh) {
+ evh.setValue(this.value);
+ evh.setValid(this.valid);
+ evh.setSubmittedValue(this.submittedValue);
+ evh.setLocalValueSet(this.localValueSet);
+ }
+
+ public void apply(IterationStateHolder ish) {
+ ish.setIterationState(this.iterationState);
+ }
+
+ public void apply(UIForm form) {
+ form.setSubmitted(this.submitted);
+ }
+}
Added: root/framework/trunk/impl/src/main/java/org/richfaces/component/UIDataAdaptor.java
===================================================================
--- root/framework/trunk/impl/src/main/java/org/richfaces/component/UIDataAdaptor.java
(rev 0)
+++
root/framework/trunk/impl/src/main/java/org/richfaces/component/UIDataAdaptor.java 2009-09-27
23:21:24 UTC (rev 15673)
@@ -0,0 +1,1183 @@
+/*
+ * 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 java.io.IOException;
+import java.io.Serializable;
+import java.text.MessageFormat;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+import javax.el.ValueExpression;
+import javax.faces.FacesException;
+import javax.faces.application.FacesMessage;
+import javax.faces.component.ContextCallback;
+import javax.faces.component.EditableValueHolder;
+import javax.faces.component.NamingContainer;
+import javax.faces.component.StateHelper;
+import javax.faces.component.StateHolder;
+import javax.faces.component.UIComponent;
+import javax.faces.component.UIComponentBase;
+import javax.faces.component.UIData;
+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.ActionEvent;
+import javax.faces.event.BehaviorEvent;
+import javax.faces.event.FacesEvent;
+import javax.faces.render.Renderer;
+
+import org.ajax4jsf.component.AjaxDataEncoder;
+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.ajax4jsf.model.SerializableDataModel;
+import org.richfaces.log.RichfacesLogger;
+import org.slf4j.Logger;
+
+/**
+ * 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
+ *
+ */
+//TODO check AjaxDataEncoder
+public abstract class UIDataAdaptor extends UIComponentBase implements AjaxDataEncoder,
NamingContainer,
+ UniqueIdVendor, IterationStateHolder {
+
+
+ /**
+ * <p>The standard component type for this component.</p>
+ */
+ public static final String COMPONENT_TYPE = "org.richfaces.Data";
+
+ /**
+ * <p>The standard component family for this component.</p>
+ */
+ public static final String COMPONENT_FAMILY = "org.richfaces.Data";
+
+ private static final Logger log = RichfacesLogger.COMPONENTS.getLogger();
+
+ private enum PropertyKeys {
+ ajaxKeys, lastId, var, rowKeyVar, stateVar, childState, rowKeyConverter
+ }
+
+ private Object rowKey = null;
+
+ private Object ajaxRowKey = null;
+
+ private DataComponentState componentState = null;
+
+ private ExtendedDataModel<?> extendedDataModel = null;
+
+ private Object originalVarValue;
+
+ private String clientId;
+
+ /**
+ *
+ */
+ public UIDataAdaptor() {
+ super();
+ }
+
+ /* (non-Javadoc)
+ * @see javax.faces.component.UIComponent#getFamily()
+ */
+ @Override
+ public String getFamily() {
+ return COMPONENT_FAMILY;
+ }
+
+ /* (non-Javadoc)
+ * @see org.ajax4jsf.component.AjaxDataEncoder#getAjaxKeys()
+ */
+ @SuppressWarnings("unchecked")
+ public Set<Object> getAjaxKeys() {
+ Set<Object> defaultAjaxKeys = null;
+ if (ajaxRowKey != null) {
+ //cannot use Collections.singleton() because ajaxKeys set should be modifiable
+ defaultAjaxKeys = new HashSet<Object>(1);
+ defaultAjaxKeys.add(ajaxRowKey);
+ }
+
+ return (Set<Object>) getStateHelper().eval(PropertyKeys.ajaxKeys,
+ defaultAjaxKeys);
+ }
+
+ /* (non-Javadoc)
+ * @see org.ajax4jsf.component.AjaxDataEncoder#setAjaxKeys(java.util.Set)
+ */
+ public void setAjaxKeys(Set<Object> ajaxKeys) {
+ getStateHelper().put(PropertyKeys.ajaxKeys, ajaxKeys);
+ }
+
+ /* (non-Javadoc)
+ * @see
org.ajax4jsf.component.AjaxChildrenEncoder#encodeAjaxChild(javax.faces.context.FacesContext,
java.lang.String, java.util.Set, java.util.Set)
+ */
+ public void encodeAjaxChild(FacesContext context, String path,
+ Set<String> ids, Set<String> renderedAreas) throws IOException {
+ // TODO Auto-generated method stub
+
+ }
+
+ /* (non-Javadoc)
+ * @see
javax.faces.component.UniqueIdVendor#createUniqueId(javax.faces.context.FacesContext,
java.lang.String)
+ */
+ public String createUniqueId(FacesContext context, String seed) {
+ Integer i = (Integer) getStateHelper().get(PropertyKeys.lastId);
+ int lastId = ((i != null) ? i : 0);
+ getStateHelper().put(PropertyKeys.lastId, ++lastId);
+ return UIViewRoot.UNIQUE_ID_PREFIX + (seed == null ? lastId : seed);
+ }
+
+ /**
+ * @return the rowKey
+ */
+ public Object getRowKey() {
+ return rowKey;
+ }
+
+ /**
+ * Setup current row 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 facesContext, Object rowKey) {
+ this.saveChildState(facesContext);
+
+ this.rowKey = rowKey;
+ this.clientId = null;
+
+ getExtendedDataModel().setRowKey(rowKey);
+
+ boolean rowSelected = (rowKey != null) && isRowAvailable();
+ setupVariable(facesContext, rowSelected);
+
+ this.restoreChildState(facesContext);
+ }
+
+ /**
+ * Save values of {@link EditableValueHolder} fields before change current
+ * row.
+ *
+ * @param faces
+ */
+ protected void saveChildState(FacesContext facesContext) {
+ Iterator<UIComponent> itr = dataChildren();
+ while (itr.hasNext()) {
+ this.saveChildState(facesContext, (UIComponent) itr.next());
+ }
+ }
+
+ /**
+ * @param facesContext
+ * @param next
+ * @param childState
+ */
+ 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(PropertyKeys.childState,
+ component.getClientId(facesContext), state);
+ }
+
+ if (component.getChildCount() > 0) {
+ for (UIComponent child: component.getChildren()) {
+ saveChildState(facesContext, child);
+ }
+ }
+
+ if (component.getFacetCount() > 0) {
+ for (UIComponent facet: component.getFacets().values()) {
+ saveChildState(facesContext, facet);
+ }
+ }
+ }
+
+ 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();
+ }
+ }
+
+ /**
+ * @param facesContext
+ */
+ protected void restoreChildState(FacesContext facesContext) {
+ Iterator<UIComponent> itr = dataChildren();
+ while (itr.hasNext()) {
+ this.restoreChildState(facesContext, (UIComponent) itr.next());
+ }
+ }
+
+ /**
+ * Restore values of {@link EditableValueHolder} fields after change current
+ * row.
+ * @param facesContext
+ * @param next
+ * @param childState
+ */
+ 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<String, SavedState> savedStatesMap =
+ (Map<String, SavedState>)
getStateHelper().get(PropertyKeys.childState);
+
+ if (savedStatesMap != null) {
+ savedState = savedStatesMap.get(component.getClientId(facesContext));
+ }
+
+ if (savedState == null) {
+ savedState = SavedState.EMPTY;
+ }
+
+
+ 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(facesContext, child);
+ }
+ }
+
+ if (component.getFacetCount() > 0) {
+ for (UIComponent facet: component.getFacets().values()) {
+ restoreChildState(facesContext, facet);
+ }
+ }
+ }
+
+ public void setRowKey(Object rowKey) {
+ setRowKey(getFacesContext(), rowKey);
+ }
+
+ protected boolean isAjaxKeyEvent(FacesEvent event) {
+ return (event instanceof ActionEvent) || (event instanceof BehaviorEvent);
+ }
+
+ protected void addAjaxKeyEvent(FacesEvent event) {
+ Object eventRowKey = getRowKey();
+ if (null != eventRowKey) {
+ this.ajaxRowKey = eventRowKey;
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see javax.faces.component.UIComponentBase#queueEvent(javax.faces.event.FacesEvent)
+ */
+ @Override
+ public void queueEvent(FacesEvent event) {
+ if (isAjaxKeyEvent(event)) {
+ addAjaxKeyEvent(event);
+ }
+
+ super.queueEvent(new RowKeyContextEventWrapper(this, event, getRowKey()));
+ }
+
+ /* (non-Javadoc)
+ * @see javax.faces.component.UIComponentBase#broadcast(javax.faces.event.FacesEvent)
+ */
+ @Override
+ public void broadcast(FacesEvent event) throws AbortProcessingException {
+ if (!(event instanceof RowKeyContextEventWrapper)) {
+ if (!broadcastLocal(event)) {
+ super.broadcast(event);
+ }
+ return;
+ }
+ FacesContext context = getFacesContext();
+ // Set up the correct context and fire our wrapped event
+ RowKeyContextEventWrapper revent = (RowKeyContextEventWrapper) event;
+
+ Object oldRowKey = getRowKey();
+ setRowKey(revent.getRowKey());
+ FacesEvent rowEvent = revent.getFacesEvent();
+ UIComponent source = rowEvent.getComponent();
+ UIComponent compositeParent = null;
+ try {
+ if (!UIComponent.isCompositeComponent(source)) {
+ compositeParent = UIComponent.getCompositeComponentParent(source);
+ }
+ if (compositeParent != null) {
+ compositeParent.pushComponentToEL(context, null);
+ }
+ source.pushComponentToEL(context, null);
+ source.broadcast(rowEvent);
+ } finally {
+ source.popComponentFromEL(context);
+ if (compositeParent != null) {
+ compositeParent.popComponentFromEL(context);
+ }
+ }
+
+ setRowKey(oldRowKey);
+ }
+
+ /**
+ * 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.
+ */
+ //TODO - is it still actual?
+ protected boolean broadcastLocal(FacesEvent event) {
+ return false;
+ }
+
+ /**
+ * @return the extendedDataModel
+ */
+ protected ExtendedDataModel<?> getExtendedDataModel() {
+ if (extendedDataModel == null) {
+ extendedDataModel = createExtendedDataModel();
+ }
+ return extendedDataModel;
+ }
+
+ /**
+ * @return
+ */
+ protected abstract ExtendedDataModel<?> createExtendedDataModel();
+
+ /**
+ * @param extendedDataModel the extendedDataModel to set
+ */
+ protected void setExtendedDataModel(ExtendedDataModel<?> extendedDataModel) {
+ this.extendedDataModel = extendedDataModel;
+ }
+
+ public String getVar() {
+ return (String) getStateHelper().get(PropertyKeys.var);
+ }
+
+ public void setVar(String var) {
+ getStateHelper().put(PropertyKeys.var, var);
+ }
+
+ public String getRowKeyVar() {
+ return (String) getStateHelper().get(PropertyKeys.rowKeyVar);
+ }
+
+ public void setRowKeyVar(String rowKeyVar) {
+ getStateHelper().put(PropertyKeys.rowKeyVar, rowKeyVar);
+ }
+
+ public String getStateVar() {
+ return (String) getStateHelper().get(PropertyKeys.stateVar);
+ }
+
+ public void setStateVar(String stateVar) {
+ getStateHelper().put(PropertyKeys.stateVar, stateVar);
+ }
+
+ //TODO - review and probably remove
+ public int getRowCount() {
+ return getExtendedDataModel().getRowCount();
+ }
+
+ public Object getRowData() {
+ return getExtendedDataModel().getRowData();
+ }
+
+ public boolean isRowAvailable() {
+ return getExtendedDataModel().isRowAvailable();
+ }
+
+ /**
+ * 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
+ *
+ * @param faces
+ * current faces context
+ * @param localModel
+ * @param rowSelected
+ */
+ protected void setupVariable(FacesContext faces, boolean rowSelected) {
+ Map<String, Object> attrs = faces.getExternalContext().getRequestMap();
+ if (rowSelected) {
+ // Current row data.
+ setupVariable(getVar(), attrs, 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);
+ }
+ }
+
+ /**
+ * @return
+ */
+ public DataComponentState getComponentState() {
+ if (componentState != null) {
+ return componentState;
+ }
+
+ ValueExpression componentStateExpression =
getValueExpression("componentState");
+ if (componentStateExpression != null) {
+ componentState = (DataComponentState)
componentStateExpression.getValue(getFacesContext().getELContext());
+ }
+
+ if (componentState == null) {
+ componentState = createComponentState();
+
+ if (componentStateExpression != null &&
+ !componentStateExpression.isReadOnly(getFacesContext().getELContext())) {
+
+ componentStateExpression.setValue(getFacesContext().getELContext(), componentState);
+ }
+ }
+
+ return componentState;
+ }
+
+ protected abstract DataComponentState createComponentState();
+
+ /**
+ * @param var
+ * @param attrs
+ * @param rowData
+ */
+ private void setupVariable(String var, Map<String, Object> attrs, Object rowData)
{
+ if (var != null) {
+ attrs.put(var, rowData);
+ }
+ }
+
+ /**
+ * @param var
+ * @param attrs
+ * @param rowData
+ */
+ private void removeVariable(String var, Map<String, Object> attrs) {
+ if (var != null) {
+ attrs.remove(var);
+ }
+ }
+
+ public Converter getRowKeyConverter() {
+ return (Converter) getStateHelper().eval(PropertyKeys.rowKeyConverter);
+ }
+
+ public void setRowKeyConverter(Converter converter) {
+ //TODO - handle partial state saving
+ getStateHelper().put(PropertyKeys.rowKeyConverter, converter);
+ }
+
+ @Override
+ public String getClientId(FacesContext facesContext) {
+ if (facesContext == null) {
+ throw new NullPointerException("context");
+ }
+
+ if (null == clientId) {
+ StringBuilder id = new StringBuilder(super.getClientId(facesContext));
+ Object rowKey = getRowKey();
+ if (rowKey != null) {
+ // Use converter to get String representation ot the row key.
+ Converter rowKeyConverter = getRowKeyConverter();
+ if(null == rowKeyConverter){
+ // Create default converter for a row key.
+ rowKeyConverter = facesContext.getApplication().createConverter(rowKey.getClass());
+ // Store converter for a invokeOnComponents call.
+ if(null != rowKeyConverter){
+ setRowKeyConverter(rowKeyConverter);
+ }
+ }
+ String rowKeyString;
+ if (null != rowKeyConverter) {
+ // Temporary set clientId, to avoid infinite calls from converter.
+ clientId = id.toString();
+ rowKeyString = rowKeyConverter.getAsString(facesContext, this, rowKey);
+ } else {
+ rowKeyString = rowKey.toString();
+ }
+
+ id.append(UINamingContainer.getSeparatorChar(facesContext)).append(rowKeyString);
+ }
+
+ Renderer renderer = getRenderer(facesContext);
+ if (null != renderer) {
+ clientId = renderer.convertClientId(facesContext, id.toString());
+ } else {
+ clientId = id.toString();
+ }
+ }
+
+ return clientId;
+ }
+
+ /**
+ * Base class for visit data model at phases decode, validation and update
+ * model
+ *
+ * @author shura
+ *
+ */
+ protected abstract class ComponentVisitor implements DataVisitor {
+
+ public DataVisitResult process(FacesContext context, Object rowKey, Object argument) {
+ setRowKey(context, rowKey);
+ if (isRowAvailable()) {
+ Iterator<UIComponent> childIterator = dataChildren();
+ while (childIterator.hasNext()) {
+ UIComponent component = childIterator.next();
+ processComponent(context, component, argument);
+ }
+ }
+
+ return DataVisitResult.CONTINUE;
+ }
+
+ public abstract void processComponent(FacesContext context,
+ UIComponent c, Object argument);
+
+ }
+
+ /**
+ * 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);
+ }
+
+ };
+
+ /**
+ * Save current state of data variable.
+ *
+ * @param faces
+ * current faces context
+ */
+ //TODO move into walk() method body
+ public void captureOrigValue(FacesContext faces) {
+ String var = getVar();
+ if (var != null) {
+ Map<String, Object> attrs = faces.getExternalContext().getRequestMap();
+ this.originalVarValue = attrs.get(var);
+ }
+
+ //TODO add support for another variables
+ }
+
+ /**
+ * 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<String, Object> attrs = faces.getExternalContext().getRequestMap();
+ if (this.originalVarValue != null) {
+ attrs.put(var, this.originalVarValue);
+ } else {
+ attrs.remove(var);
+ }
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see javax.faces.component.UIComponent#setValueExpression(java.lang.String,
javax.el.ValueExpression)
+ */
+ @Override
+ public void setValueExpression(String name, ValueExpression binding) {
+ if ("var".equals(name) || "rowKeyVar".equals(name) ||
"stateVar".equals(name)) {
+ throw new IllegalArgumentException(MessageFormat.format("{0} cannot be
EL-expression",
+ name));
+ }
+
+ super.setValueExpression(name, binding);
+ }
+
+ /**
+ * Check for validation errors on children components. If true, saved values
+ * must be keep on render phase
+ *
+ * @param context
+ * @return
+ */
+ protected boolean keepSaved(FacesContext context) {
+ // For an any validation errors, children components state should be preserved
+ FacesMessage.Severity sev = context.getMaximumSeverity();
+ return (sev != null && (FacesMessage.SEVERITY_ERROR.compareTo(sev) >= 0));
+ }
+
+
+ /**
+ * Perform iteration on all children components and all data rows with given
+ * visitor.
+ *
+ * @param faces
+ * @param visitor
+ */
+ protected void iterate(FacesContext faces, ComponentVisitor visitor) {
+ // stop if not rendered
+ if (!this.isRendered()) {
+ return;
+ }
+
+ // reset rowIndex
+ this.captureOrigValue(faces);
+ this.setRowKey(faces, null);
+
+ try {
+ Iterator<UIComponent> fixedChildren = fixedChildren();
+ while (fixedChildren.hasNext()) {
+ UIComponent component = fixedChildren.next();
+ visitor.processComponent(faces, component, null);
+ }
+
+ walk(faces, visitor, null);
+ } catch (Exception e) {
+ throw new FacesException(e);
+ } finally {
+ this.setRowKey(faces, null);
+ this.restoreOrigValue(faces);
+ }
+ }
+
+
+ /**
+ * Walk ( visit ) this component on all data-aware children for each row.
+ *
+ * @param faces
+ * @param visitor
+ */
+ public void walk(FacesContext faces, DataVisitor visitor, Object argument) {
+ Range range = null;
+
+ DataComponentState componentState = getComponentState();
+ if (componentState != null) {
+ range = componentState.getRange();
+ }
+
+ getExtendedDataModel().walk(faces, visitor, range, argument);
+ }
+
+ public void processDecodes(FacesContext faces) {
+ if (!this.isRendered()) {
+ return;
+ }
+
+ this.iterate(faces, decodeVisitor);
+ this.decode(faces);
+ }
+
+ public void processValidators(FacesContext faces) {
+ if (!this.isRendered()) {
+ return ;
+ }
+
+ this.iterate(faces, validateVisitor);
+ }
+
+ public void processUpdates(FacesContext faces) {
+ if (!this.isRendered()) {
+ return;
+ }
+
+ this.iterate(faces, updateVisitor);
+ 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();
+ }
+ }
+
+ @Override
+ public void setId(String id) {
+ super.setId(id);
+ this.clientId = null;
+ }
+
+ /* (non-Javadoc)
+ * @see org.ajax4jsf.component.IterationStateHolder#getIterationState()
+ */
+ public Object getIterationState() {
+ assert (rowKey == null);
+
+ StateHelper stateHelper = getStateHelper();
+
+ return new Object[] {
+ stateHelper.get(PropertyKeys.childState),
+ this.componentState,
+ this.ajaxRowKey,
+ this.extendedDataModel,
+ };
+ }
+
+ /* (non-Javadoc)
+ * @see org.ajax4jsf.component.IterationStateHolder#setIterationState(java.lang.Object)
+ */
+ public void setIterationState(Object stateObject) {
+ assert (rowKey == null);
+ //TODO - ?
+ //restoreChildState(getFacesContext());
+
+ StateHelper stateHelper = getStateHelper();
+ if (stateObject != null) {
+ Object[] state = (Object[]) stateObject;
+
+ stateHelper.put(PropertyKeys.childState, state[0]);
+ this.componentState = (DataComponentState) state[1];
+ this.ajaxRowKey = state[2];
+ this.extendedDataModel = (ExtendedDataModel<?>) state[3];
+ } else {
+ stateHelper.remove(PropertyKeys.childState);
+ this.componentState = null;
+ this.ajaxRowKey = null;
+ this.extendedDataModel = null;
+ }
+ }
+
+ protected void resetDataModel(FacesContext context) {
+ this.extendedDataModel = null;
+ }
+
+ protected void resetChildState(FacesContext context) {
+ getStateHelper().remove(PropertyKeys.childState);
+ }
+
+ protected void preEncodeBegin(FacesContext context) {
+ resetDataModel(context);
+
+ if (!keepSaved(context)) {
+ resetChildState(context);
+ }
+ }
+
+ @Override
+ public void encodeBegin(FacesContext context) throws IOException {
+ preEncodeBegin(context);
+
+ super.encodeBegin(context);
+ }
+
+ /* (non-Javadoc)
+ * @see
javax.faces.component.UIComponentBase#saveState(javax.faces.context.FacesContext)
+ */
+ @Override
+ public Object saveState(FacesContext context) {
+ //TODO handle model serialization - "execute" model
+ Boolean componentStateIsStateHolder = null;
+ Object savedComponentState = null;
+
+ //TODO - partial state saving handling
+ if (componentState instanceof StateHolder) {
+ componentStateIsStateHolder = Boolean.TRUE;
+ StateHolder stateHolder = (StateHolder) componentState;
+ if (!stateHolder.isTransient()) {
+ savedComponentState = stateHolder.saveState(context);
+ }
+ } else {
+ componentStateIsStateHolder = Boolean.FALSE;
+ if (componentState instanceof Serializable) {
+ savedComponentState = componentState;
+ }
+ }
+
+ return new Object[] {
+ super.saveState(context),
+ savedComponentState,
+ componentStateIsStateHolder
+ };
+ }
+
+ /* (non-Javadoc)
+ * @see
javax.faces.component.UIComponentBase#restoreState(javax.faces.context.FacesContext,
java.lang.Object)
+ */
+ @Override
+ public void restoreState(FacesContext context, Object stateObject) {
+ Object[] state = (Object[]) stateObject;
+ // TODO Auto-generated method stub
+ super.restoreState(context, state[0]);
+
+ Object savedComponentState = state[1];
+ if (savedComponentState != null) {
+ boolean componentStateIsStateHolder = ((Boolean) state[2]).booleanValue();
+ if (componentStateIsStateHolder) {
+ componentState = createComponentState();
+ ((StateHolder) componentState).restoreState(context, savedComponentState);
+ } else {
+ componentState = (DataComponentState) restoreAttachedState(context,
savedComponentState);
+ }
+
+ //TODO update state model binding
+ }
+ }
+
+ private boolean matchesBaseId(String clientId, String baseId, char 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 context, String clientId,
+ ContextCallback callback) throws FacesException {
+ if (null == context || null == clientId || null == callback) {
+ throw new NullPointerException();
+ }
+
+ String baseId = super.getClientId(context);
+ if (!matchesBaseId(clientId, baseId, 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(context, null);
+ //}
+
+ if (clientId.equals(baseId)) {
+ callback.invokeContextCallback(context, this);
+ found = true;
+ } else {
+ Iterator<UIComponent> fixedChildrenItr = fixedChildren();
+ while (fixedChildrenItr.hasNext() && !found) {
+ UIComponent fixedChild = fixedChildrenItr.next();
+ found = fixedChild.invokeOnComponent(context, clientId, callback);
+ }
+ }
+
+ if (!found) {
+ Object newRowKey = null;
+ // Call for a child component - try to detect row key
+ // baseId.length() + 1 expression skips SEPARATOR_CHAR
+ String rowKeyString = extractKeySegment(context,
+ clientId.substring(baseId.length() + 1));
+ if (rowKeyString != null) {
+ Converter keyConverter = getRowKeyConverter();
+ if (null != keyConverter) {
+ try {
+ newRowKey = keyConverter.getAsObject(context, this,
+ rowKeyString);
+ } catch (ConverterException e) {
+ // TODO: log error
+ }
+ }
+ }
+
+ setRowKey(context, newRowKey);
+
+ if (isRowAvailable()) {
+ Iterator<UIComponent> dataChildrenItr = dataChildren();
+ while (dataChildrenItr.hasNext() && !found) {
+ UIComponent dataChild = dataChildrenItr.next();
+ found = dataChild.invokeOnComponent(context, clientId, callback);
+ }
+ }
+ }
+ } catch (Exception e) {
+ throw new FacesException(e);
+ } finally {
+ //if (null != oldRowKey) {
+ try {
+ setRowKey(context, oldRowKey);
+ restoreOrigValue(context);
+ } catch (Exception e) {
+ log.error(e.getMessage(), e);
+ }
+ //}
+ }
+
+ return found;
+ }
+
+ // Performs pre-phase initialization before visiting children
+ // (if necessary).
+ //TODO - do we need this?
+ private void preVisitChildren(VisitContext visitContext) {
+
+// // If EXECUTE_LIFECYCLE hint is set, we need to do
+// // lifecycle-related initialization before visiting children
+// if (visitContext.getHints().contains(VisitHint.EXECUTE_LIFECYCLE)) {
+// FacesContext facesContext = visitContext.getFacesContext();
+// PhaseId phaseId = facesContext.getCurrentPhaseId();
+//
+// if (phaseId == PhaseId.APPLY_REQUEST_VALUES)
+// preDecode(facesContext);
+// else if (phaseId == PhaseId.PROCESS_VALIDATIONS)
+// preValidate(facesContext);
+// else if (phaseId == PhaseId.UPDATE_MODEL_VALUES)
+// preUpdate(facesContext);
+// else if (phaseId == PhaseId.RENDER_RESPONSE)
+// preEncode(facesContext);
+// }
+ }
+
+ // Tests whether we need to visit our children as part of
+ // a tree visit
+ private boolean doVisitChildren(VisitContext context) {
+
+ // 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.
+ setRowKey(null);
+ Collection<String> idsToVisit = context.getSubtreeIdsToVisit(this);
+ assert (idsToVisit != null);
+
+ // All ids or non-empty collection means we need to visit our children.
+ return (!idsToVisit.isEmpty());
+ }
+
+ private boolean visitFixedChildren(VisitContext visitContext,
+ VisitCallback callback) {
+
+ Iterator<UIComponent> fixedChildrenItr = fixedChildren();
+ while (fixedChildrenItr.hasNext()) {
+ UIComponent fixedChild = fixedChildrenItr.next();
+ if (fixedChild.visitTree(visitContext, callback)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ private boolean visitDataChildren(final VisitContext visitContext,
+ final VisitCallback callback) {
+
+ FacesContext facesContext = visitContext.getFacesContext();
+ final boolean[] singleBoolean = new boolean[]{false};
+
+ this.walk(facesContext, new DataVisitor() {
+
+ public DataVisitResult process(FacesContext context, Object rowKey, Object argument)
{
+
+ setRowKey(context, rowKey);
+
+ if (isRowAvailable()) {
+ Iterator<UIComponent> dataChildrenItr = dataChildren();
+ while (dataChildrenItr.hasNext()) {
+ UIComponent dataChild = dataChildrenItr.next();
+ if (dataChild.visitTree(visitContext, callback)) {
+ singleBoolean[0] = true;
+
+ return DataVisitResult.STOP;
+ }
+ }
+ }
+
+ return DataVisitResult.CONTINUE;
+ }
+ }, null);
+
+ return singleBoolean[0];
+ }
+
+ @Override
+ public boolean visitTree(VisitContext visitContext,
+ VisitCallback callback) {
+ // First check to see whether we are visitable. If not
+ // short-circuit out of this subtree, though allow the
+ // visit to proceed through to other subtrees.
+ if (!isVisitable(visitContext)) {
+ return false;
+ }
+
+ // Clear out the row index is one is set so that
+ // we start from a clean slate.
+ FacesContext facesContext = visitContext.getFacesContext();
+
+ captureOrigValue(facesContext);
+
+ Object oldRowKey = getRowKey();
+ setRowKey(facesContext, null);
+
+ // Push ourselves to EL
+ pushComponentToEL(facesContext, null);
+
+ try {
+
+ // Visit ourselves. Note that we delegate to the
+ // VisitContext to actually perform the visit.
+ VisitResult result = visitContext.invokeVisitCallback(this, callback);
+
+ // If the visit is complete, short-circuit out and end the visit
+ if (result == VisitResult.COMPLETE) {
+ return true;
+ }
+
+ // Visit children, short-circuiting as necessary
+ if ((result == VisitResult.ACCEPT) && doVisitChildren(visitContext))
{
+
+ if (visitFixedChildren(visitContext, callback)) {
+ return true;
+ }
+
+ if (visitDataChildren(visitContext, callback)) {
+ return true;
+ }
+ }
+ }
+ finally {
+ // Clean up - pop EL and restore old row index
+ popComponentFromEL(facesContext);
+ try {
+ setRowKey(oldRowKey);
+ restoreOrigValue(facesContext);
+ } catch (Exception e) {
+ // TODO: handle exception
+ log.error(e.getMessage(), e);
+ }
+ }
+
+ // Return false to allow the visit to continue
+ return false;
+ }
+
+ /**
+ * @param context
+ * @param substring
+ * @return
+ */
+ protected String extractKeySegment(FacesContext context, String substring) {
+ return null;
+ }
+
+}
Added: root/framework/trunk/impl/src/main/java/org/richfaces/component/UISequence.java
===================================================================
--- root/framework/trunk/impl/src/main/java/org/richfaces/component/UISequence.java
(rev 0)
+++
root/framework/trunk/impl/src/main/java/org/richfaces/component/UISequence.java 2009-09-27
23:21:24 UTC (rev 15673)
@@ -0,0 +1,153 @@
+/*
+ * 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 java.sql.ResultSet;
+import java.util.Collections;
+import java.util.List;
+
+import javax.faces.component.UINamingContainer;
+import javax.faces.context.FacesContext;
+import javax.faces.convert.Converter;
+import javax.faces.model.ArrayDataModel;
+import javax.faces.model.DataModel;
+import javax.faces.model.ListDataModel;
+import javax.faces.model.ResultDataModel;
+import javax.faces.model.ResultSetDataModel;
+import javax.faces.model.ScalarDataModel;
+import javax.servlet.jsp.jstl.sql.Result;
+
+import org.ajax4jsf.model.DataComponentState;
+import org.ajax4jsf.model.ExtendedDataModel;
+import org.ajax4jsf.model.RepeatState;
+import org.ajax4jsf.model.SequenceDataModel;
+
+/**
+ * @author Nick Belaevski
+ *
+ */
+public class UISequence extends UIDataAdaptor {
+
+ protected enum PropertyKeys {
+ first, rows, value
+ }
+
+ @SuppressWarnings("unchecked")
+ protected DataModel<?> createFacesModel(Object value) {
+ DataModel<?> model = null;
+
+ if (value == null) {
+ model = new ListDataModel(Collections.EMPTY_LIST);
+ } else if (value instanceof DataModel) {
+ model = (DataModel) value;
+ } else if (value instanceof List) {
+ model = new ListDataModel((List) value);
+ } else if (Object[].class.isAssignableFrom(value.getClass())) {
+ model = new ArrayDataModel((Object[]) value);
+ } else if (value instanceof ResultSet) {
+ model = new ResultSetDataModel((ResultSet) value);
+ } else if (value instanceof Result) {
+ model = new ResultDataModel((Result) value);
+ } else {
+ model = new ScalarDataModel(value);
+ }
+
+ return model;
+ }
+
+ @Override
+ protected ExtendedDataModel<?> createExtendedDataModel() {
+ ExtendedDataModel<?> model = null;
+
+ // Synthesize a DataModel around our current value if possible
+ Object value = getValue();
+ if (value instanceof ExtendedDataModel<?>) {
+ model = (ExtendedDataModel<?>) value;
+ } else {
+ model = new SequenceDataModel(createFacesModel(value));
+ }
+
+ return model;
+ }
+
+ @Override
+ protected String extractKeySegment(FacesContext context, String clientIdSubstring) {
+ char separatorChar = UINamingContainer.getSeparatorChar(context);
+
+ int separatorIndex = clientIdSubstring.indexOf(separatorChar);
+ if (separatorIndex < 0) {
+ return clientIdSubstring;
+ } else {
+ return clientIdSubstring.substring(0, separatorIndex);
+ }
+ }
+
+ @Override
+ protected DataComponentState createComponentState() {
+ return new RepeatState() {
+
+ @Override
+ public int getFirst() {
+ return UISequence.this.getFirst();
+ }
+
+ @Override
+ public int getRows() {
+ return UISequence.this.getRows();
+ }
+ };
+ }
+
+ /* (non-Javadoc)
+ * @see org.richfaces.component.UIDataAdaptor#getRowKeyConverter()
+ */
+ //TODO make this a property of model
+ @Override
+ public Converter getRowKeyConverter() {
+ return getFacesContext().getApplication().createConverter(Integer.class);
+ }
+
+ public int getFirst() {
+ return (Integer) getStateHelper().eval(PropertyKeys.first, 0);
+ }
+
+ public void setFirst(int first) {
+ getStateHelper().put(PropertyKeys.first, first);
+ }
+
+ public int getRows() {
+ return (Integer) getStateHelper().eval(PropertyKeys.rows, 0);
+ }
+
+ public void setRows(int rows) {
+ getStateHelper().put(PropertyKeys.rows, rows);
+ }
+
+ public Object getValue() {
+ return getStateHelper().eval(PropertyKeys.value);
+ }
+
+ public void setValue(Object value) {
+ getStateHelper().put(PropertyKeys.value, value);
+ }
+}
Modified:
root/framework/trunk/impl/src/main/java/org/richfaces/component/UISwitchablePanel.java
===================================================================
---
root/framework/trunk/impl/src/main/java/org/richfaces/component/UISwitchablePanel.java 2009-09-25
16:50:56 UTC (rev 15672)
+++
root/framework/trunk/impl/src/main/java/org/richfaces/component/UISwitchablePanel.java 2009-09-27
23:21:24 UTC (rev 15673)
@@ -27,14 +27,12 @@
import javax.faces.component.UIComponent;
import javax.faces.component.UIInput;
import javax.faces.context.FacesContext;
-import javax.faces.el.ValueBinding;
import javax.faces.event.AbortProcessingException;
import javax.faces.event.ActionEvent;
import javax.faces.event.FacesEvent;
import javax.faces.event.PhaseId;
import javax.faces.event.ValueChangeEvent;
-import org.ajax4jsf.context.AjaxContext;
import org.ajax4jsf.renderkit.AjaxRendererUtils;
import org.richfaces.event.SwitchablePanelSwitchEvent;
@@ -70,9 +68,9 @@
return switchType;
}
- ValueBinding switchTypeBinding = getValueBinding("switchType");
- if (switchTypeBinding != null) {
- return (String) switchTypeBinding.getValue(FacesContext.getCurrentInstance());
+ ValueExpression switchTypeExpression = getValueExpression("switchType");
+ if (switchTypeExpression != null) {
+ return (String)
switchTypeExpression.getValue(FacesContext.getCurrentInstance().getELContext());
}
return DEFAULT_METHOD;
Modified:
root/framework/trunk/impl/src/main/java/org/richfaces/webapp/taglib/UIComponentELTagBase.java
===================================================================
---
root/framework/trunk/impl/src/main/java/org/richfaces/webapp/taglib/UIComponentELTagBase.java 2009-09-25
16:50:56 UTC (rev 15672)
+++
root/framework/trunk/impl/src/main/java/org/richfaces/webapp/taglib/UIComponentELTagBase.java 2009-09-27
23:21:24 UTC (rev 15673)
@@ -34,7 +34,7 @@
import javax.faces.webapp.UIComponentELTag;
import org.ajax4jsf.Messages;
-import org.ajax4jsf.component.UIDataAdaptor;
+import org.richfaces.component.UIDataAdaptor;
/**
* @author Maksim Kaszynski
Modified: root/framework/trunk/impl/src/main/resources/META-INF/faces-config.xml
===================================================================
--- root/framework/trunk/impl/src/main/resources/META-INF/faces-config.xml 2009-09-25
16:50:56 UTC (rev 15672)
+++ root/framework/trunk/impl/src/main/resources/META-INF/faces-config.xml 2009-09-27
23:21:24 UTC (rev 15673)
@@ -9,11 +9,11 @@
-->
</factory>
<application>
- <system-event-listener>
+ <!-- system-event-listener>
<system-event-listener-class>org.ajax4jsf.component.RenderPhaseUIDataAdaptorVisitor</system-event-listener-class>
<system-event-class>javax.faces.event.PreRenderComponentEvent</system-event-class>
<source-class>org.ajax4jsf.component.UIDataAdaptor</source-class>
- </system-event-listener>
+ </system-event-listener -->
<!--
<variable-resolver>org.richfaces.skin.SkinVariableResolver</variable-resolver>
<property-resolver>org.richfaces.skin.SkinPropertyResolver</property-resolver>
Deleted:
root/framework/trunk/impl/src/main/resources/META-INF/services/org.richfaces.component.RenderPhaseComponentVisitor
===================================================================
---
root/framework/trunk/impl/src/main/resources/META-INF/services/org.richfaces.component.RenderPhaseComponentVisitor 2009-09-25
16:50:56 UTC (rev 15672)
+++
root/framework/trunk/impl/src/main/resources/META-INF/services/org.richfaces.component.RenderPhaseComponentVisitor 2009-09-27
23:21:24 UTC (rev 15673)
@@ -1 +0,0 @@
-org.ajax4jsf.component.RenderPhaseUIDataAdaptorVisitor