/*
* eGov suite of products aim to improve the internal efficiency,transparency,
* accountability and the service delivery of the government organizations.
*
* Copyright (C) <2015> eGovernments Foundation
*
* The updated version of eGov suite of products as by eGovernments Foundation
* is available at http://www.egovernments.org
*
* 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
* 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
* http://www.gnu.org/licenses/gpl.html .
*
* In addition to the terms of the GPL license to be adhered to in using this
* program, the following additional terms are to be complied with:
*
* 1) All versions of this program, verbatim or modified must carry this
* Legal Notice.
*
* 2) Any misrepresentation of the origin of the material is prohibited. It
* is required that all modified versions of this material be marked in
* reasonable ways as different from the original version.
*
* 3) This license does not grant any rights to any user of the program
* with regards to rights under trademark law for use of the trade names
* or trademarks of eGovernments Foundation.
*
* In case of any queries, you can reach eGovernments Foundation at contact@egovernments.org.
*/
package org.egov.egf.web.actions.masters;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.struts2.ServletActionContext;
import org.egov.egf.web.actions.masters.JQueryGridActionSupport.MultipleSearchFilter.Rule;
import org.egov.infra.web.struts.actions.BaseFormAction;
import org.egov.infstr.services.Page;
import org.egov.infstr.services.PersistenceService;
import org.hibernate.Criteria;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.Junction;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.Writer;
import java.util.List;
/**
* This will supports Action classes to integrate with jqgrid, to do pagination, searching, filtering (single and group) and ajax
* form saving
**/
public abstract class JQueryGridActionSupport extends BaseFormAction {
@Autowired
@Qualifier("persistenceService")
protected PersistenceService persistenceService;
private static final long serialVersionUID = 1L;
protected static final String ADD = "add";
protected static final String EDIT = "edit";
protected static final String DELETE = "del";
// Forjquery datatable pagination, saving and search filter.
protected Integer id;
protected String oper;
private boolean _search;
private Integer rows;
private Integer page;
private String ord;
private String searchField;
private String searchString;
private String searchOper;
private String sidx;
private String sord;
private String filters;
private Integer totalPages;
private Integer totalRecords;
@Override
public Object getModel() {
return null;
}
/**
* Returns Page {@link Page} result for the given hibernate model class with a mandatory keyFieldName, keyFieldValue.
* Internally this method will apply all filtering and ordering according to the value arrived from jqgrid.
**/
protected Page getPagedResult(final Class<?> clazz, final String keyFieldName, final Object keyFieldValue) {
final Criteria criteria = persistenceService.getSession().createCriteria(clazz);
criteria.add(Restrictions.eq(keyFieldName, keyFieldValue));
applySearchCriteriaIfAny(criteria);
final Criteria countCriteria = persistenceService.getSession().createCriteria(clazz);
countCriteria.add(Restrictions.eq(keyFieldName, keyFieldValue));
countCriteria.setProjection(Projections.rowCount());
totalRecords = ((Number) countCriteria.uniqueResult()).intValue();
return new Page(criteria, page, rows);
}
/**
* Use to send response text directly to the HttpServletResponse
**/
protected void sendAJAXResponse(final String response) {
try {
final HttpServletResponse httpResponse = ServletActionContext.getResponse();
final Writer httpResponseWriter = httpResponse.getWriter();
IOUtils.write(response, httpResponseWriter);
IOUtils.closeQuietly(httpResponseWriter);
} catch (final IOException e) {
LOG.error("Error occurred while processing Ajax response", e);
}
}
/**
* Populates full jqgrid json data string with the given model json data which is used by jqgrid to populated data-table.
**/
protected String constructJqGridResponse(final String jsonData) {
return new StringBuilder().
append("{\"page\":").append(page).
append(",\"total\":").append(getTotalPages()).
append(",\"records\":").append(totalRecords).
append(",\"rows\":").append(jsonData).append("}").toString();
}
/**
* This will get invoked only if user uses search on jqgrid. This is capable applying jqgrid single and group filtering
* searches.
**/
private void applySearchCriteriaIfAny(final Criteria criteria) {
if (_search)
if (StringUtils.isBlank(filters))
criteria.add(applyRestriction());
else {
final MultipleSearchFilter multipleSearchFilter = getMultiSearchFilter();
if (multipleSearchFilter.getGroupOp().equals("AND"))
applyJunctionCriterion(Restrictions.conjunction(), criteria, multipleSearchFilter);
else if (multipleSearchFilter.getGroupOp().equals("OR"))
applyJunctionCriterion(Restrictions.disjunction(), criteria, multipleSearchFilter);
}
criteria.addOrder(applyOrderBy());
}
/**
* Used when search comes from jqgrid group filtering
**/
private void applyJunctionCriterion(final Junction junction, final Criteria criteria,
final MultipleSearchFilter multipleSearchFilter) {
for (final Rule rule : multipleSearchFilter.getRules()) {
searchOper = rule.getOp();
searchField = rule.getField();
searchString = rule.getData();
junction.add(applyRestriction());
}
criteria.add(junction);
}
/**
* Implementing Action need to override this method incase the search criteria contains non string values. eg: <code>
* protected Object convertType (String searchField, String searchValue) {
* Object convertedValue = null;
* if (searchField.equals("accountNumber")) {
* convertedValue = new BigDecimal(searchValue);
* }
* return convertedValue;
* }
* </code>
**/
protected Object convertValueType(final String searchField, final String searchValue) {
return searchValue;
}
/**
* Used to convert jqgrid search operator to hibernate restriction.
**/
private Criterion applyRestriction() {
final Object convertedValue = convertValueType(searchField, searchString);
if (searchOper.equals("eq"))
return Restrictions.eq(searchField, convertedValue);
else if (searchOper.equals("ne"))
return Restrictions.ne(searchField, convertedValue);
if (convertedValue instanceof String) {
if (searchOper.equals("bw"))
return Restrictions.ilike(searchField, searchString + "%");
else if (searchOper.equals("cn"))
return Restrictions.ilike(searchField, "%" + searchString + "%");
else if (searchOper.equals("ew"))
return Restrictions.ilike(searchField, "%" + searchString);
else if (searchOper.equals("bn"))
return Restrictions.not(Restrictions.ilike(searchField, searchString + "%"));
else if (searchOper.equals("en"))
return Restrictions.not(Restrictions.ilike(searchField, "%" + searchString));
else if (searchOper.equals("nc"))
return Restrictions.not(Restrictions.ilike(searchField, "%" + searchString + "%"));
else if (searchOper.equals("in"))
return Restrictions.in(searchField, searchString.split(","));
else if (searchOper.equals("ni"))
return Restrictions.not(Restrictions.in(searchField, searchString.split(",")));
} else if (searchOper.equals("lt"))
return Restrictions.lt(searchField, convertedValue);
else if (searchOper.equals("le"))
return Restrictions.le(searchField, convertedValue);
else if (searchOper.equals("gt"))
return Restrictions.gt(searchField, convertedValue);
else if (searchOper.equals("ge"))
return Restrictions.ge(searchField, convertedValue);
return null;
}
/**
* Used to convert jqgrid order by to hibernate Order by
**/
private Order applyOrderBy() {
final String orderBy = sord == null ? ord : sord;
final String orderByField = sidx == null ? searchField : sidx;
if (orderBy.equals("asc"))
return Order.asc(orderByField);
else
return Order.desc(orderByField);
}
public void setId(final Integer id) {
this.id = id;
}
public void setRows(final Integer rows) {
this.rows = rows;
}
public void setPage(final Integer page) {
this.page = page;
}
public void setOrd(final String ord) {
this.ord = ord;
}
public void setSearchField(final String searchField) {
this.searchField = searchField;
}
public void setSearchString(final String searchString) {
this.searchString = searchString;
}
public void setSearchOper(final String searchOper) {
this.searchOper = searchOper;
}
public void set_search(final boolean _search) {
this._search = _search;
}
public void setSidx(final String sidx) {
this.sidx = sidx;
}
public void setSord(final String sord) {
this.sord = sord;
}
public void setOper(final String oper) {
this.oper = oper;
}
public void setFilters(final String filters) {
this.filters = filters;
}
/**
* This method will convert the incoming group search filter to java class {@link MultipleSearchFilter}
**/
private MultipleSearchFilter getMultiSearchFilter() {
return new GsonBuilder().create().fromJson(filters, MultipleSearchFilter.class);
}
/**
* Returns total number of pages
**/
private Integer getTotalPages() {
if (totalPages == null) {
totalPages = totalRecords / rows;
if (totalRecords % rows != 0)
totalPages++;
}
return totalPages;
}
/**
* Inner class which used with {@link Gson} to convert the group search filter json to a Java class.
**/
class MultipleSearchFilter {
private String groupOp;
private List<Rule> rules;
class Rule {
private String field;
private String op;
private String data;
public String getField() {
return field;
}
public void setField(final String field) {
this.field = field;
}
public String getOp() {
return op;
}
public void setOp(final String op) {
this.op = op;
}
public String getData() {
return data;
}
public void setData(final String data) {
this.data = data;
}
}
public String getGroupOp() {
return groupOp;
}
public void setGroupOp(final String groupOp) {
this.groupOp = groupOp;
}
public List<Rule> getRules() {
return rules;
}
public void setRules(final List<Rule> rules) {
this.rules = rules;
}
}
}