[jboss-user] [JBoss Seam] - Re: Using rich:datascroller With Seam and Hibernate Paginati
neilac333
do-not-reply at jboss.com
Fri Jan 25 14:02:24 EST 2008
So I have done some research, and I have found that it actually isn't the rich:datascroller I should be focusing on but rather the rich:dataTable to which it is bound. It appears to me I need to do two things.
First, I need to write my own DataModel. It seems I am supposed to use the RichFaces class ExtendedDataModel to help manage paging. Here is an implementation of a SerializableDataModel, which subclasses ExtendedDataModel, from the RichFaces site:
| package org.richfaces.demo.extendeddatamodel;
|
|
|
| import java.io.IOException;
|
| import java.util.ArrayList;
|
| import java.util.HashMap;
|
| import java.util.List;
|
| import java.util.Map;
|
|
|
| import javax.faces.context.FacesContext;
|
|
|
| import org.ajax4jsf.model.DataVisitor;
|
| import org.ajax4jsf.model.Range;
|
| import org.ajax4jsf.model.SequenceRange;
|
| import org.ajax4jsf.model.SerializableDataModel;
|
| /**
|
| *
|
| * @author ias
|
| * This is example class that intended to demonstrate use of ExtendedDataModel and SerializableDataModel.
|
| * This implementation intended to be used as a request scope bean. However, it actually provides serialized
|
| * state, so on a post-back we do not load data from the data provider. Instead we use data that was used
|
| * during rendering.
|
| * This data model must be used together with Data Provider, which is responsible for actual data load
|
| * from the database using specific filtering and sorting. Normally Data Provider must be in either session, or conversation
|
| * scope.
|
| */
|
| public class AuctionDataModel extends SerializableDataModel {
|
|
|
| private AuctionDataProvider dataProvider;
|
| private Integer currentPk;
|
| private Map<Integer,AuctionItem> wrappedData = new HashMap<Integer,AuctionItem>();
|
| private List<Integer> wrappedKeys = null;
|
| private boolean detached = false;
|
|
|
| /**
|
| *
|
| */
|
| private static final long serialVersionUID = -1956179896877538628L;
|
|
|
| /**
|
| * This method never called from framework.
|
| * (non-Javadoc)
|
| * @see org.ajax4jsf.model.ExtendedDataModel#getRowKey()
|
| */
|
| @Override
|
| public Object getRowKey() {
|
| return currentPk;
|
| }
|
| /**
|
| * This method normally called by Visitor before request Data Row.
|
| */
|
| @Override
|
| public void setRowKey(Object key) {
|
| this.currentPk = (Integer) key;
|
|
|
| }
|
| /**
|
| * This is main part of Visitor pattern. Method called by framework many times during request processing.
|
| */
|
| @Override
|
| public void walk(FacesContext context, DataVisitor visitor, Range range, Object argument) throws IOException {
|
| int firstRow = ((SequenceRange)range).getFirstRow();
|
| int numberOfRows = ((SequenceRange)range).getRows();
|
| if (detached) { // Is this serialized model
|
| // Here we just ignore current Rage and use whatever data was saved in serialized model.
|
| // Such approach uses much more getByPk() operations, instead of just one request by range.
|
| // Concrete case may be different from that, so you can just load data from data provider by range.
|
| // We are using wrappedKeys list only to preserve actual order of items.
|
| for (Integer key:wrappedKeys) {
|
| setRowKey(key);
|
| visitor.process(context, key, argument);
|
| }
|
| } else { // if not serialized, than we request data from data provider
|
| wrappedKeys = new ArrayList<Integer>();
|
| for (AuctionItem item:dataProvider.getItemsByrange(new Integer(firstRow), numberOfRows, null, true)) {
|
| wrappedKeys.add(item.getPk());
|
| wrappedData.put(item.getPk(), item);
|
| visitor.process(context, item.getPk(), argument);
|
| }
|
| }
|
| }
|
| /**
|
| * This method must return actual data rows count from the Data Provider. It is used by pagination control
|
| * to determine total number of data items.
|
| */
|
| private Integer rowCount; // better to buffer row count locally
|
| @Override
|
| public int getRowCount() {
|
| if (rowCount==null) {
|
| rowCount = new Integer(getDataProvider().getRowCount());
|
| return rowCount.intValue();
|
| } else {
|
| return rowCount.intValue();
|
| }
|
| }
|
| /**
|
| * This is main way to obtain data row. It is intensively used by framework.
|
| * We strongly recommend use of local cache in that method.
|
| */
|
| @Override
|
| public Object getRowData() {
|
| if (currentPk==null) {
|
| return null;
|
| } else {
|
| AuctionItem ret = wrappedData.get(currentPk);
|
| if (ret==null) {
|
| ret = getDataProvider().getAuctionItemByPk(currentPk);
|
| wrappedData.put(currentPk, ret);
|
| return ret;
|
| } else {
|
| return ret;
|
| }
|
| }
|
| }
|
|
|
| /**
|
| * Unused rudiment from old JSF staff.
|
| */
|
| @Override
|
| public int getRowIndex() {
|
| throw new UnsupportedOperationException();
|
| }
|
|
|
| /**
|
| * Unused rudiment from old JSF staff.
|
| */
|
| @Override
|
| public Object getWrappedData() {
|
| throw new UnsupportedOperationException();
|
| }
|
|
|
| /**
|
| * Never called by framework.
|
| */
|
| @Override
|
| public boolean isRowAvailable() {
|
| if (currentPk==null) {
|
| return false;
|
| } else {
|
| return getDataProvider().hasAuctionItemByPk(currentPk);
|
| }
|
| }
|
|
|
| /**
|
| * Unused rudiment from old JSF staff.
|
| */
|
| @Override
|
| public void setRowIndex(int rowIndex) {
|
| throw new UnsupportedOperationException();
|
| }
|
|
|
| /**
|
| * Unused rudiment from old JSF staff.
|
| */
|
| @Override
|
| public void setWrappedData(Object data) {
|
| throw new UnsupportedOperationException();
|
| }
|
|
|
| /**
|
| * This method suppose to produce SerializableDataModel that will be serialized into View State and used on a post-back.
|
| * In current implementation we just mark current model as serialized. In more complicated cases we may need to
|
| * transform data to actually serialized form.
|
| */
|
| public SerializableDataModel getSerializableModel(Range range) {
|
| if (wrappedKeys!=null) {
|
| detached = true;
|
| // Some activity to detach persistent data from wrappedData map may be taken here.
|
| // In that specific case we are doing nothing.
|
| return this;
|
| } else {
|
| return null;
|
| }
|
| }
|
| /**
|
| * This is helper method that is called by framework after model update. In must delegate actual database update to
|
| * Data Provider.
|
| */
|
| @Override
|
| public void update() {
|
| getDataProvider().update();
|
| }
|
|
|
| public AuctionDataProvider getDataProvider() {
|
| return dataProvider;
|
| }
|
|
|
| public void setDataProvider(AuctionDataProvider dataProvider) {
|
| this.dataProvider = dataProvider;
|
| }
|
|
|
| }
|
Second, I need Seam to install my custom DataModel so that it is the one applied to the collection when I use @DataModel in a Seam component. It seems to me the way to do that is similar to what you find here (from Pete's seamdiscs example):
| package org.jboss.seam.trinidad;
|
| import static org.jboss.seam.ScopeType.STATELESS;
| import static org.jboss.seam.annotations.Install.FRAMEWORK;
|
| import javax.faces.model.DataModel;
|
| import org.jboss.seam.annotations.Install;
| import org.jboss.seam.annotations.Name;
| import org.jboss.seam.annotations.Scope;
| import org.jboss.seam.annotations.intercept.BypassInterceptors;
| import org.jboss.seam.faces.DataModels;
| import org.jboss.seam.framework.EntityQuery;
| import org.jboss.seam.framework.HibernateEntityQuery;
| import org.jboss.seam.framework.Query;
|
| /**
| * Provide enhanced features when Trinidad is used as a JSF component set
| * @author pmuir
| *
| */
|
| @Name("org.jboss.seam.faces.dataModels")
| @Install(precedence=FRAMEWORK, classDependencies="org.apache.myfaces.trinidad.component.UIXComponent")
| @Scope(STATELESS)
| @BypassInterceptors
| public class TrinidadDataModels extends DataModels
| {
|
| @Override
| public DataModel getDataModel(Query query)
| {
| // If an EntityQuery is in use we can return a CollectionModel
| // backed by the database
| if (query instanceof EntityQuery)
| {
| return new EntityCollectionModel((EntityQuery) query);
| }
| else if (query instanceof HibernateEntityQuery)
| {
| return new HibernateEntityCollectionModel((HibernateEntityQuery) query);
| }
| else
| {
| return super.getDataModel(query);
| }
| }
|
|
| }
|
|
Now I am not using the Seam CRUD stuff. However, I think if I create my ExtendedDataModel implementation and annotate it with @Install(precedence=FRAMEWORK) and give it the right name, then that should work.
I suppose I am wondering now if the steps I describe are correct and if they are sufficient.
Thanks.
View the original post : http://www.jboss.com/index.html?module=bb&op=viewtopic&p=4123641#4123641
Reply to the post : http://www.jboss.com/index.html?module=bb&op=posting&mode=reply&p=4123641
More information about the jboss-user
mailing list