javax.faces.model.DataModel Maven / Gradle / Ivy
/*
* $Id: DataModel.java,v 1.20 2007/04/27 22:00:09 ofung Exp $
*/
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
* and Distribution License("CDDL") (collectively, the "License"). You
* may not use this file except in compliance with the License. You can obtain
* a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
* or glassfish/bootstrap/legal/LICENSE.txt. See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each
* file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
* Sun designates this particular file as subject to the "Classpath" exception
* as provided by Sun in the GPL Version 2 section of the License file that
* accompanied this code. If applicable, add the following below the License
* Header, with the fields enclosed by brackets [] replaced by your own
* identifying information: "Portions Copyrighted [year]
* [name of copyright owner]"
*
* Contributor(s):
*
* If you wish your version of this file to be governed by only the CDDL or
* only the GPL Version 2, indicate your decision by adding "[Contributor]
* elects to include this software in this distribution under the [CDDL or GPL
* Version 2] license." If you don't indicate a single choice of license, a
* recipient has the option to distribute your version of this file under
* either the CDDL, the GPL Version 2 or to extend the choice of license to
* its licensees as provided above. However, if you add GPL Version 2 code
* and therefore, elected the GPL Version 2 license, then the option applies
* only if the new code is made subject to such option by the copyright
* holder.
*/
package javax.faces.model;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
import javax.faces.FacesException;
import javax.faces.component.UIData;
/**
* DataModel
* is an abstraction around arbitrary data
* binding technologies that can be used to adapt a variety of data sources
* for use by JavaServer Faces components that support per-row processing
* for their child components (such as {@link UIData}.
*
* The data collection underlying a {@link DataModel} instance is
* modeled as a collection of row objects that can be accessed by
* a zero-relative cursor (row index). The APIs provide mechanisms to
* position to a specified zero-relative row index, and to retrieve an
* object that represents the data that corresponds to the current
* row index.
*
* A concrete {@link DataModel} instance is attached to a particular
* collection of underlying data by calling the setWrappedData()
* method. It can be detached from that underlying data collection by
* passing a null
parameter to this method.
*
* Concrete {@link DataModel} implementations must provide a public
* zero-arguments constructor that calls setWrappedData(null)
.
* A convenience constructor that takes a wrapped object of the appropriate
* type (and passes it on via a call to setWrappedData()
,
* should also be provided.
*
* Event listeners may be registered to receive notifications
* of when a new row index is selected.
*/
public abstract class DataModel implements Iterable {
private static final DataModelListener[] EMPTY_DATA_MODEL_LISTENER =
new DataModelListener[0];
// -------------------------------------------------------------- Properties
/**
* Return a flag indicating whether there is rowData
* available at the current rowIndex
. If no
* wrappedData
is available, return false
.
*
* @throws FacesException if an error occurs getting the row availability
*/
public abstract boolean isRowAvailable();
/**
* Return the number of rows of data objects represented by this
* {@link DataModel}. If the number of rows is unknown, or no
* wrappedData
is available, return -1.
*
* @throws FacesException if an error occurs getting the row count
*/
public abstract int getRowCount();
/**
* Return an object representing the data for the currenty selected
* row index. If no wrappedData
is available, return
* null
.
*
* @throws FacesException if an error occurs getting the row data
* @throws IllegalArgumentException if now row data is available
* at the currently specified row index
*/
public abstract E getRowData();
/**
* Return the zero-relative index of the currently selected row. If
* we are not currently positioned on a row, or no wrappedData
* is available, return -1.
*
* @throws FacesException if an error occurs getting the row index
*/
public abstract int getRowIndex();
/**
* Set the zero-relative index of the currently selected row, or -1
* to indicate that we are not positioned on a row. 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.
*
* If there is no wrappedData
available when this method
* is called, the specified rowIndex
is stored (and may be
* retrieved by a subsequent call to getRowData()
), but no
* event is sent. Otherwise, if the currently selected row index is
* changed by this call, a {@link DataModelEvent} will be sent to the
* rowSelected()
method of all registered
* {@link DataModelListener}s.
*
* @param rowIndex The new zero-relative index (must be non-negative)
*
* @throws FacesException if an error occurs setting the row index
* @throws IllegalArgumentException if rowIndex
* is less than -1
*/
public abstract void setRowIndex(int rowIndex);
/**
* Return the object representing the data wrapped by this
* {@link DataModel}, if any.
*/
public abstract Object getWrappedData();
/**
* Set the object representing the data collection wrapped by this
* {@link DataModel}. If the specified data
is
* null
, detach this {@link DataModel} from any previously
* wrapped data collection instead.
*
* If data
is non-null
, the currently selected
* row index must be set to zero, and a {@link DataModelEvent} must be sent
* to the rowSelected()
method of all registered
* {@link DataModelListener}s indicating that this row is now selected.
*
* @param data Data collection to be wrapped, or null
to
* detach from any previous data collection
*
* @throws ClassCastException if data
is not of the
* appropriate type for this {@link DataModel} implementation
*/
public abstract void setWrappedData(Object data);
// ------------------------------------------------------ Instance Variables
/**
* The list of registered {@link DataModelListener}s for this
* {@link DataModel}. This variable will be null
unless
* there is at least one registered listener.
*/
private List listeners = null;
// --------------------------------------------- Event Listener Registration
/**
* Add a new {@link DataModelListener} to the set interested in
* notifications from this {@link DataModel}.
*
* @param listener The new {@link DataModelListener} to be registered
*
* @throws NullPointerException if listener
* is null
*/
public void addDataModelListener(DataModelListener listener) {
if (listener == null) {
throw new NullPointerException();
}
if (listeners == null) {
//noinspection CollectionWithoutInitialCapacity
listeners = new ArrayList();
}
listeners.add(listener);
}
/**
* Return the set of {@link DataModelListener}s interested in
* notifications from this {@link DataModel}. If there are no such
* listeners, an empty array is returned.
*/
public DataModelListener[] getDataModelListeners() {
if (listeners == null) {
return EMPTY_DATA_MODEL_LISTENER;
} else {
return listeners.toArray
(new DataModelListener[listeners.size()]);
}
}
/**
* Remove an existing {@link DataModelListener} from the set
* interested in notifications from this {@link DataModel}.
*
* @param listener The old {@link DataModelListener} to be deregistered
*
* @throws NullPointerException if listener
* is null
*/
public void removeDataModelListener(DataModelListener listener) {
if (listener == null) {
throw new NullPointerException();
}
if (listeners != null) {
listeners.remove(listener);
if (listeners.isEmpty()) {
listeners = null;
}
}
}
/**
* Return a read-only Iterator
over the
* row data for this model.
*
* @since 2.0
*/
public Iterator iterator() {
return new DataModelIterator(this);
}
// ---------------------------------------------------------- Nested Classes
@SuppressWarnings({"unchecked"})
private static final class DataModelIterator implements Iterator {
private DataModel model;
private int index;
// -------------------------------------------------------- Constructors
DataModelIterator(DataModel model) {
this.model = model;
this.model.setRowIndex(index);
}
// ----------------------------------------------- Methods from Iterator
/**
* @see java.util.Iterator#hasNext()
*/
public boolean hasNext() {
return model.isRowAvailable();
}
/**
* @see java.util.Iterator#next()
*/
public T next() {
if (!model.isRowAvailable()) {
throw new NoSuchElementException();
}
Object o = model.getRowData();
model.setRowIndex(++index);
return (T) o;
}
/**
* Unsupported.
* @see java.util.Iterator#remove()
*/
public void remove() {
throw new UnsupportedOperationException();
}
} // END DataModelIterator
}