Method from javax.faces.component.UIData Detail: |
public void broadcast(FacesEvent event) throws AbortProcessingException {
if (!(event instanceof WrapperEvent)) {
super.broadcast(event);
return;
}
FacesContext context = FacesContext.getCurrentInstance();
// Set up the correct context and fire our wrapped event
WrapperEvent revent = (WrapperEvent) event;
if (isNestedWithinUIData()) {
setDataModel(null);
}
int oldRowIndex = getRowIndex();
setRowIndex(revent.getRowIndex());
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);
}
}
setRowIndex(oldRowIndex);
}
Override the default UIComponentBase#broadcast processing to
unwrap any wrapped FacesEvent and reset the current row index,
before the event is actually broadcast. For events that we did not wrap
(in queueEvent() ), default processing will occur.
|
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);
}
|
public void encodeBegin(FacesContext context) throws IOException {
preEncode(context);
super.encodeBegin(context);
}
In addition to the default behavior, ensure that any saved per-row
state for our child input components is discarded unless it is needed to
rerender the current page with errors.
|
public String getClientId(FacesContext context) {
if (context == null) {
throw new NullPointerException();
}
// If baseClientId and clientIdBuilder are both null, this is the
// first time that getClientId() has been called.
// If we're not nested within another UIData, then:
// - create a new StringBuilder assigned to clientIdBuilder containing
// our client ID.
// - toString() the builder - this result will be our baseClientId
// for the duration of the component
// - append UINamingContainer.getSeparatorChar() to the builder
// If we are nested within another UIData, then:
// - create an empty StringBuilder that will be used to build
// this instance's ID
if (baseClientId == null && clientIdBuilder == null) {
if (!isNestedWithinUIData()) {
clientIdBuilder = new StringBuilder(super.getClientId(context));
baseClientId = clientIdBuilder.toString();
baseClientIdLength = (baseClientId.length() + 1);
clientIdBuilder.append(UINamingContainer.getSeparatorChar(context));
clientIdBuilder.setLength(baseClientIdLength);
} else {
clientIdBuilder = new StringBuilder();
}
}
int rowIndex = getRowIndex();
if (rowIndex >= 0) {
String cid;
if (!isNestedWithinUIData()) {
// we're not nested, so the clientIdBuilder is already
// primed with clientID +
// UINamingContainer.getSeparatorChar(). Append the
// current rowIndex, and toString() the builder. reset
// the builder to it's primed state.
cid = clientIdBuilder.append(rowIndex).toString();
clientIdBuilder.setLength(baseClientIdLength);
} else {
// we're nested, so we have to build the ID from scratch
// each time. Reuse the same clientIdBuilder instance
// for each call by resetting the length to 0 after
// the ID has been computed.
cid = clientIdBuilder.append(super.getClientId(context))
.append(UINamingContainer.getSeparatorChar(context)).append(rowIndex)
.toString();
clientIdBuilder.setLength(0);
}
return (cid);
} else {
if (!isNestedWithinUIData()) {
// Not nested and no row available, so just return our baseClientId
return (baseClientId);
} else {
// nested and no row available, return the result of getClientId().
// this is necessary as the client ID will reflect the row that
// this table represents
return super.getClientId(context);
}
}
}
Return a client identifier for this component that includes the
current value of the rowIndex property, if it is not set to
-1. This implies that multiple calls to getClientId() may
return different results, but ensures that child components can
themselves generate row-specific client identifiers (since UIData
is a NamingContainer ).
|
protected DataModel getDataModel() {
// Return any previously cached DataModel instance
if (this.model != null) {
return (model);
}
// Synthesize a DataModel around our current value if possible
Object current = getValue();
if (current == null) {
setDataModel(new ListDataModel(Collections.EMPTY_LIST));
} else if (current instanceof DataModel) {
setDataModel((DataModel) current);
} else if (current instanceof List) {
setDataModel(new ListDataModel((List) current));
} else if (Object[].class.isAssignableFrom(current.getClass())) {
setDataModel(new ArrayDataModel((Object[]) current));
} else if (current instanceof ResultSet) {
setDataModel(new ResultSetDataModel((ResultSet) current));
} else if (current instanceof Result) {
setDataModel(new ResultDataModel((Result) current));
} else {
setDataModel(new ScalarDataModel(current));
}
return (model);
}
Return the internal DataModel object representing the data
objects that we will iterate over in this component's rendering.
If the model has been cached by a previous call to #setDataModel , return it. Otherwise call #getValue . If the
result is null, create an empty ListDataModel and return it. If
the result is an instance of DataModel , return it. Otherwise,
adapt the result as described in #getValue and return it.
|
public String getFamily() {
return (COMPONENT_FAMILY);
}
|
public int getFirst() {
return (Integer) getStateHelper().eval(PropertyKeys.first, 0);
}
|
public UIComponent getFooter() {
return getFacet("footer");
}
|
public UIComponent getHeader() {
return getFacet("header");
}
|
public int getRowCount() {
return (getDataModel().getRowCount());
}
Return the number of rows in the underlying data model. If the number
of available rows is unknown, return -1.
|
public Object getRowData() {
return (getDataModel().getRowData());
}
Return the data object representing the data for the currently
selected row index, if any.
|
public int getRowIndex() {
return (Integer) getStateHelper().eval(PropertyKeys.rowIndex, -1);
}
Return the zero-relative index of the currently selected row. If we
are not currently positioned on a row, return -1. This property is
not enabled for value binding expressions.
|
public int getRows() {
return (Integer) getStateHelper().eval(PropertyKeys.rows, 0);
}
Return the number of rows to be displayed, or zero for all remaining
rows in the table. The default value of this property is zero.
|
public Object getValue() {
return getStateHelper().eval(PropertyKeys.value);
}
Return the value of the UIData. This value must either be
be of type DataModel , or a type that can be adapted
into a DataModel . UIData will automatically
adapt the following types:
- Arrays
java.util.List
java.sql.ResultSet
javax.servlet.jsp.jstl.sql.Result
All other types will be adapted using the ScalarDataModel
class, which will treat the object as a single row of data.
|
public String getVar() {
return (String) getStateHelper().get(PropertyKeys.var);
}
Return the request-scope attribute under which the data object for the
current row will be exposed when iterating. This property is
not enabled for value binding expressions.
|
public boolean invokeOnComponent(FacesContext context,
String clientId,
ContextCallback callback) throws FacesException {
if (null == context || null == clientId || null == callback) {
throw new NullPointerException();
}
String myId = super.getClientId(context);
boolean found = false;
if (clientId.equals(myId)) {
try {
callback.invokeContextCallback(context, this);
return true;
}
catch (Exception e) {
throw new FacesException(e);
}
}
// check the facets, if any, of UIData
if (this.getFacetCount() > 0) {
for (UIComponent c : this.getFacets().values()) {
c.invokeOnComponent(context, clientId, callback);
}
}
// check column level facets, if any
if (this.getChildCount() > 0) {
for (UIComponent column : this.getChildren()) {
if (column instanceof UIColumn) {
if (column.getFacetCount() > 0) {
for (UIComponent facet : column.getFacets().values()) {
facet.invokeOnComponent(context, clientId, callback);
}
}
}
}
}
int lastSep, newRow, savedRowIndex = this.getRowIndex();
try {
char sepChar = UINamingContainer.getSeparatorChar(context);
// If we need to strip out the rowIndex from our id
// PENDING(edburns): is this safe with respect to I18N?
if (myId.endsWith(sepChar + Integer.toString(savedRowIndex, 10))) {
lastSep = myId.lastIndexOf(sepChar);
assert (-1 != lastSep);
myId = myId.substring(0, lastSep);
}
// myId will be something like form:outerData for a non-nested table,
// and form:outerData:3:data for a nested table.
// clientId will be something like form:outerData:3:outerColumn
// for a non-nested table. clientId will be something like
// outerData:3:data:3:input for a nested table.
if (clientId.startsWith(myId)) {
int preRowIndexSep, postRowIndexSep;
if (-1 != (preRowIndexSep =
clientId.indexOf(sepChar,
myId.length()))) {
// Check the length
if (++preRowIndexSep < clientId.length()) {
if (-1 != (postRowIndexSep =
clientId.indexOf(sepChar,
preRowIndexSep + 1))) {
try {
newRow = Integer
.valueOf(clientId.substring(preRowIndexSep,
postRowIndexSep))
.intValue();
} catch (NumberFormatException ex) {
// PENDING(edburns): I18N
String message =
"Trying to extract rowIndex from clientId \'"
+
clientId
+ "\' "
+ ex.getMessage();
throw new NumberFormatException(message);
}
this.setRowIndex(newRow);
if (this.isRowAvailable()) {
found = super.invokeOnComponent(context,
clientId,
callback);
}
}
}
}
}
}
catch (FacesException fe) {
throw fe;
}
catch (Exception e) {
throw new FacesException(e);
}
finally {
this.setRowIndex(savedRowIndex);
}
return found;
}
Override behavior from UIComponentBase#invokeOnComponent to provide special care for
positioning the data properly before finding the component and
invoking the callback on it. If the argument
clientId is equal to this.getClientId()
simply invoke the contextCallback , passing the
context argument and this as arguments, and
return true. If the argument clientId
is not equal to this.getClientId() , inspect each of
the facet children of this UIData instance and for
each one, compare its clientId with the argument
clientId . If there is a match, invoke the
contextCallback , passing the context
argument and this as arguments, and return
true . Otherwise, attempt to extract a rowIndex from
the clientId . For example, if the argument
clientId was form:data:3:customerHeader
the rowIndex would be 3 . Let this value be called
newIndex . The current rowIndex of this instance must
be saved aside and restored before returning in all cases,
regardless of the outcome of the search or if any exceptions are
thrown in the process.
The implementation of this method must never return true
if setting the rowIndex of this instance to be equal to
newIndex causes this instance to return false
from #isRowAvailable .
|
public boolean isRowAvailable() {
return (getDataModel().isRowAvailable());
}
Return a flag indicating whether there is rowData
available at the current rowIndex . If no
wrappedData is available, return false .
|
public void processDecodes(FacesContext context) {
if (context == null) {
throw new NullPointerException();
}
if (!isRendered()) {
return;
}
preDecode(context);
iterate(context, PhaseId.APPLY_REQUEST_VALUES);
decode(context);
}
|
public void processUpdates(FacesContext context) {
if (context == null) {
throw new NullPointerException();
}
if (!isRendered()) {
return;
}
preUpdate(context);
iterate(context, PhaseId.UPDATE_MODEL_VALUES);
// This is not a EditableValueHolder, so no further processing is required
}
|
public void processValidators(FacesContext context) {
if (context == null) {
throw new NullPointerException();
}
if (!isRendered()) {
return;
}
Application app = context.getApplication();
app.publishEvent(context, PreValidateEvent.class, this);
preValidate(context);
iterate(context, PhaseId.PROCESS_VALIDATIONS);
app.publishEvent(context, PostValidateEvent.class, this);
}
|
public void queueEvent(FacesEvent event) {
super.queueEvent(new WrapperEvent(this, event, getRowIndex()));
}
Override the default UIComponentBase#queueEvent processing to
wrap any queued events in a wrapper so that we can reset the current row
index in broadcast() .
|
protected void setDataModel(DataModel dataModel) {
this.model = dataModel;
}
Set the internal DataModel. This UIData instance must
use the given DataModel as its internal value representation from
now until the next call to setDataModel . If the given
DataModel is null , the internal
DataModel must be reset in a manner so that the next call to
#getDataModel causes lazy instantion of a newly refreshed
DataModel .
Subclasses might call this method if they either want to restore the
internal DataModel during the Restore View phase or
if they want to explicitly refresh the current DataModel for
the Render Response phase.
|
public void setFirst(int first) {
if (first < 0) {
throw new IllegalArgumentException(String.valueOf(first));
}
getStateHelper().put(PropertyKeys.first, first);
}
|
public void setFooter(UIComponent footer) {
getFacets().put("footer", footer);
}
Set the footer facet of this component. A convenience method for
getFacets().put("footer", footer) .
|
public void setHeader(UIComponent header) {
getFacets().put("header", header);
}
Set the header facet of this component. A convenience method for
getFacets().put("header", header) .
|
public void setRowIndex(int rowIndex) {
// Save current state for the previous row index
saveDescendantState();
// Update to the new row index
//this.rowIndex = rowIndex;
getStateHelper().put(PropertyKeys.rowIndex, rowIndex);
DataModel localModel = getDataModel();
localModel.setRowIndex(rowIndex);
// if rowIndex is -1, clear the cache
if (rowIndex == -1) {
setDataModel(null);
}
// Clear or expose the current row data as a request scope attribute
String var = (String) getStateHelper().get(PropertyKeys.var);
if (var != null) {
Map< String, Object > requestMap =
getFacesContext().getExternalContext().getRequestMap();
if (rowIndex == -1) {
oldVar = requestMap.remove(var);
} else if (isRowAvailable()) {
requestMap.put(var, getRowData());
} else {
requestMap.remove(var);
if (null != oldVar) {
requestMap.put(var, oldVar);
oldVar = null;
}
}
}
// Reset current state information for the new row index
restoreDescendantState();
}
Set the zero relative index of the current row, or -1 to indicate that
no row is currently selected, by implementing the following algorithm.
It is possible to set the row index at a value for which the underlying
data collection does not contain any row data. Therefore, callers may
use the isRowAvailable() method to detect whether row data
will be available for use by the getRowData() method.
- Save current state information for all descendant components (as
described below).
- Store the new row index, and pass it on to the DataModel
associated with this UIData instance.
- If the new
rowIndex value is -1:
- If the
var property is not null,
remove the corresponding request scope attribute (if any).
- Reset the state information for all descendant components
(as described below).
- If the new
rowIndex value is not -1:
- If the
var property is not null, call
getRowData() and expose the resulting data object
as a request scope attribute whose key is the var
property value.
- Reset the state information for all descendant components
(as described below).
To save current state information for all descendant components,
UIData must maintain per-row information for each descendant
as follows:
- If the descendant is an instance of
EditableValueHolder , save
the state of its localValue property.
- If the descendant is an instance of
EditableValueHolder ,
save the state of the localValueSet property.
- If the descendant is an instance of
EditableValueHolder , save
the state of the valid property.
- If the descendant is an instance of
EditableValueHolder ,
save the state of the submittedValue property.
To restore current state information for all descendant components,
UIData must reference its previously stored information for the
current rowIndex and call setters for each descendant
as follows:
- If the descendant is an instance of
EditableValueHolder ,
restore the value property.
- If the descendant is an instance of
EditableValueHolder ,
restore the state of the localValueSet property.
- If the descendant is an instance of
EditableValueHolder ,
restore the state of the valid property.
- If the descendant is an instance of
EditableValueHolder ,
restore the state of the submittedValue property.
|
public void setRows(int rows) {
if (rows < 0) {
throw new IllegalArgumentException(String.valueOf(rows));
}
getStateHelper().put(PropertyKeys.rows, rows);
}
Set the number of rows to be displayed, or zero for all remaining rows
in the table.
|
public void setValue(Object value) {
setDataModel(null);
getStateHelper().put(PropertyKeys.value, value);
}
Set the value of the UIData . This value must either be
be of type DataModel , or a type that can be adapted into a DataModel .
|
public void setValueBinding(String name,
ValueBinding binding) {
if ("value".equals(name)) {
setDataModel(null);
} else if ("var".equals(name) || "rowIndex".equals(name)) {
throw new IllegalArgumentException();
}
super.setValueBinding(name, binding);
} Deprecated! This - has been replaced by #setValueExpression(java.lang.String,
javax.el.ValueExpression) .
If "name" is something other than "value", "var", or "rowIndex", rely
on the superclass conversion from ValueBinding to
ValueExpression .
|
public void setValueExpression(String name,
ValueExpression binding) {
if ("value".equals(name)) {
this.model = null;
} else if ("var".equals(name) || "rowIndex".equals(name)) {
throw new IllegalArgumentException();
}
super.setValueExpression(name, binding);
}
Set the ValueExpression used to calculate the value for the
specified attribute or property name, if any. In addition, if a ValueExpression is set for the value property, remove any
synthesized DataModel for the data previously bound to this
component.
|
public void setVar(String var) {
getStateHelper().put(PropertyKeys.var, var);
}
Set the request-scope attribute under which the data object for the
current row wil be exposed when iterating.
|
public boolean visitTree(VisitContext context,
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(context))
return false;
// Clear out the row index is one is set so that
// we start from a clean slate.
int oldRowIndex = getRowIndex();
setRowIndex(-1);
// Push ourselves to EL
FacesContext facesContext = context.getFacesContext();
pushComponentToEL(facesContext, null);
try {
// Visit ourselves. Note that we delegate to the
// VisitContext to actually perform the visit.
VisitResult result = context.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(context)) {
// First visit facets
if (visitFacets(context, callback))
return true;
// Next column facets
if (visitColumnFacets(context, callback))
return true;
// And finally, visit rows
if (visitColumnsAndRows(context, callback))
return true;
}
}
finally {
// Clean up - pop EL and restore old row index
popComponentFromEL(facesContext);
setRowIndex(oldRowIndex);
}
// Return false to allow the visit to continue
return false;
}
Override the behavior in UIComponent#visitTree to handle iteration correctly.
If the UIComponent#isVisitable method of this instance
returns false , take no action and return.
Otherwise, save aside the result of a call to #getRowIndex . Call UIComponent#pushComponentToEL and
invoke the visit callback on this UIData instance as
described in UIComponent#visitTree . Let the result of
the invoctaion be visitResult. If visitResult
is VisitResult#COMPLETE , take no further action and
return true . Otherwise, determine if we need to
visit our children. The default implementation calls VisitContext#getSubtreeIdsToVisit passing this as
the argument. If the result of that call is non-empty, let
doVisitChildren be true . If
doVisitChildren is true and
visitResult is VisitResult#ACCEPT , take the
following action.
If this component has facets, call UIComponent#getFacets on this instance and invoke the
values() method. For each
UIComponent in the returned Map ,
call UIComponent#visitTree .
If this component has children, for each child
UIComponent retured from calling #getChildren on this instance, if the child has facets, call
UIComponent#getFacets on the child instance and invoke
the values() method. For each
UIComponent in the returned Map ,
call UIComponent#visitTree .
Iterate over the columns and rows.
Let rowsToProcess be the return from #getRows .
Let rowIndex be the return from #getFirst - 1.
While the number of rows processed is less than
rowsToProcess, take the following actions.
Call #setRowIndex , passing the current row index.
If #isRowAvailable returns false , take no
further action and return false .
For each child component of this UIData that is
also an instance of UIColumn , call UIComponent#visitTree on the child. If such a call returns
true , terminate iteration and return
true . Take no action on non UIColumn
children.
Call #popComponentFromEL and restore the saved row
index with a call to #setRowIndex .
Return false to allow the visiting to
continue.
|