2010-03-16

Richfaces DataTable: Server Side Pagination, Sorting and Filtering

PaginatingDataModel.java

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.el.Expression;
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;
import org.richfaces.model.ExtendedFilterField;
import org.richfaces.model.FilterField;
import org.richfaces.model.Modifiable;
import org.richfaces.model.Ordering;
import org.richfaces.model.SortField2;

public abstract class PaginatingDataModel<T, U> extends SerializableDataModel implements Modifiable {

    private static final long serialVersionUID = 2954923950179861809L;

    protected U currentPk;
    
    protected int rowIndex;

    protected boolean descending = true;

    protected String sortField = null;
    
    protected HashMap<String,Object> filterMap = new HashMap<String,Object>();

    protected boolean detached = false;

    protected List<U> wrappedKeys = new ArrayList<U>();

    protected Integer rowCount;

    protected Map<U, T> wrappedData = new HashMap<U, T>();

    /**
     * 
     * @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() {
        detached = false;
    }

    /**
     * 
     * @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 arg0) {
        rowIndex = arg0;
    }

    /**
     * 
     * @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() {
        return rowIndex;
    }

    /**
     * 
     * @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) {
            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, filterMap, 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(filterMap).intValue();
        }
        return rowCount;
    }

    @Override
    public void modify(List<FilterField> filterFields, List<SortField2> sortFields) {
        filterMap.clear();
        SortField2 sortField2 = null;
        String expressionStr = null;
        ExtendedFilterField extendedFilterField = null;
        Expression expression = null;
        String value = null;
        if (sortFields != null && !sortFields.isEmpty()) {
            sortField2 = sortFields.get(0);
            expression = sortField2.getExpression();
            expressionStr = expression.getExpressionString();
            if (!expression.isLiteralText()) {
                expressionStr = expressionStr.replaceAll("[#|$]{1}\\{.*?\\.", "").replaceAll("\\}", "");
            }
            this.sortField = expressionStr;
            if (sortField2.getOrdering() == Ordering.DESCENDING) {
                this.descending = true;
            } else {
                this.descending = false;
            }
        }
        if (filterFields != null && !filterFields.isEmpty()) {
            for (FilterField filterField : filterFields) {
                if (filterField instanceof ExtendedFilterField) {
                    extendedFilterField = (ExtendedFilterField) filterField;
                    value = extendedFilterField.getFilterValue();
                    if (value != null && !value.equals("")) {
                        expression = extendedFilterField.getExpression();
                        expressionStr = expression.getExpressionString();
                        if (!expression.isLiteralText()) {
                            expressionStr = expressionStr.replaceAll("[#|$]{1}\\{.*?\\.", "").replaceAll("\\}", "");
                        }
                        filterMap.put(expressionStr, value);
                    }
                }
            }
        }
    }

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

    /**
     * 
     * @param firstRow
     * 
     * @param numberOfRows
     * 
     * @param sortField
     * 
     * @param descending
     * 
     * @return List<T>
     */
    public abstract List<T> findObjects(int firstRow, int numberOfRows, String sortField, HashMap<String,Object> filterMap, boolean descending);

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

    /**
     * 
     * @return Long
     */
    public abstract Long getNumRecords(HashMap<String,Object> filterMap);

}

PersonPaginatingDataModel.java

import java.util.HashMap;
import java.util.List;

import org.jboss.seam.annotations.In;
import org.jboss.seam.annotations.Name;

import at.ooegkk.svnet.juhealth.entity.Person;
import at.ooegkk.svnet.juhealth.service.PersonService;

@Name("personPaginatingDataModel")
public class PersonPaginatingDataModel extends PaginatingDataModel<Person, Long> {
    
    private static final long serialVersionUID = 1868068053701471139L;
    
    @In(required = false)
    private PersonService personService;

    /**
     * @see PaginatingDataModel#getId
     */
    @Override
    public Long getId(Person person) {
        return person.getId();
    }

    /**
     * @see PaginatingDataModel#findObjects
     */
    @Override
    public List<Person> findObjects(int firstRow, int maxResult, String sortField, HashMap<String,Object> filterMap, boolean descending) {
        return personService.getRange(firstRow, maxResult, sortField, filterMap, descending);
    }

    /**
     * @see PaginatingDataModel#getObjectById(java.lang.Object)
     */
    @Override
    public Person getObjectById(Long id) {
        return personService.getPersonById(id);
    }

