A Generic Superclass for Sorting and Paginating in the database with Richfaces

In my previous post, I presented a solution for sorting and paginating in the database with Richfaces, and that post should be read prior to this one.  However, an examination of the previous solution shows that the only things that are specific to the items being presented are the Id of the item, the item itself, and the DAO used to perform the actual queries.  If we put all the parts of the code that deal with these three items into separate methods, and then override those methods in the subclasses, we can avoid duplicating code.  In contrast to my previous post, I will post all the code of the superclass up front, and then discuss it.  Generics are used so that the superclass can be provided with the types of the items and the id.

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;

/**
 * @param 
 * @param <U>
 */
public abstract class PaginatingDataModel extends SerializableDataModel {
    /** */
    private static final long serialVersionUID = 2954923950179861809L;
    /** */
    protected U currentPk;
    /** */
    protected boolean descending = true;
    /** */
    protected String sortField = getDefaultSortField();
    /** */
    protected boolean detached = false;
    /** */
    protected List<U> wrappedKeys = new ArrayList<U>();
    /** */
    protected Integer rowCount;
    /** */
    protected Map<U> wrappedData = new HashMap<U>();

    /**
     * @see org.ajax4jsf.model.ExtendedDataModel#getRowKey()
     */
    @Override
    public Object getRowKey()
    {
        return currentPk;
    }

    /**
     * @see org.ajax4jsf.model.ExtendedDataModel#setRowKey(java.lang.Object)
     */
    @SuppressWarnings("unchecked")
    @Override
    public void setRowKey(final Object key)
    {
        this.currentPk = (U) key;
    }

    /**
     * @see org.ajax4jsf.model.SerializableDataModel#update()
     */
    @Override
    public void update()
    {
        if (getSortFieldObject() != null)
        {
            final String newSortField = getSortFieldObject().toString();
            if (newSortField.equals(sortField))
            {
                descending = !descending;
            }
            sortField = newSortField;
        }
        detached = false;
    }

    /**
     * @return Object
     */
    protected Object getSortFieldObject()
    {
        final FacesContext context = FacesContext.getCurrentInstance();
        final Object sortFieldObject = context.getExternalContext().getRequestParameterMap().get("sortField");
        return sortFieldObject;
    }

    /**
     * @param sortField
     */
    public void setSortField(final String sortField)
    {
        if (this.sortField.equals(sortField))
        {
            descending = !descending;
        } else
        {
            this.sortField = sortField;
        }
    }

    /**
     * @return String
     */
    public String getSortField()
    {
        return sortField;
    }

    /**
     * @see org.ajax4jsf.model.ExtendedDataModel#getSerializableModel(org.ajax4jsf.model.Range)
     */
    @Override
    public SerializableDataModel getSerializableModel(final Range range)
    {
        if (wrappedKeys != null)
        {
            detached = true;
            return this;
        }
        return null;
    }

    /**
     * @see javax.faces.model.DataModel#setRowIndex(int)
     */
    @Override
    public void setRowIndex(final int rowIndex)
    {
        throw new UnsupportedOperationException();

    }

    /**
     * @see javax.faces.model.DataModel#setWrappedData(java.lang.Object)
     */
    @Override
    public void setWrappedData(final Object data)
    {
        throw new UnsupportedOperationException();

    }

    /**
     * @see javax.faces.model.DataModel#getRowIndex()
     */
    @Override
    public int getRowIndex()
    {
        throw new UnsupportedOperationException();
    }

    /**
     * @see javax.faces.model.DataModel#getWrappedData()
     */
    @Override
    public Object getWrappedData()
    {
        throw new UnsupportedOperationException();
    }

    /**
     * @see org.ajax4jsf.model.ExtendedDataModel#walk(javax.faces.context.FacesContext,
     *      org.ajax4jsf.model.DataVisitor, org.ajax4jsf.model.Range,
     *      java.lang.Object)
     */
    @Override
    public void walk(final FacesContext context, final DataVisitor visitor, final Range range, final Object argument)
            throws IOException
    {
        final int firstRow = ((SequenceRange) range).getFirstRow();
        final int numberOfRows = ((SequenceRange) range).getRows();
        if (detached &amp;amp;&amp;amp; getSortFieldObject() != null)
        {
            for (final U key : wrappedKeys)
            {
                setRowKey(key);
                visitor.process(context, key, argument);
            }
        } else
        { // if not serialized, than we request data from data
            // provider
            wrappedKeys = new ArrayList<U>();
            for (final T object : findObjects(firstRow, numberOfRows, sortField, descending))
            {
                wrappedKeys.add(getId(object));
                wrappedData.put(getId(object), object);
                visitor.process(context, getId(object), argument);
            }
        }
    }

