[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