    /**
     * 
     * @see PaginatingDataModel#getNumRecords
     */
    @Override
    public Long getNumRecords(HashMap<String,Object> filterMap) {
        return personService.getCount(filterMap);
    }
}

PersonService.java

import java.util.HashMap;
import java.util.List;

import javax.ejb.Remote;

import at.ooegkk.svnet.juhealth.entity.Person;

@Remote
public interface PersonService {

 public List<Person> findAllPersons();
 public void save(Person p);
 public void merge(Person p);
 public void remove(Person p);
 public Person getPersonById(Long id);
 public Long getCount(HashMap<String,Object> filterMap);
 public List<Person> getRange(Integer firstRow, Integer maxResult, String sortField, HashMap<String,Object> filterMap, boolean descending);
    
}

PersonServiceImpl.java

import java.util.HashMap;
import java.util.List;

import javax.ejb.EJB;
import javax.ejb.Stateless;

import at.ooegkk.svnet.juhealth.dao.GenericDAO;
import at.ooegkk.svnet.juhealth.dao.PersonDAO;
import at.ooegkk.svnet.juhealth.entity.Person;
import at.ooegkk.svnet.juhealth.service.PersonService;

@Stateless
@SuppressWarnings("unchecked")
public class PersonServiceImpl implements PersonService {

 @EJB(name="svnet-juhealth-EAR/PersonDAOImpl/local")
 private PersonDAO personDAOImpl;
 
 public List<Person> findAllPersons() {
  List<Person> allPersons = personDAOImpl.findAll(Person.class);
  return allPersons;
 }
 
 public void save(Person person) {
  personDAOImpl.persist(person);
 }

 public void merge(Person person) {
  personDAOImpl.merge(person);
 }
 
 public void remove(Person person) {
  personDAOImpl.remove(person);
 }
 
 public Person getPersonById(Long id) {
  Person p = (Person) personDAOImpl.findById(Person.class, id);
  return p;
 }
 
 public Long getCount(HashMap<String,Object> filterMap) {
        Long count = personDAOImpl.getCount(Person.class, filterMap);
        return count;
    }
    
    public List<Person> getRange(Integer firstRow, Integer maxResult, String sortField, HashMap<String,Object> filterMap, boolean descending) {
        List<Person> list = null;
        if (descending) {
            list = personDAOImpl.findByFilter(Person.class, firstRow, maxResult, sortField, GenericDAO.SORT_ORDER.DESC, filterMap);
        } else {
            list = personDAOImpl.findByFilter(Person.class, firstRow, maxResult, sortField, GenericDAO.SORT_ORDER.ASC, filterMap);
        }
        return list;
    }

}

GenericDAO.java

package at.ooegkk.svnet.juhealth.dao;

import java.util.HashMap;
import java.util.List;
import java.util.Set;

import javax.ejb.Local;

@SuppressWarnings("unchecked")
@Local
public interface GenericDAO {

    public enum SORT_ORDER {
        ASC, DESC
    };

    public Object findById(Class entityClass, long id);

    public List findAll(Class entityClass);

    public List findAll(Class entityClass, String orderByAttribute, SORT_ORDER sortOrder);

    public List findAll(Class entityClass, int maxResult);

    public List findAll(Class entityClass, int firstRow, int maxResult);

    public List findAll(Class entityClass, int maxResult, String orderByAttribute, SORT_ORDER sortOrder);

    public void persist(Object entity, boolean flushImmediate);

    public void persist(Object entity);

    public Object merge(Object entity, boolean flushImmediate);

    public Object merge(Object entity);

    public void remove(Object entity, boolean flushImmediate);

    public void remove(Object entity);

    public Set<String> exludeNames();

    public Long getCount(Class entityClass);
    
    public Long getCount(Class entityClass, HashMap<String,Object> filterMap);

    public List findByFilter(Class entityClass, int firstRow, int maxResult, String orderByAttribute, SORT_ORDER sortOrder,
            HashMap<String, Object> filterMap);

}

GenericDAOImpl.java

import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

import at.ooegkk.svnet.juhealth.dao.GenericDAO;

@SuppressWarnings("unchecked")
@Stateless
public class GenericDAOImpl implements GenericDAO {
 
 @PersistenceContext(unitName="svnet-juhealth")
 private EntityManager entityManager;

 public EntityManager getEntityManager() {
  return entityManager;
 }

 public void setEntityManager(EntityManager entityManager) {
  this.entityManager = entityManager;
 }

 public Object findById(Class entityClass, long id) {
  return getEntityManager().find(entityClass, id);
 }