    /**
     * @see javax.faces.model.DataModel#isRowAvailable()
     */
    @Override
    public boolean isRowAvailable()
    {
        if (currentPk == null)
        {
            return false;
        }
        if (wrappedKeys.contains(currentPk))
        {
            return true;
        }
        if (wrappedData.entrySet().contains(currentPk))
        {
            return true;
        }
        try
        {
            if (getObjectById(currentPk) != null)
            {
                return true;
            }
        } catch (final Exception e)
        {

        }
        return false;
    }

    /**
     * @see javax.faces.model.DataModel#getRowData()
     */
    @Override
    public Object getRowData()
    {
        if (currentPk == null)
        {
            return null;
        }

        T object = wrappedData.get(currentPk);
        if (object == null)
        {
            object = getObjectById(currentPk);
            wrappedData.put(currentPk, object);
        }
        return object;
    }

    /**
     * @see javax.faces.model.DataModel#getRowCount()
     */
    @Override
    public int getRowCount()
    {
        if (rowCount == null)
        {
            rowCount = getNumRecords();
        }
        return rowCount;
    }

    /**
     * 
     * @param object
     * @return U
     */
    public abstract U getId(T object);

    /**
     * @param firstRow
     * @param numberOfRows
     * @param sortField
     * @param descending
     * @return List
     */
    public abstract List findObjects(int firstRow, int numberOfRows, String sortField, boolean descending);

    /**
     * @param id
     * @return T
     */
    public abstract T getObjectById(U id);

    /**
     * @return String
     */
    public abstract String getDefaultSortField();

    /**
     * @return int
     */
    public abstract int getNumRecords();
}


The abstract methods are all at the end.  Here is one possible subclass.  Note that it is Session scoped:


import static org.jboss.seam.ScopeType.SESSION;

import java.util.List;

import org.jboss.seam.annotations.In;
import org.jboss.seam.annotations.Logger;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.Scope;
import org.jboss.seam.log.Log;

import PaginatingDataModel;
import IFormsService;
import EntityDTO;
import FolderDTO;

@Name("newhireDataModel")
@Scope(SESSION)
public class NewhireList
    extends PaginatingDataModel
{
    /** */
    private static final long serialVersionUID = 2672142810059859813L;
    
    /** */
    @In
    private IFormsService serviceForms;
    
    /** */
    @In
    EntityDTO currentEntity;
    
    /** */
    @Logger
    Log log;
    
    /**
     * @see PaginatingDataModel#getId(java.lang.Object)
     */
    @Override
    public Integer getId(FolderDTO object)
    {
        return object.getPk();
    }
    
    /**
     * @see PaginatingDataModel#findObjects(int, int, java.lang.String, boolean)
     */
    @Override
    public List findObjects(int firstRow, int numberOfRows, String sortField, boolean descending)
    {
        return serviceForms.findFolders(firstRow, numberOfRows, sortField, descending);
    }
    
    /**
     * @see PaginatingDataModel#getObjectById(java.lang.Object)
     */
    @Override
    public FolderDTO getObjectById(Integer id)
    {
        return serviceForms.getFolder(id);
    }
    
    /**
     * @see PaginatingDataModel#getDefaultSortField()
     */
    @Override
    public String getDefaultSortField()
    {
        return "attribute(EOD)";
    }
    
    /**
     * @see PaginatingDataModel#getNumRecords()
     */
    @Override
    public int getNumRecords()
    {
        return serviceForms.countFolders(null, currentEntity);
    }
    
}

No change needs to be done to the JSF layer when using this solution.

Advertisements

