/*
* FinTP - Financial Transactions Processing Application
* Copyright (C) 2013 Business Information Systems (Allevo) S.R.L.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* or contact Allevo at : 031281 Bucuresti, 23C Calea Vitan, Romania,
* phone +40212554577, office@allevo.ro <mailto:office@allevo.ro>, www.allevo.ro.
*/
package ro.allevo.fintpws.resources;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.Query;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.UriInfo;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.codehaus.jettison.json.JSONException;
import org.codehaus.jettison.json.JSONObject;
import ro.allevo.fintpws.util.JpaFilter;
/**
* @author horia
* @version $Revision: 1.0 $
*/
public class PagedCollection {
/**
* Field logger.
*/
private static Logger logger = LogManager.getLogger(PagedCollection.class
.getName());
/**
* Field PARAM_FILTER. (value is ""filter"")
*/
static final String PARAM_FILTER = "filter";
/**
* Field PARAM_PAGE. (value is ""page"")
*/
static final String PARAM_PAGE = "page";
/**
* Field PARAM_PAGE_SIZE. (value is ""filter"")
*/
static final String PARAM_PAGE_SIZE = "page_size";
/**
* Field FILTER_TOTAL. (value is ""t"")
*/
static final String FILTER_TOTAL = "t";
/**
* Field DEFAULT_PAGE. (value is 1)
*/
private static final int DEFAULT_PAGE = 1;
/**
* Field DEFAULT_PAGE_SIZE. (value is 100)
*/
private static final int DEFAULT_PAGE_SIZE = 100;
/**
* Field MAX_PAGE_SIZE. (value is 100)
*/
private static final int MAX_PAGE_SIZE = 100;
private EntityManager entityManager = null;
protected Class<?> entityClass = null;
private int page;
private int pageSize;
private List<?> items;
private Integer total;
// actual uri info provided by parent resource
private UriInfo uriInfo;
protected Query itemsQuery;
private Query totalQuery;
private boolean needsTotal;
private boolean hasMore;
/**
* Constructor for PagedCollection.
*
* @param uriInfo
* UriInfo
* @param query
* Query
*/
public PagedCollection(UriInfo uriInfo, EntityManager entityManager){
this.entityManager = entityManager;
this.uriInfo = uriInfo;
this.total = 0;
this.page = DEFAULT_PAGE;
this.pageSize = DEFAULT_PAGE_SIZE;
this.hasMore = false;
this.needsTotal = false;
}
/**
* Constructor for PagedCollection.
*
* @param uriInfo
* UriInfo
* @param query
* Query
*/
public PagedCollection(UriInfo uriInfo, Query itemsQuery, Query totalQuery) {
this.uriInfo = uriInfo;
this.itemsQuery = itemsQuery;
this.totalQuery = totalQuery;
this.total = 0;
this.page = DEFAULT_PAGE;
this.pageSize = DEFAULT_PAGE_SIZE;
this.hasMore = false;
this.needsTotal = false;
}
/**
* Constructor for PagedCollection.
*
* @param uriInfo
* UriInfo
* @param query
* Query
*/
public PagedCollection(UriInfo uriInfo, Query itemsQuery, Query totalQuery, EntityManager entityManager, Class<?> entityClass) {
this(uriInfo, itemsQuery, totalQuery);
this.entityManager = entityManager;
this.entityClass = entityClass;
}
/**
* Method filterResource. Changes the items query by performing filter and sort options based on
* query parameters and values.
*/
protected void filterResource(){
MultivaluedMap<String, String> params = uriInfo.getQueryParameters();
if(entityManager != null)
itemsQuery = new JpaFilter(uriInfo, entityManager, entityClass).createQuery();
}
/**
* @param filterName
* @param filterValue
*
* Method filterResource. Changes the items query by performing filter and sort options based on
* query parameters and values. Besides query parameters, the method modifies the query by performing
* an initial filtering based on the two parameters
*/
protected void filterResource(String filterName, String filterValue) {
MultivaluedMap<String, String> params = uriInfo.getQueryParameters();
if(entityManager != null)
itemsQuery = new JpaFilter(uriInfo, entityManager, entityClass,
filterName, filterValue).createQuery();
}
/**
* Method getPage. Sanitizes the input query string parameters [page] and
* [page_size] and retrieves the requested page of items from the database
* page_size is limited to 100 If page is invalid ( not a number, <1 ), the
* first page is returned If page_size is invalid ( not a number, <0, >100
* ), the page size is set to 100
*/
protected void getPage() {
MultivaluedMap<String, String> params = uriInfo.getQueryParameters();
// get page
page = DEFAULT_PAGE;
if (params.containsKey(PARAM_PAGE)) {
try {
page = Integer.parseInt(params.getFirst(PARAM_PAGE));
} catch (NumberFormatException nfe) {
// just ignore garbage, return default page
}
}
// check boundaries
if (page < 1) {
page = DEFAULT_PAGE;
}
// get page size
pageSize = DEFAULT_PAGE_SIZE;
if (params.containsKey(PARAM_PAGE_SIZE)) {
try {
pageSize = Integer.parseInt(params.getFirst(PARAM_PAGE_SIZE));
} catch (NumberFormatException nfe) {
// just ignore garbage, return default page
}
}
// check boundaries
if ((pageSize < 0) || (pageSize > MAX_PAGE_SIZE)) {
pageSize = DEFAULT_PAGE_SIZE;
}
// request +1 item and set has_more metadata if it is returned
itemsQuery.setFirstResult((page - 1) * pageSize);
itemsQuery.setMaxResults(pageSize + 1);
hasMore = false;
// execute the query
items = itemsQuery.getResultList();
if (items.size() == pageSize + 1) {
// remove the extra item
items.remove(pageSize);
hasMore = true;
}
// look for a fiter to request total number of items
needsTotal = false;
if ((params.containsKey(PARAM_FILTER))
&& params.getFirst(PARAM_FILTER).contains(FILTER_TOTAL)) {
needsTotal = true;
// optimization ( if we're on the first page and has_more is false,
// return the count from the selection )
if ((page == DEFAULT_PAGE) && (!hasMore)) {
total = items.size();
} else {
total = ((Long) totalQuery.getSingleResult()).intValue();
}
}
}
/**
* Method asJson.
*
* @return JSONObject
* @throws JSONException
*/
protected JSONObject asJson() throws JSONException {
JSONObject jsonItem = ApiResource.getMetaResource(uriInfo.getPath(),
this.getClass());
if (needsTotal)
jsonItem.put("total", total);
if (hasMore) {
jsonItem.put("has_more", hasMore);
}
return jsonItem;
}
/**
* Method getItems.
*
* @return List<?>
*/
public List<?> getItems() {
return items;
}
/**
* Method getItemsQuery.
*
* @return Query
*/
public Query getItemsQuery() {
return itemsQuery;
}
/**
* Method getTotalQuery.
*
* @return Query
*/
public Query getTotalQuery() {
return totalQuery;
}
/**
* Method setItemsQuery.
*
* @param itemsQuery
* Query
*/
public void setItemsQuery(Query itemsQuery) {
this.itemsQuery = itemsQuery;
}
/**
* Method setTotalQuery.
*
* @param totalQuery
* Query
*/
public void setTotalQuery(Query totalQuery) {
this.totalQuery = totalQuery;
}
/**
* Method has_more
*
* @return boolean
* */
public boolean hasMore() {
return hasMore;
}
/**
* Method getUriInfo.
*
* @return UriInfo
*/
public UriInfo getUriInfo() {
return uriInfo;
}
}