 public List findAll(Class entityClass) {
  return getEntityManager().createQuery(
    "select e from " + entityClass.getName() + " e ")
    .getResultList();
 }

 public List findAll(Class entityClass, 
   String orderByAttribute, SORT_ORDER sortOrder) {
  String sortOrderString = "desc";
  if (sortOrder == SORT_ORDER.ASC) {
   sortOrderString = "asc";
  }
  return getEntityManager().createQuery(
    "select e from " + entityClass.getName() + " e order by " +
    orderByAttribute + " " + sortOrderString).getResultList();
 }

 public List findAll(Class entityClass, int maxResult) {
  Query q = getEntityManager().createQuery(
    "select e from " + entityClass.getName() + " e ");
  if (maxResult > 0) {
   q.setMaxResults(maxResult);
  }
  return q.getResultList();
 }
 
 public List findAll(Class entityClass, int firstRow, int maxResult) {
        Query q = getEntityManager().createQuery(
                "select e from " + entityClass.getName() + " e ");
        if (firstRow > 0) {
            q.setFirstResult(firstRow);
        }
        if (maxResult > 0) {
            q.setMaxResults(maxResult);
        }
        return q.getResultList();
    }

 public List findAll(Class entityClass, int maxResult,
   String orderByAttribute, SORT_ORDER sortOrder) {
  String sortOrderString = "desc";
  if (sortOrder == SORT_ORDER.ASC) {
   sortOrderString = "asc";
  }
  Query q = getEntityManager().createQuery(
    "select e from " + entityClass.getName() + " e order by "
      + orderByAttribute + " " + sortOrderString);
  if (maxResult > 0) {
   q.setMaxResults(maxResult);
  }
  return q.getResultList();
 }

 public void persist(Object entity, boolean flushImmediate) {
  getEntityManager().persist(entity);
  if (flushImmediate)
   getEntityManager().flush();
 }

 public void persist(Object entity) {
  this.persist(entity, false);
 }

 public Object merge(Object entity, boolean flushImmediate) {
  Object obj = getEntityManager().merge(entity);
  if (flushImmediate)
   getEntityManager().flush();
  return obj;
 }

 public Object merge(Object entity) {
  return this.merge(entity, false);
 }

 public void remove(Object entity, boolean flushImmediate) {
  getEntityManager().remove(getEntityManager().merge(entity));
  if (flushImmediate)
   getEntityManager().flush();
 }

 public void remove(Object entity) {
  this.remove(entity, false);
 }

 public Set<String> exludeNames() {
  return new HashSet<String>();
 }
 
 public Long getCount(Class entityClass) {
        Query q = getEntityManager().createQuery(
                "select count(e) from " + entityClass.getName() + " e ");
        return (Long) q.getSingleResult();
 }
 
 public Long getCount(Class entityClass, HashMap<String,Object> filterMap) {
     StringBuffer query = new StringBuffer();
     query.append("select count(e) from " + entityClass.getName() + " e");
     // where clause
        query.append(this.getWhereClause(filterMap));
        Query q = getEntityManager().createQuery(query.toString());
        // parameter
        q = this.getParameteredQuery(q, filterMap);
     return (Long) q.getSingleResult();
    }
 
 public List findByFilter(Class entityClass, int firstRow, int maxResult,
            String orderByAttribute, SORT_ORDER sortOrder, HashMap<String,Object> filterMap) {
     StringBuffer query = new StringBuffer();
     query.append("SELECT e FROM " + entityClass.getName() + " e");
     // sort order
        String sortOrderString = "desc";
        if (sortOrder == SORT_ORDER.ASC) {
            sortOrderString = "asc";
        }
        // where clause
        query.append(this.getWhereClause(filterMap));
        // order by
        if (orderByAttribute != null) {
            query.append(" ORDER BY " + orderByAttribute + " " + sortOrderString);
        }
        Query q = getEntityManager().createQuery(query.toString());
        // parameter
        q = this.getParameteredQuery(q, filterMap);
        if (firstRow > 0) {
            q.setFirstResult(firstRow);
        }
        if (maxResult > 0) {
            q.setMaxResults(maxResult);
        }
        return q.getResultList();
    }
 