17 thoughts on “A Generic Superclass for Sorting and Paginating in the database with Richfaces

  1. Hi,
    Thank you for your post and for the previous one. They are very interesting.
    I’ve also read some other posts regarding pagination and rich:datascroller but I still can’t solve one problem .
    I cannot set my datascroller to show the correct number of pages. The reason for this is that ListSequenceDataModel is used for calculating the number of pages instead of my ExtendedDataModel.
    I have TestDataModel class which extends SerializableDataModel where in wrappedData I have just 10 elements but my getRowCount method returns the number of all records in the database which is 500. The datascroller though shows that there is only one page.
    I debug the richfaces code to see how the datascroller is rendered.
    This is done mainly in DatascrollerTemplate and DataScrollerRenderer in package org.richfaces.renderkit.html. As expected the datascroller uses the DataModel of the DataTable to calculate the number of pages:
    org.richfaces.component.UIDatascroller.getRowCount(UIData data)
    and after:
    UIDataAdapter.getRowCount(){
    … return getExtendedDataModel().getRowCount();
    }

    Here getExtendedDataModel() returns an instance of ModifiableModel which field “originalModel” contains my custom TestDataModel. So modifiableModel.getOriginalModel.getRowCount will return 500 as I need. But look at the implementation of modifiableModel.getRowCount:

    public int getRowCount() {
    return delegate.getRowCount();
    }

    !!!???
    delegate is an instance of ListSequenceDataModel which contains the list wrappedKeys. So getRowCount() returns wrappedKeys.size() which is 10 so the datascroller renders with only one page.

    At the time of rendering the dataTable when the model is created () both fields: originalModel and delegate are set to TestDataModel. But at some point before delegate is set to ListSequenceDataModel and returns the size of the list.

    Here is example of my code:

    @Name(“testDataModel”)
    @Scope(ScopeType.SESSION)
    public class TestDataModel extends SerializableDataModel {

    private Integer currentPk;

    private boolean detached = false;
    private List wrappedKeys = null;
    private final Map wrappedData = new HashMap();
    private Integer rowCount;

    @In(create = true)
    private UserService userManager;

    @Override
    public void walk(FacesContext context, DataVisitor visitor, Range range, Object argument) throws IOException {
    if (detached){
    for (Integer key : wrappedKeys) {
    setRowKey(key);
    visitor.process(context, key, argument);
    }
    } else {
    int firstRow = ((SequenceRange) range).getFirstRow();
    int numberOfRows =((SequenceRange) range).getRows();
    wrappedKeys = new ArrayList();
    for (User user : userManager.findUsersPaged(firstRow, numberOfRows, null, null)) {
    wrappedKeys.add(user.getId());
    wrappedData.put(user.getId(), user);
    visitor.process(context, user.getId(), argument);
    }
    }
    }


    @Override
    public int getRowCount() {
    rowCount = userManager.countUsers();
    return rowCount;
    }

    @Scope(ScopeType.SESSION)
    @Name(“userManager”)
    public class UserAction implements UserService{

    public List findUsersPaged(int firstRow, int numberOfRows, String sortField, boolean descending) {
    List users = entityManager.createQuery(“select u from User u”).setFirstResult(firstRow).setMaxResults(numberOfRows).getResultList();
    return users;
    }

    Another thing is that there is no way to set the number of pages directly to the UIDatascroller component either by an attribute or by the API
    I’m very interested to see how this problem can be solved.
    If your are familiar with this could you give me a tip.

    Many thanks,
    Hristo

  2. Hello,

    thanks a lot for your post. It helped me a lot but to understand pagination and richfaces but I still did’nt manage to make it working … I’m learning Seam/Richfaces since 2 months and I would like to do a proof of concept, so I implemented the different classes but I’m having some difficulties here :
    1. I replaced
    @In private IFormsService serviceForms
    with
    @In private AlarmRuleManager alarmRuleManager;

    And I’m getting this error :
    Caused by org.jboss.seam.RequiredException with message: “@In attribute requires non-null value: alarmRuleDataModel.alarmRuleManager”

    How do I instantiate this alarmRuleManager and where ?

    Thanks a lot in advance.

    Yves

  3. Hi,
    Thank you for your post it was really useful for me.

    I’ve just started with seams/jsf. Previously I wrote my applications with struts2/spring/jsp so all this stuff is a little different and difficult to me.

    I consider if it is possible to add filtering to this example.
    I assume that to provide filtering I need to write method similar to protected Object getSortFieldObject() (use it in public void update()) and set variable(s) that I want to filter by (those will be used in findObjects() method).

    However I’m unable to read parameters in my seam action.
    I’m propagating them with something like this (embedded in header):

    <f:facet name="header"
    <h:inputText value="#{mySeamAction.filterByField}" id="input" 
        label="Filter by filterByField">
        <a4j:support event="onkeyup" reRender="myTable"
             ignoreDupResponses="true" requestDelay="700" focus="input" />
    </h:inputText>
    </f:facet>
    

    Could you please give me some hints how to achieve above.

  4. Hi,

    Thanks for your posts.

    I’m having trouble with sorting. Clicking on the sort header doesn’t sort the records. I saw in the debugger that every request the model is being created again. I’ve added a default constructor and I print there the this.toString() and every time it’s something different, although the model is session-scoped:
    after a first time I go to the page it prints

    com.camayu.dao.CamayuUserList@51672e
    com.camayu.dao.CamayuUserList_$$_javassist_1@688aeb

    and then, click on sort header prints
    com.camayu.dao.CamayuUserList_$$_javassist_1@cc52fc

    then
    com.camayu.dao.CamayuUserList_$$_javassist_1@a5b02

    and so on.

    Any idea why this is happening?

    Thanks in advance,

    Uri

  5. Hi,

    I think I’ve figured it out. Sorting doesn’t work when javax.faces.STATE_SAVING_METHOD=client. When it’s ‘server’, everything works great.

    Thanks again for your post, it’s very helpful!

  6. For anyone who would like to continue using the Richfaces sortBy functionality within this model, I have come up with a straight-forward solution. Your PaginatingDataModel should implement org.richfaces.model.Modifiable which means you have one more method to implement. I have implemented this method as follows:

    	public void modify(List<FilterField> filterFields, List<SortField2> sortFields)
    	{
    		if (sortFields != null && !sortFields.isEmpty())
    		{
    			SortField2 sortField2 = sortFields.get(0);
    			Expression expression = sortField2.getExpression();
    			String expressionStr = expression.getExpressionString();
    			if (!expression.isLiteralText())
    			{
    				expressionStr = expressionStr.replaceAll("[#|$]{1}\{.*?\.", "")
    						.replaceAll("\}", "");
    			}
    			this.sortField = expressionStr;
    
    			Ordering ordering = sortField2.getOrdering();
    			if (ordering == Ordering.DESCENDING)
    			{
    				this.descending = true;
    			}
    			else
    			{
    				this.descending = false;
    			}
    		}
    	}
    

    Note that my implementation of the modify() method only sorts using one field and I do not need filtering. If you need to sort using multiple fields and do filtering, it should be pretty easy to do by modifying the findObjects(int firstRow, int numberOfRows, String sortField, boolean descending) to something like this findObjects(int firstRow, int numberOfRows, List sortFields, List filterFields, boolean descending).

    The modify() method is called by Richfaces when you have the sortBy attribute defined on the rich:column tag:

        <rich:column sortBy="#{newhire.lastName}"> 
            <f:facet name="header"> 
    			<h:outputLabel for="name" value="Name"/>
            </f:facet> 
            <h:outputText id="name"
                value="#{newhire.lastName}, #{newhire.firstName}" />
        </rich:column>
    

    In order for this to work, you will need to remove the methods getSortFieldObject(), setSortField(final String sortField), and getSortField() from PaginatingDataModel. You will also need to remove most of the code in update() so that your new update() method looks like this:

    	public void update()
    	{
    		this.detached = false;
    	}
    

    Everything else should be able to stay the same. Hope this helps!

    Doug

  7. Hi!

    I managed to use the PaginatingDataModel with Seam framework’s EntityQuery but I have a small problem.

    When scrolling with the datascroller the dataTable rows are not updated. It’s because the PaginatingDataModel’s update function is not called so the model remains detached and works from the wrappedData “cache”.

    In your previous blog entry there are some thoughts about the detached attribute but I did not quite understand it. How is it related to the sortFieldObject? I use a different sorting method.

    Thanks in advance!

  8. Thank you a lot for this post.
    It is really use full for my project.
    But i have one problem. findObjects method is calling multiple times.
    I know for this prevention use “detached” flag but it is not working.
    i am using JSF + Seam.
    Please provide solution for that.
    Thank’s in advance.

  9. “The most important method is the walk method. This method will be called by Richfaces, and will give you an opportunity to pull from the database just those records that will be shown to the user. However, it is important to note that this method can potentially be called many times during one request, and we only want to make one call to the database.”

    It is taken from your previous post.
    would you pls share to us why this multiple access to db happens for a single ajax request?

    Thanks, you post an excellent solution.

  10. Question re: making your code work with this use case – an AJAX selection box allows users to filter the results by a certain type (e.g. in a list of Users, maybe they select USA from the country dropdown, causing the result list to be recalculated to only include Users from the USA).

    When that selection occurs, what code would need to be called on PaginatingDataModel to ensure it is looking at the most recent data – e.g. would something need to be done to the ‘detached’ variable, or anything like that?

    Also, how could we force the dataScroller to go back to page 1 anytime this result list change occurs? The range parameter to the walk() method seems to be the place – would I change that method to manually reset the ‘firstRow’ variable when the result list changes? Something like:

    int firstRow = ((SequenceRange) range).getFirstRow(); 
    if (resultListHasChanged()) {
      firstRow = 0;
    }        
    

    Thanks.

  11. Hi, i apply your solution, but i have a problem whith a jsf life-cicle. Ex: if a faces message occurres, is not renderized, but if resubmit a form (ajax) a single message is duplicated. Any idea ?

    Tank´s
    Kloss

  12. Hi,
    thank you for your articles.
    I’m developing a web-application with a strong pagination data model usage. In some case I have to paginate more than 20000 tuple from a database. This is getting slower so, in debug mode, I notice every page rendering the findObject method is called multiple times (twice or four time) and so getNumber making rendering slower and slower. Do you have any suggestion to improve performance?

    Many thanks,
    Carlo

  13. okay i had a go at this – its been driving me crazy. I tried to first wire up and dataslider to an ordinary seam EntityQuery (built by jboss tools).

    couldnt get this to work properly – it page forward and i can select from drop down page list – but i cant go backwards.

    I somehow thought it might be the datamodel for the slider. So i took your code and tweaked it to encapsulate the seam framework classes.

    however when i run this i still get the same problem – i can go forward, and select a page. but i cant use the first or previous links they dont refresh anything.

    Further i am surprised at the number of times the functions are called – if yo see my trace, (other than injection not seeming to trigger – i’ve had to code round that in the constructor)

    would really appreciate any ideas on why this isnt working. Very frustrating

    
    import java.util.ArrayList;
    import java.util.List;
    
    import javax.faces.model.SelectItem;
    
    import org.domain.forsterslist.entity.Node;
    import org.domain.forsterslist.session.NodeHome;
    import org.domain.forsterslist.session.NodeList;
    import org.jboss.seam.ScopeType;
    import org.jboss.seam.annotations.In;
    import org.jboss.seam.annotations.Logger;
    import org.jboss.seam.annotations.Name;
    import org.jboss.seam.annotations.Scope;
    import org.jboss.seam.log.Log;
    
    
    
    @Name("paginatingNodeListDataModel")
    @Scope(ScopeType.CONVERSATION)
    public class PaginatingNodeList
        extends PaginatingDataModel<Node, Integer>
    {
        /** */
        private static final long serialVersionUID = 2672142810059859813L;
    
        /** */
        @In (required=false)
        private NodeList nodeList;
        
        @In (required=false)
        private NodeHome nodeHome;
    
        /** */
        @In (required=false)
        Node currentEntity;
    
        /** */
        @Logger
        Log log;
    
        private int rows;
    
    	private List<SelectItem> pagesToScroll;
    
    	private Integer scrollerPage;
    	
    	public PaginatingNodeList ()
    	{
            setRows (3);	//set default as 3 rows for rich:data scroller 
            setScrollerPage(1);
        	if (nodeList == null)
        	{
        		System.out.println ("injection failed for nodeList on paginating node list");
        		nodeList = new NodeList();
        	}
    
        	if (nodeHome == null)
        	{
        		System.out.println ("injection failed for nodeHome on paginating node list");
        		nodeHome = new NodeHome();
        	}
    
    	}
    	//calculate the number of pages
        public List<SelectItem>  getPagesToScroll() 
        {
        	List<SelectItem> list = new ArrayList<SelectItem>();
        	for (int i = 1; i <= getMaxScrollerPages(); i++)
        	{
        		if (Math.abs((i-scrollerPage)) < 5)
        		{
        			//start page numbering at 1 for display select list
        			SelectItem pageNum = new SelectItem(i);
        			//if (getScrollerPage()+1 == page) pageNum.setDisabled(true);
         			list.add(pageNum);
        		}
        	}
        	//log.debug("pages to scroll start at #0", list.get(0));
        	System.out.println ("pages to scroll start at [" + list.get(0).getLabel() + "]" + " for object " + this.toString());
        	pagesToScroll = list;
     		return pagesToScroll;
    	}
    
        //debug
        public List<SelectItem>  getPagesToScroll(String calledFrom) 
        {
        	System.out.print (" get pages to scroll called from " + calledFrom);
        	return getPagesToScroll();
        }
        
        public int getMaxScrollerPages ()
        {
        	//counting pages from 1 so add one to div count
        	int rc = nodeList.getResultCount().intValue();
        	int np = rc/rows;
        	int mnp = (rc % rows == 0 ? np  : np + 1); //test page boundary
        	//log.debug("getMaxScroller pages are #0", mnp);
        	System.out.println ("getMaxScroller pages are " + mnp + " on object " + this.toString());
        	return mnp;  
        }
    
        //debug
        public int getMaxScrollerPages (String calledFrom)
        {
        	System.out.print (" get max scroller pages called from " );
        	return getMaxScrollerPages ();
        	
        }
        
    	public int getScrollerPage() 
    	{
        	//log.debug("getMaxScroller pages are #0", scrollerPage);
        	System.out.println ("getScroller page is " + scrollerPage + " on object " + this.toString());
        	return scrollerPage;
    	}
    
    	//debug
    	public int getScrollerPage(String calledFrom)
    	{
        	System.out.print ("getScrollerPage called from " + calledFrom );
        	return getScrollerPage();
    		
    	}
    
    	public void setScrollerPage(int scrollerPage) 
    	{
    		//reset the count to meet the interanl working of the rich data slider
    		String chk = " setMaxScroller pages are " + scrollerPage;
       		if (log == null)
       			System.out.println ("null logger " +chk + " on object " + this.toString());
       		else
       			log.debug(chk);
        		
    		this.scrollerPage = scrollerPage;
    	}
    
    	//debug
    	public void setScrollerPage(int scrollerPage, String calledFrom)
    	{
    	   	System.out.print ("setScroller page called from " + calledFrom);
    	    		
    		setScrollerPage (scrollerPage);
    	}
    
    	public int getRows() {
    		return rows;
    	}
    
    	public void setRows(int rows) {
    		this.rows = rows;
    	}
    
    
        
        /**
         * @see PaginatingDataModel#getId(java.lang.Object)
         */
        @Override
        public Integer getId(Node object)
        {
            return object.getId().intValue();
        }
    
        /**
         * @see PaginatingDataModel#findObjects(int, int, java.lang.String, boolean)
         */
        @Override
        public List<Node> findObjects(int firstRow, int numberOfRows, String sortField, boolean descending)
        {
            return nodeList.findNodes(firstRow, numberOfRows, sortField, descending);
        }
    
        public List<Node> getResultList ()
        {
        	return nodeList.getResultList();
        }
        
        /**
         * @see PaginatingDataModel#getObjectById(java.lang.Object)
         */
        @Override
        public Node getObjectById(Integer id)
        {
        	long nodeId = (long)Integer.valueOf(id);
            nodeHome.setId(id);
            return nodeHome.getInstance();
        }
    
        /**
         * @see PaginatingDataModel#getDefaultSortField()
         */
        @Override
        public String getDefaultSortField()
        {
            return "attribute(EOD)";
        }
    
        /**
         * @see PaginatingDataModel#getNumRecords()
         */
        @Override
        public int getNumRecords()
        {
            //return nodeList.countNodes(null, currentEntity);
        	return nodeList.getResultCount().intValue();
        }
    
    }
    
    

    heres is my jboss tools generated NodeHomeEntityQuery (from seam frameworks)
    (you see the earlier funcs when i tried to hook up the entity query dirctely to the datatable and got the same problem.

    
    import java.util.ArrayList;
    import java.util.List;
    
    import javax.faces.model.SelectItem;
    
    import org.domain.forsterslist.entity.Node;
    import org.jboss.seam.ScopeType;
    import org.jboss.seam.annotations.AutoCreate;
    import org.jboss.seam.annotations.In;
    import org.jboss.seam.annotations.Logger;
    import org.jboss.seam.annotations.Name;
    import org.jboss.seam.annotations.Scope;
    import org.jboss.seam.core.Manager;
    import org.jboss.seam.framework.EntityQuery;
    import org.jboss.seam.log.Log;
    
    @Name("nodeList")
    @Scope (ScopeType.CONVERSATION)	//see if this gets rid of multiple calls
    @AutoCreate
    public class NodeList extends EntityQuery<Node>
    {
    	
    	@Logger
    	private Log log;
    	
    	@In (required=false)
    	Manager mgr; 
    	
    	private int rows;
    
    	private List<SelectItem> pagesToScroll;
    
    	private Integer scrollerPage;
    	
    	//calculate the number of pages
        public List<SelectItem>  getPagesToScroll() 
        {
        	List<SelectItem> list = new ArrayList<SelectItem>();
        	for (int i = 1; i <= getMaxScrollerPages(); i++)
        	{
        		if (Math.abs((i-scrollerPage)) < 5)
        		{
        			//start page numbering at 1 for display select list
        			SelectItem pageNum = new SelectItem(i);
        			//if (getScrollerPage()+1 == page) pageNum.setDisabled(true);
         			list.add(pageNum);
        		}
        	}
        	//log.debug("pages to scroll start at #0", list.get(0));
        	System.out.println ("pages to scroll start at [" + list.get(0).getLabel() + "]" + " for object " + this.toString());
        	pagesToScroll = list;
     		return pagesToScroll;
    	}
    
        //debug
        public List<SelectItem>  getPagesToScroll(String calledFrom) 
        {
        	System.out.print (" get pages to scroll called from " + calledFrom);
        	return getPagesToScroll();
        }
        
        public int getMaxScrollerPages ()
        {
        	//counting pages from 1 so add one to div count
        	int rc = getResultCount().intValue();
        	int np = rc/rows;
        	int mnp = (rc % rows == 0 ? np  : np + 1); //test page boundary
        	//log.debug("getMaxScroller pages are #0", mnp);
        	System.out.println ("getMaxScroller pages are " + mnp + " on object " + this.toString());
        	return mnp;  
        }
    
        //debug
        public int getMaxScrollerPages (String calledFrom)
        {
        	System.out.print (" get max scroller pages called from " );
        	return getMaxScrollerPages ();
        	
        }
        
    	public int getScrollerPage() 
    	{
        	//log.debug("getMaxScroller pages are #0", scrollerPage);
        	System.out.println ("getScroller page is " + scrollerPage + " on object " + this.toString());
        	return scrollerPage;
    	}
    
    	//debug
    	public int getScrollerPage(String calledFrom)
    	{
        	System.out.print ("getScrollerPage called from " + calledFrom );
        	return getScrollerPage();
    		
    	}
    
    	public void setScrollerPage(int scrollerPage) 
    	{
    		//reset the count to meet the interanl working of the rich data slider
    		String chk = " setMaxScroller pages are " + scrollerPage;
       		if (log == null)
       			System.out.println ("null logger " +chk + " on object " + this.toString());
       		else
       			log.debug(chk);
        		
    		this.scrollerPage = scrollerPage;
    	}
    
    	//debug
    	public void setScrollerPage(int scrollerPage, String calledFrom)
    	{
    	   	System.out.print ("setScroller page called from " + calledFrom);
    	    		
    		setScrollerPage (scrollerPage);
    	}
    
    	public int getRows() {
    		return rows;
    	}
    
    	public void setRows(int rows) {
    		this.rows = rows;
    	}
    
    	public List<Node> findNodes(int firstRow, int numberOfRows, String sortField, boolean descending)
    	{
    		this.setFirstResult(firstRow);
    		this.setMaxResults(numberOfRows);
    		this.setOrderColumn(sortField);
    		this.setOrderDirection(descending ? "desc" : "asc" );
    		
    		return this.getResultList();
    				
    	}
    	/**
    	 * 
    	 */
    	private static final long serialVersionUID = 1L;
    
    	public NodeList()
        {
            setEjbql("select node from Node node");
            rows = 3;	//set default as 3 rows for rich:data scroller 
            setScrollerPage (1, "nodeList constructor for object " + this.toString() + " ");  //set to first page on create
        }
    }
    
    

    lastly heres my trace with output (as injection deosnt seem to be working i couldnt get a Log log injected – so did it the hard way.

    i have 4 entries in the database and row count set to 3 – hence two pages to paginate through. this trace is what i get when i am on the last page, and try to click the first or previous links

    04:40:41,277 INFO  [STDOUT] null logger  setMaxScroller pages are 1 on object org.domain.forsterslist.richfaces.datamodel.PaginatingNodeList@6f2403
    04:40:41,277 INFO  [STDOUT] injection failed for nodeList on paginating node list
    04:40:41,277 INFO  [STDOUT] setScroller page called from nodeList constructor for object org.domain.forsterslist.session.NodeList@a54441 
    04:40:41,277 INFO  [STDOUT] null logger  setMaxScroller pages are 1 on object org.domain.forsterslist.session.NodeList@a54441
    04:40:41,277 INFO  [STDOUT] injection failed for nodeHome on paginating node list
    04:40:41,277 INFO  [STDOUT] null logger  setMaxScroller pages are 1 on object org.domain.forsterslist.richfaces.datamodel.PaginatingNodeList_$$_javassist_seam_5@243e1a
    04:40:41,278 INFO  [STDOUT] injection failed for nodeList on paginating node list
    04:40:41,278 INFO  [STDOUT] setScroller page called from nodeList constructor for object org.domain.forsterslist.session.NodeList@1692123 
    04:40:41,278 INFO  [STDOUT] null logger  setMaxScroller pages are 1 on object org.domain.forsterslist.session.NodeList@1692123
    04:40:41,278 INFO  [STDOUT] injection failed for nodeHome on paginating node list
    04:40:41,278 INFO  [STDOUT] setScroller page called from nodeList constructor for object org.domain.forsterslist.session.NodeList@fe8294 
    04:40:41,278 INFO  [STDOUT] null logger  setMaxScroller pages are 1 on object org.domain.forsterslist.session.NodeList@fe8294
    04:40:41,278 INFO  [STDOUT] setScroller page called from nodeList constructor for object org.domain.forsterslist.session.NodeList_$$_javassist_seam_4@12ef96c 
    04:40:41,278 INFO  [STDOUT] null logger  setMaxScroller pages are 1 on object org.domain.forsterslist.session.NodeList_$$_javassist_seam_4@12ef96c
    04:40:41,281 INFO  [STDOUT] Hibernate: 
        select
            node0_.node_id as node1_83_,
            node0_.createdDate as createdD2_83_,
            node0_.name as name83_,
            node0_.version as version83_,
            node0_1_.city as city84_,
            node0_1_.country as country84_,
            node0_1_.county as county84_,
            node0_1_.postCode as postCode84_,
            node0_1_.region as region84_,
            node0_1_.street as street84_,
            node0_1_.streetNumber as streetNu7_84_,
            node0_2_.firstName as firstName85_,
            node0_2_.lastName as lastName85_,
            node0_2_.middleName as middleName85_,
            node0_2_.profile_id as profile5_85_,
            case 
                when node0_1_.node_id is not null then 1 
                when node0_2_.node_id is not null then 2 
                when node0_.node_id is not null then 0 
            end as clazz_ 
        from
            Node node0_ 
        left outer join
            Place node0_1_ 
                on node0_.node_id=node0_1_.node_id 
        left outer join
            Person node0_2_ 
                on node0_.node_id=node0_2_.node_id
    04:40:41,283 INFO  [STDOUT] getScroller page is 1 on object org.domain.forsterslist.richfaces.datamodel.PaginatingNodeList@6f2403
    04:40:41,286 INFO  [STDOUT] Hibernate: 
        select
            count(node0_.node_id) as col_0_0_ 
        from
            Node node0_ limit ?
    04:40:41,287 INFO  [STDOUT] getMaxScroller pages are 2 on object org.domain.forsterslist.richfaces.datamodel.PaginatingNodeList@6f2403
    04:40:41,287 INFO  [STDOUT] getMaxScroller pages are 2 on object org.domain.forsterslist.richfaces.datamodel.PaginatingNodeList@6f2403
    04:40:41,287 INFO  [STDOUT] getMaxScroller pages are 2 on object org.domain.forsterslist.richfaces.datamodel.PaginatingNodeList@6f2403
    04:40:41,288 INFO  [STDOUT] pages to scroll start at [1] for object org.domain.forsterslist.richfaces.datamodel.PaginatingNodeList@6f2403
    04:40:41,288 INFO  [STDOUT] getScroller page is 1 on object org.domain.forsterslist.richfaces.datamodel.PaginatingNodeList@6f2403
    04:40:41,294 INFO  [STDOUT] getScroller page is 2 on object org.domain.forsterslist.richfaces.datamodel.PaginatingNodeList@6f2403
    04:40:41,298 INFO  [STDOUT] getScroller page is 2 on object org.domain.forsterslist.richfaces.datamodel.PaginatingNodeList@6f2403
    04:40:41,298 INFO  [STDOUT] getMaxScroller pages are 2 on object org.domain.forsterslist.richfaces.datamodel.PaginatingNodeList@6f2403
    04:40:41,298 INFO  [STDOUT] getMaxScroller pages are 2 on object org.domain.forsterslist.richfaces.datamodel.PaginatingNodeList@6f2403
    04:40:41,299 INFO  [STDOUT] getMaxScroller pages are 2 on object org.domain.forsterslist.richfaces.datamodel.PaginatingNodeList@6f2403
    04:40:41,299 INFO  [STDOUT] pages to scroll start at [1] for object org.domain.forsterslist.richfaces.datamodel.PaginatingNodeList@6f2403
    04:40:41,299 INFO  [STDOUT] getScroller page is 2 on object org.domain.forsterslist.richfaces.datamodel.PaginatingNodeList@6f2403
    04:40:41,301 INFO  [STDOUT] getMaxScroller pages are 2 on object org.domain.forsterslist.richfaces.datamodel.PaginatingNodeList@6f2403
    
    

    would really like to get a fix for this if i could. Its now hampering the project i was trying to build.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s