package org.jpwh.web.dao; import javax.persistence.EntityManager; import javax.persistence.TypedQuery; import javax.persistence.criteria.CriteriaQuery; import javax.persistence.criteria.Path; import javax.persistence.metamodel.Bindable; import javax.persistence.metamodel.SingularAttribute; import java.util.Arrays; public abstract class Page { public static enum SortDirection { ASC, DESC } /* The model holds the size of each page and the number of records shown per page. The value -1 is special, meaning "no limit, show all records". */ protected int size = -1; /* Keeping the number of total records is necessary for some calculations, for example, to determine whether there is actually a "next" page. */ protected long totalRecords; /* Paging always requires a deterministic record order; typically, you sort by a particular attribute of your entity classes in ascending or descending order. The javax.persistence.metamodel.SingularAttribute is an attribute of either an entity or an embeddable class in JPA, it's not a collection (you can't "order by collection" in a query). */ protected SingularAttribute sortAttribute; protected SortDirection sortDirection; /* The allowedAttributes list is set when creating the page model; it restricts the possible sortable attributes to the ones you can handle in your queries. */ protected SingularAttribute[] allowedAttributes; protected Page(int size, long totalRecords, SingularAttribute defaultAttribute, SortDirection defaultDirection, SingularAttribute... allowedAttributes) { this.size = size; this.totalRecords = totalRecords; this.sortDirection = defaultDirection; this.allowedAttributes = allowedAttributes; setSortAttribute(defaultAttribute); } public int getSize() { return size; } public void setSize(int size) { this.size = size; } public long getTotalRecords() { return totalRecords; } public void setTotalRecords(long totalRecords) { this.totalRecords = totalRecords; } public SingularAttribute[] getAllowedAttributes() { return allowedAttributes; } public SingularAttribute getSortAttribute() { return sortAttribute; } public SortDirection getSortDirection() { return sortDirection; } public void setSortDirection(SortDirection sortDirection) { this.sortDirection = sortDirection; } public boolean isSortedAscending() { return SortDirection.ASC.equals(getSortDirection()); } public void setAllowedAttributes(SingularAttribute[] allowedAttributes) { this.allowedAttributes = allowedAttributes; } public void setSortAttribute(SingularAttribute attribute) { if (attribute == null) return; if (!Arrays.asList(allowedAttributes).contains(attribute)) { throw new IllegalArgumentException( "Sorting by attribute not allowed: " + attribute.getName() ); } this.sortAttribute = attribute; } public boolean isMoreThanOneAvailable() { return getTotalRecords() != 0 && getTotalRecords() > getSize(); } public boolean isAttributeDeclaredIn(SingularAttribute attribute, Bindable bindable) { return attribute != null && attribute.getDeclaringType().equals(bindable); } public boolean isApplicableFor(Bindable bindable) { return isAttributeDeclaredIn(getSortAttribute(), bindable); } public void throwIfNotApplicableFor(Path attributePath) { if (!isApplicableFor(attributePath.getModel())) { throw new IllegalArgumentException( "Paging settings/sort attribute are not declared " + "by model of query path: " + attributePath ); } } abstract public TypedQuery createQuery( EntityManager em, CriteriaQuery criteriaQuery, Path attributePath ); }