 private String getWhereClause(HashMap<String,Object> filterMap) {
     StringBuffer query = new StringBuffer();
     if (filterMap != null && !filterMap.isEmpty()) {
            query.append(" WHERE");
            boolean first = true;
            for (String column : filterMap.keySet()) {
                if (first) {
                    first = false;
                } else {
                    query.append(" AND");
                }
                if (filterMap.get(column) instanceof String) {
                    query.append(" UPPER(e." + column + ") LIKE :" + column);
                } else {
                    query.append(" e." + column + " = :" + column);
                }
            }
        }
     return query.toString();
 }
 
 private Query getParameteredQuery(Query q, HashMap<String,Object> filterMap) {
     if (filterMap != null && !filterMap.isEmpty()) {
            for (String column : filterMap.keySet()) {
                if (filterMap.get(column) instanceof String) {
                    String value = (String) filterMap.get(column);
                    q.setParameter(column, value.toUpperCase() + "%");
                } else {
                    q.setParameter(column, filterMap.get(column));
                }
            }
        }
     return q;
 }
 
}


PersonDAO.java

import javax.ejb.Local;

@Local
public interface PersonDAO extends GenericDAO {

}

PersonDAOImpl.java

import javax.ejb.Stateless;

import at.ooegkk.svnet.juhealth.dao.PersonDAO;

@Stateless
public class PersonDAOImpl extends GenericDAOImpl implements PersonDAO {
    
}

AbstractEntity.java

import java.io.Serializable;

import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.MappedSuperclass;

@MappedSuperclass
public class AbstractEntity implements Serializable {

 /**
  * 
  */
 private static final long serialVersionUID = 1L;
 
 private Long id;


 @Id
 @GeneratedValue(strategy=GenerationType.AUTO)
 public Long getId() {
  return id;
 }

 public void setId(Long id) {
  this.id = id;
 }

}

Person.java

import java.io.Serializable;
import java.util.Date;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.OneToOne;
import javax.persistence.Table;

import org.hibernate.annotations.Cache;
import org.hibernate.annotations.CacheConcurrencyStrategy;
import org.hibernate.annotations.Cascade;
import org.hibernate.annotations.CascadeType;
import org.hibernate.validator.Length;
import org.hibernate.validator.NotNull;
import org.jboss.seam.annotations.Name;

import at.ooegkk.intranet.example.validator.VSNR;

@Name("person")
@Entity
@Table
@Cache(usage=CacheConcurrencyStrategy.READ_WRITE)
public class Person extends AbstractEntity implements Serializable {
 /**
  * 
  */
 private static final long serialVersionUID = 1L;
 private String vorname;
 private String nachname;
 private String vsnr;
 private Date geburtsdatum;
 private Address adresse = new Address();
 
 @Column
 @NotNull(message="#{messages['field.required']}")
 public String getVorname() {
  return vorname;
 }
 public void setVorname(String vorname) {  
  this.vorname = vorname;
 }
 @Column
 public String getNachname() {
  return nachname;
 }
 public void setNachname(String nachname) {
  this.nachname = nachname;
 }
 @Column
 @NotNull
 @Length(max=10,min=10)
 public String getVsnr() {
  return vsnr;
 }
 public void setVsnr(String vsnr) {
  this.vsnr = vsnr;
 }
 @OneToOne(targetEntity=Address.class)
 @Cascade(value=CascadeType.ALL)
 public Address getAdresse() {
  return adresse;
 }
 public void setAdresse(Address adresse) {
  this.adresse = adresse;
 }
 @Column
 public Date getGeburtsdatum() {
  return geburtsdatum;
 }
 public void setGeburtsdatum(Date geburtsdatum) {
  this.geburtsdatum = geburtsdatum;
 }
}

Address.java

import java.io.Serializable;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Table;

import org.hibernate.validator.NotNull;
import org.jboss.seam.annotations.Name;

@Entity
@Table
@Name("adresse")
public class Address extends AbstractEntity implements Serializable {
 
 /**
  * 
  */
 private static final long serialVersionUID = 1L;
 private Integer plz;
 private String ort;
 private String strasse;
 @Column
 public Integer getPlz() {
  return plz;
 }
 public void setPlz(Integer plz) {
  this.plz = plz;
 }
 @Column
 public String getOrt() {
  return ort;
 }
 public void setOrt(String ort) {
  this.ort = ort;
 }
 @Column
 @NotNull
 public String getStrasse() {
  return strasse;
 }
 public void setStrasse(String strasse) {
  this.strasse = strasse;
 }
}

index.xhtml

