All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.jsftoolkit.base.DataIterator Maven / Gradle / Ivy

Go to download

The core classes for the JSF Toolkit Component Framework. Includes all framework base and utility classes as well as component kick-start/code-generation and registration tools. Also includes some classes for testing that are reused in other projects. They cannot be factored out into a separate project because they are referenced by the tests and they reference this code (circular dependence).

The newest version!
package com.jsftoolkit.base;

import javax.el.ValueExpression;
import javax.faces.FacesException;
import javax.faces.component.ContextCallback;
import javax.faces.component.UIColumn;
import javax.faces.component.UIComponent;
import javax.faces.component.UIData;
import javax.faces.context.FacesContext;
import javax.faces.model.DataModel;

import com.jsftoolkit.utils.Utils;

/**
 * General purpose data iterator. Unlike {@link UIData}, {@link DataIterator}
 * is not coupled to a particular rendering model. i.e. all child components
 * will be processed, not just {@link UIColumn}s. Other than this deviation,
 * its behavior should be identical to {@link UIData}s, except when using any
 * of the extensions mentioned below.
 * 

* The "rowId" property allows you to specify the client identity of each data * item. As long as this value is unique, any actions performed on a particular * row will always be applied to the proper data item, regardless of changes to * the underlying {@link DataModel}. *

* In the event that an element with matching id is no longer in the DataModel, * the action will simply not occur. *

* Any facets added to this component will be ignored. * * @see #getClientId(FacesContext) * @author noah * */ public class DataIterator extends DataIteratorBase implements JsfIterator { private static final String ID_FORMAT = "%s" + SEPARATOR_CHAR + "%s"; private static final java.util.logging.Logger LOG = java.util.logging.Logger .getLogger(DataIterator.class.getCanonicalName()); /** * If the attribute "rowId" is set, it will be evaluated for the current row * to determine the clientId prefix for the current rows children. *

* If it is not set, the rowIndex is used. */ @Override public String getClientId(FacesContext context) { Utils.notNull(context, "context"); ValueExpression rowId = getValueExpression(ROW_ID); if (rowId == null || getRowIndex() < 0) { return super.getClientId(context); } else { String thisId = getContainerId(context); return String.format(ID_FORMAT, thisId, rowId.getValue(context .getELContext())); } } /** * * @param context * @return the clientId of this UIData component */ private String getContainerId(FacesContext context) { final int originalIndex = super.getRowIndex(); // turn off iteration while we retrieve the id setRowIndex(-1); String thisId = super.getClientId(context); // restore the row index setRowIndex(originalIndex); return thisId; } /** * Adds logic to resolve custom row ids if a custom row id expression was * specified. */ @Override public boolean invokeOnComponent(FacesContext context, String clientId, ContextCallback callback) throws FacesException { Utils.notNull(context, "context"); Utils.notNull(clientId, "clientId"); ValueExpression rowExpression = getValueExpression(ROW_ID); String baseId = getContainerId(context); // parse the rowId String rowId = getRowId(clientId, baseId); if (rowId == null) { // the component being looked for is not down this branch, so abort return false; } int originalIndex = getRowIndex(); boolean found = false; try { if (rowExpression == null) { // XXX why doesn't super.invokeOnComponent work right? try { setRowIndex(Integer.parseInt(rowId)); found = invokeOnChildren(context, clientId, callback); } catch (NumberFormatException e) { LOG.warning("Could not parse rowId: " + rowId); return false; } } else { // iterate over all the data until we find an instance that // matches the id iterate over the rows for (int i = 0; !found && isSetRowAvailable(i); i++) { if (rowId.equals(Utils.toString(rowExpression .getValue(context.getELContext())))) { // if we're on a row whose rowExpression matches the // rowId, try each of the children found = invokeOnChildren(context, clientId, callback); // the rowId is suppose to be unique, so if we found a // match, quit, whether or not found returned true break; } } } } catch (Exception e) { throw new FacesException(e); } finally { setRowIndex(originalIndex); } return found; } /** * Calls {@link #invokeOnComponent(FacesContext, String, ContextCallback)} * on each child node, reseting it's id before the call. * * @param context * @param clientId * @param callback * @return */ protected boolean invokeOnChildren(FacesContext context, String clientId, ContextCallback callback) { for (UIComponent child : getChildren()) { // reset the child's id child.setId(child.getId()); if (child.invokeOnComponent(context, clientId, callback)) { return true; } } return false; } /** * Sets the row index and returns {@link #isRowAvailable()}. * * @param index * @return */ protected boolean isSetRowAvailable(int index) { setRowIndex(index); return isRowAvailable(); } /** * Given the child client id and the id of this component, returns the * portion identifying the row. * * @param clientId * @param thisId * @return the rowId, parsed from the client id. */ public static String getRowId(String clientId, String thisId) { if (!clientId.startsWith(thisId + SEPARATOR_CHAR)) { return null; } int startIndex = thisId.length() + 1; // find the next separator so we can parse the rowId int endIndex = clientId.indexOf(SEPARATOR_CHAR, startIndex); endIndex = endIndex == -1 ? clientId.length() : endIndex; if (startIndex <= endIndex && startIndex > 0 && endIndex <= clientId.length()) { return clientId.substring(startIndex, endIndex); } return null; } /** * Calls {@link UIComponent#processDecodes(FacesContext)} on each child, * once per row. */ @Override public void processDecodes(FacesContext context) { Utils.notNull(context, "context"); if (!isRendered()) { return; } // let each child decode UIDataProcessor.iterate(context, (JsfIterator) this, new UIDataProcessor() { public void processChild(FacesContext context, UIComponent child) { child.processDecodes(context); } }); // let our renderer (if any) decode decode(context); } /** * Calls {@link UIComponent#processUpdates(FacesContext)} on each child, * once per row. */ @Override public void processUpdates(FacesContext context) { Utils.notNull(context, "context"); if (!isRendered()) { return; } UIDataProcessor.iterate(context, (JsfIterator) this, new UIDataProcessor() { public void processChild(FacesContext context, UIComponent child) { child.processUpdates(context); } }); } /** * Calls {@link UIComponent#processValidators(FacesContext)} on each child, * once per row. */ @Override public void processValidators(FacesContext context) { Utils.notNull(context, "context"); if (!isRendered()) { return; } UIDataProcessor.iterate(context, (JsfIterator) this, new UIDataProcessor() { public void processChild(FacesContext context, UIComponent child) { child.processValidators(context); } }); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy