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 ListgetPersonen() 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; } }