<rich:dataTable value="#{personPaginatingDataModel}" var="person" rows="3" reRender="scroller" id="simpletable" width="100%" rowClasses="firstrow,secondrow"<
 <f:facet name="header"<
  <h:outputText value="Personen"/<
 </f:facet<
 <rich:column width="10%"<
  <s:link action="#{personManager.personEdit}"<
   <f:param name="personId" value="#{person.id}"/<
   <img src="/img/icon_bearbeiten.gif" alt="Bearbeiten"/<
  </s:link<
 </rich:column<
 <rich:column width="18%"< 
  <f:facet name="header"<
   <h:outputText value="SVNR"/<
  </f:facet<
  <h:outputText value="#{person.vsnr}"/<
 </rich:column<
 <rich:column sortBy="#{person.vorname}" filterBy="#{person.vorname}" filterEvent="onkeyup" filterValue="#{personManager.currentVornameFilterValue}" width="18%"< 
  <f:facet name="header"<
   <h:outputText value="Vorname"/<
  </f:facet<
  <h:outputText value="#{person.vorname}"/<
 </rich:column<
 <rich:column filterBy="#{person.nachname}" filterEvent="onkeyup" filterValue="#{personManager.currentNachnameFilterValue}" width="18%"< 
  <f:facet name="header"<
   <h:outputText value="Nachname"/<
  </f:facet<
  <h:outputText value="#{person.nachname}"/<
 </rich:column<
 <rich:column width="18%"<
  <f:facet name="header"<
   <h:outputText value="Strasse"/<
  </f:facet<
  <h:outputText value="#{person.adresse.strasse}"/<
 </rich:column< 
 <rich:column width="8%"<
  <f:facet name="header"<
   <h:outputText value="PLZ"/<
  </f:facet<
  <h:outputText value="#{person.adresse.plz}"/<
 </rich:column< 
 <rich:column width="10%"<
  <f:facet name="header"<
   <h:outputText value="Ort"/<
  </f:facet<
  <h:outputText value="#{person.adresse.ort}"/<
 </rich:column<
</rich:dataTable<
<rich:datascroller id="scroller" renderIfSinglePage="false" for="simpletable"<</rich:datascroller<

Edit at 2012/09/26: The reason that some readers were asking for the source code of the PersonManager, I edited this post. Because I have improved the PersonManager since the creation of the first post, I inserted an older version from the repository. Hopefully it is compatible with the other code.

PersonManager

import java.util.List;

import org.jboss.seam.ScopeType;
import org.jboss.seam.annotations.Begin;
import org.jboss.seam.annotations.End;
import org.jboss.seam.annotations.In;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.Out;
import org.jboss.seam.annotations.Scope;
import org.jboss.seam.annotations.web.RequestParameter;

import at.ooegkk.svnet.juhealth.datamodel.PersonPaginatingDataModel;
import at.ooegkk.svnet.juhealth.entity.Person;
import at.ooegkk.svnet.juhealth.service.PersonService;

@Name("personManager")
@Scope(ScopeType.SESSION)
public class PersonManager {

    @In(required = false)
    private PersonService personService;

    @In(create = true)
    @Out(required = false)
    public Person person;

    @Out(required = false)
    public Person searchPerson = new Person();

    @RequestParameter
    public Long personId;

    public String currentVornameFilterValue;

    public String currentNachnameFilterValue;

    @In(create = true)
    public PersonPaginatingDataModel personPaginatingDataModel;

    public PersonManager() {
    }

    public Person getPerson() {
        return person;
    }

    public void setPerson(Person person) {
        this.person = person;
    }

    public Person getSearchPerson() {
        return searchPerson;
    }

    public void setSearchPerson(Person searchPerson) {
        this.searchPerson = searchPerson;
    }

    public PersonPaginatingDataModel getPersonPaginatingDataModel() {
        return personPaginatingDataModel;
    }

    public void setPersonPaginatingDataModel(PersonPaginatingDataModel personPaginatingDataModel) {
        this.personPaginatingDataModel = personPaginatingDataModel;
    }

    public String personenList() {
        return "personenList";
    }

    public String personAdd() {
        return "personAdd";
    }

    @Begin(join = true)
    @End
    public String personSave() throws Exception {
        try {
            if (person.getId() == null) {
                this.personService.save(person);
            } else {
                this.personService.merge(person);
            }
            return "personSave";
        } catch (Exception e) {
            throw e;
        }
    }

    public String personReset() throws Exception {
        try {
            person = new Person();
            return "personReset";
        } catch (Exception e) {
            throw e;
        }
    }

    public String personEdit() throws Exception {
        try {
            person = this.personService.getPersonById(personId);
            return "personEdit";
        } catch (Exception e) {
            throw e;
        }
    }

    public String personenSearch() throws Exception {
        try {
            return "personenSearch";
        } catch (Exception e) {
            throw e;
        }
    }

    public List getPersonen() throws Exception {
        try {
            return this.personService.findAllPersons();
        } catch (Exception e) {
            throw e;
        }
    }

    public String getCurrentVornameFilterValue() {
        return currentVornameFilterValue;
    }

    public void setCurrentVornameFilterValue(String currentVornameFilterValue) {
        this.currentVornameFilterValue = currentVornameFilterValue;
    }

    public String getCurrentNachnameFilterValue() {
        return currentNachnameFilterValue;
    }

    public void setCurrentNachnameFilterValue(String currentNachnameFilterValue) {
        this.currentNachnameFilterValue = currentNachnameFilterValue;
    }

}

15 comments:

  1. Excellent post. Well done. I've been battling with the filtering/sorting unitl I stumbled across this. Cheers, John.

    ReplyDelete
  2. Awesome! This is the first solution that I come across in the net and actually works out of the box. Great job Alex!!!

    ReplyDelete
  3. The only thing that is missing though is an ajaxSingle="false" inside the datascroller.
    This is because by default the performs a client-side paging so ajaxSingle=true.
    In order to get the updated values in the backing bean you need the ajaxSingle="false".

    ReplyDelete
  4. Hi,
    Great post. It works very well. i have a question. I need to show the number of filtered row dynamically on the page but the RowCount gives me always the toral(initial) rowNumber. It seems that the filter values become empty when i call tha RowCount.
    Could you please help me with this problem.
    Thanks in advance

    ReplyDelete
  5. This saved my day. I gave some treatment to couple this on my Model and Service tiers. Works great!

    Thank you very much for sharing!

    ReplyDelete
  6. Hey, thanks for yor example. Can you provide the source of the personManager as well?

    ReplyDelete
  7. Hi guys,

    sorry for the late reply but I was not very active at my blog in the last time ;)

    First of all thank you for your posts.

    @sole: I had the same problem and I have not found a good solution yet. My work-around was that I have a button elsewhere which opens a modal panel that shows the actual row count. If you find a better solution, please let me know!

    @tardy: I will edit the post in the next time, so you can find some code of the personManager as well.

    ReplyDelete
  8. Is there a chance you could post PersonManager just to understand what "filterValue" does in general?
    thx in adv.

    ReplyDelete
  9. Now I have updated the post and it also shows the PersonManager. Hopefully it is compatible with the other code, because I have already improved the shown example. So I took an older version from the repository.

    You can find more information about the filterValue on the demo page of RichFaces:

    http://livedemo.exadel.com/richfaces-demo/richfaces/filteringFeature.jsf?c=filtering&tab=usage

    If you have more questions, please let me know!

    ReplyDelete
  10. Hi,

    I have to implement dynamic pagination in my project and I have a huge data set.I want to use EhCache to store the data I have already obtained from the DB. can you please suggest at what point can I cache the data and retrieve.
    Please help!!!

    ReplyDelete
  11. Hi,

    I also use the dynamic pagination in a project with a huge data set. Because it only retrievs about 15 rows at one time, the caching is not necessary there. My experience is that the most users only need the first 50 rows. Additionally I provide them some fields to minimise the result set. This fields are indexed in the database and so it is possible to reach good performance as well.

    So my first advice is to check if it is really necessary in your case.

    If you like to use the caching mechanism, I would suggest caching in the "Data Access" Layer. When you use a ORM-tool like JPA then I would use the caching opportunities from this tool.
    So it should be possible to use the dynamic pagination like presented in the blog post and add the caching in the function when the data set is retrieved from the database.

    ReplyDelete
  12. Wow... Good good excelent job! Thank you for the solution!

    ReplyDelete
  13. Excellent code, worked out fine with the textbox filters. How can i make it work with
    selectbox/combobox as one of the column filter? Basically i want to filter results based on the value selected in the selectbox/combobox?

    ReplyDelete
  14. @ashokchittela
    Is it possible for you to use Richfaces 4? If yes, then look at the richfaces demo showcase site, there is an example with Arrangeable model and Filtering. At the Filterin page you can find an example with a selectbox.
    By the way I am working on the Richfaces 4 upgrade at the moment. So I will post the new code in the next few days...

    ReplyDelete
  15. Hi Alex, Where can I found the richfaces 4 example please?

    ReplyDelete