From f107d185e84020cdbc11deccf66f549b2b957b8f Mon Sep 17 00:00:00 2001 From: Keith Woodlock Date: Thu, 2 May 2013 01:56:32 +0100 Subject: [PATCH] MIFOSX-321: tidy up some of backend implementation for client pagination and sorting example. --- .../core/service}/Page.java | 23 ++------ .../core/service}/PaginationHelper.java | 13 ++-- .../client/api/ClientsApiResource.java | 21 +++---- .../service/ClientReadPlatformService.java | 6 +- .../ClientReadPlatformServiceImpl.java | 59 ++++++++----------- .../group/service/SearchParameters.java | 57 ++++++++++++++++-- 6 files changed, 102 insertions(+), 77 deletions(-) rename mifosng-provider/src/main/java/org/mifosplatform/{portfolio/pagination => infrastructure/core/service}/Page.java (55%) rename mifosng-provider/src/main/java/org/mifosplatform/{portfolio/pagination => infrastructure/core/service}/PaginationHelper.java (72%) diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/pagination/Page.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/core/service/Page.java similarity index 55% rename from mifosng-provider/src/main/java/org/mifosplatform/portfolio/pagination/Page.java rename to mifosng-provider/src/main/java/org/mifosplatform/infrastructure/core/service/Page.java index b5ebb9d89..2c51f92ab 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/pagination/Page.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/core/service/Page.java @@ -3,36 +3,25 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this file, * You can obtain one at http://mozilla.org/MPL/2.0/. */ -package org.mifosplatform.portfolio.pagination; +package org.mifosplatform.infrastructure.core.service; -import java.util.ArrayList; import java.util.List; -import com.google.gson.Gson; - public class Page { - private int totalFilteredRecords; - private List pageItems = new ArrayList(); + private final int totalFilteredRecords; + private final List pageItems; - public void setPageItems(List pageItems) { + public Page(final List pageItems, final int totalFilteredRecords) { this.pageItems = pageItems; + this.totalFilteredRecords = totalFilteredRecords; } public int getTotalFilteredRecords() { return this.totalFilteredRecords; } - public void setTotalFilteredRecords(int totalFilteredRecords) { - this.totalFilteredRecords = totalFilteredRecords; - } - public List getPageItems() { return pageItems; } - - @Override - public String toString() { - return new Gson().toJson(this); - } -} +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/pagination/PaginationHelper.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/core/service/PaginationHelper.java similarity index 72% rename from mifosng-provider/src/main/java/org/mifosplatform/portfolio/pagination/PaginationHelper.java rename to mifosng-provider/src/main/java/org/mifosplatform/infrastructure/core/service/PaginationHelper.java index 3cf4692e9..1464108f2 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/pagination/PaginationHelper.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/core/service/PaginationHelper.java @@ -3,7 +3,9 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this file, * You can obtain one at http://mozilla.org/MPL/2.0/. */ -package org.mifosplatform.portfolio.pagination; +package org.mifosplatform.infrastructure.core.service; + +import java.util.List; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.RowMapper; @@ -13,16 +15,11 @@ public class PaginationHelper { public Page fetchPage(final JdbcTemplate jt, final String sqlCountRows, final String sqlFetchRows, final Object args[], final RowMapper rowMapper) { - final Page page = new Page(); - - page.getPageItems().addAll(jt.query(sqlFetchRows, args, rowMapper)); + final List items = jt.query(sqlFetchRows, args, rowMapper); // determine how many rows are available final int totalFilteredRecords = jt.queryForInt(sqlCountRows); - page.setTotalFilteredRecords(totalFilteredRecords); - - return page; + return new Page(items, totalFilteredRecords); } - } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/api/ClientsApiResource.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/api/ClientsApiResource.java index 4f2d7d08a..5165ac244 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/api/ClientsApiResource.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/api/ClientsApiResource.java @@ -33,6 +33,7 @@ import org.mifosplatform.infrastructure.core.data.CommandProcessingResult; import org.mifosplatform.infrastructure.core.exception.UnrecognizedQueryParamException; import org.mifosplatform.infrastructure.core.serialization.ApiRequestJsonSerializationSettings; import org.mifosplatform.infrastructure.core.serialization.ToApiJsonSerializer; +import org.mifosplatform.infrastructure.core.service.Page; import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext; import org.mifosplatform.organisation.office.data.OfficeData; import org.mifosplatform.organisation.office.service.OfficeReadPlatformService; @@ -40,7 +41,6 @@ import org.mifosplatform.portfolio.client.data.ClientAccountSummaryCollectionDat import org.mifosplatform.portfolio.client.data.ClientData; import org.mifosplatform.portfolio.client.service.ClientReadPlatformService; import org.mifosplatform.portfolio.group.service.SearchParameters; -import org.mifosplatform.portfolio.pagination.Page; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Component; @@ -90,18 +90,19 @@ public class ClientsApiResource { @GET @Consumes({ MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_JSON }) - public String retrieveAllPaginatedAndSorted(@QueryParam("sqlSearch") final String sqlSearch, - @QueryParam("officeId") final Long officeId, @QueryParam("externalId") final String externalId, - @QueryParam("displayName") final String displayName, @QueryParam("firstName") final String firstname, - @QueryParam("lastName") final String lastname, @QueryParam("underHierarchy") final String hierarchy, - @QueryParam("offset") final int offset, @QueryParam("limit") final int limit, @QueryParam("orderBy") final String orderBy, + public String retrieveAll(@QueryParam("sqlSearch") final String sqlSearch, @QueryParam("officeId") final Long officeId, + @QueryParam("externalId") final String externalId, @QueryParam("displayName") final String displayName, + @QueryParam("firstName") final String firstname, @QueryParam("lastName") final String lastname, + @QueryParam("underHierarchy") final String hierarchy, @QueryParam("offset") final Integer offset, + @QueryParam("limit") final Integer limit, @QueryParam("orderBy") final String orderBy, @QueryParam("sortOrder") final String sortOrder) { + context.authenticatedUser().validateHasReadPermission(ClientApiConstants.CLIENT_RESOURCE_NAME); final SearchParameters searchParameters = SearchParameters.forClients(sqlSearch, officeId, externalId, displayName, firstname, - lastname, hierarchy); - Page clientData = this.clientReadPlatformService.retrieveAllPaginatedAndSorted(searchParameters, offset, limit, - orderBy, sortOrder); + lastname, hierarchy, offset, limit, orderBy, sortOrder); + + final Page clientData = this.clientReadPlatformService.retrieveAll(searchParameters); return this.toApiJsonSerializer.serialize(clientData); } @@ -123,7 +124,7 @@ public class ClientsApiResource { return this.toApiJsonSerializer.serialize(settings, clientData, ClientApiConstants.CLIENT_RESPONSE_DATA_PARAMETERS); } - + @POST @Consumes({ MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_JSON }) diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/service/ClientReadPlatformService.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/service/ClientReadPlatformService.java index 26b0de42e..fc87e6cdf 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/service/ClientReadPlatformService.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/service/ClientReadPlatformService.java @@ -7,19 +7,17 @@ package org.mifosplatform.portfolio.client.service; import java.util.Collection; +import org.mifosplatform.infrastructure.core.service.Page; import org.mifosplatform.portfolio.client.data.ClientAccountSummaryCollectionData; import org.mifosplatform.portfolio.client.data.ClientAccountSummaryData; import org.mifosplatform.portfolio.client.data.ClientData; import org.mifosplatform.portfolio.group.service.SearchParameters; -import org.mifosplatform.portfolio.pagination.Page; public interface ClientReadPlatformService { ClientData retrieveTemplate(); - Collection retrieveAll(SearchParameters searchParameters); - - Page retrieveAllPaginatedAndSorted(SearchParameters searchParameters, int offset, int limit, String sortBy, String sortOrder); + Page retrieveAll(SearchParameters searchParameters); ClientData retrieveOne(Long clientId); diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/service/ClientReadPlatformServiceImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/service/ClientReadPlatformServiceImpl.java index 13386e4a8..50c255ef9 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/service/ClientReadPlatformServiceImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/service/ClientReadPlatformServiceImpl.java @@ -16,6 +16,8 @@ import org.joda.time.LocalDate; import org.mifosplatform.infrastructure.core.api.ApiParameterHelper; import org.mifosplatform.infrastructure.core.data.EnumOptionData; import org.mifosplatform.infrastructure.core.domain.JdbcSupport; +import org.mifosplatform.infrastructure.core.service.Page; +import org.mifosplatform.infrastructure.core.service.PaginationHelper; import org.mifosplatform.infrastructure.core.service.TenantAwareRoutingDataSource; import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext; import org.mifosplatform.organisation.office.data.OfficeData; @@ -29,8 +31,6 @@ import org.mifosplatform.portfolio.group.data.GroupGeneralData; import org.mifosplatform.portfolio.group.service.SearchParameters; import org.mifosplatform.portfolio.loanaccount.data.LoanStatusEnumData; import org.mifosplatform.portfolio.loanproduct.service.LoanEnumerations; -import org.mifosplatform.portfolio.pagination.Page; -import org.mifosplatform.portfolio.pagination.PaginationHelper; import org.mifosplatform.useradministration.domain.AppUser; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.dao.EmptyResultDataAccessException; @@ -46,6 +46,7 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService private final OfficeReadPlatformService officeReadPlatformService; // data mappers + private final PaginationHelper paginationHelper = new PaginationHelper(); private final ClientMapper clientMapper = new ClientMapper(); private final ClientLookupMapper lookupMapper = new ClientLookupMapper(); private final ClientMembersOfGroupMapper membersOfGroupMapper = new ClientMembersOfGroupMapper(); @@ -72,49 +73,41 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService } @Override - public Collection retrieveAll(final SearchParameters searchParameters) { + public Page retrieveAll(final SearchParameters searchParameters) { final AppUser currentUser = context.authenticatedUser(); final String hierarchy = currentUser.getOffice().getHierarchy(); final String hierarchySearchString = hierarchy + "%"; - String sql = "select " + this.clientMapper.schema() + " where o.hierarchy like ?"; + StringBuilder sqlBuilder = new StringBuilder(200); + sqlBuilder.append("select SQL_CALC_FOUND_ROWS "); + sqlBuilder.append(this.clientMapper.schema()); + sqlBuilder.append(" where o.hierarchy like ?"); final String extraCriteria = buildSqlStringFromClientCriteria(searchParameters); - if (StringUtils.isNotBlank(extraCriteria)) sql += " and (" + extraCriteria + ")"; + if (StringUtils.isNotBlank(extraCriteria)) { + sqlBuilder.append(" and (").append(extraCriteria).append(")"); + } - sql += " order by c.display_name ASC, c.account_no ASC"; + // DONT order by default - just use database natural ordering so doesnt + // have to scan entire database table. + // sql += " order by c.display_name ASC, c.account_no ASC"; + if (searchParameters.isOrderByRequested()) { + sqlBuilder.append(" order by ").append(searchParameters.getOrderBy()).append(' ').append(searchParameters.getSortOrder()); + } - return this.jdbcTemplate.query(sql, clientMapper, new Object[] { hierarchySearchString }); - } + if (searchParameters.isLimited()) { + sqlBuilder.append(" limit ").append(searchParameters.getLimit()); + } - @Override - public Page retrieveAllPaginatedAndSorted(final SearchParameters searchParameters, final int offset, final int limit, - final String orderby, final String sortOrder) { + if (searchParameters.isOffset()) { + sqlBuilder.append(" offset ").append(searchParameters.getOffset()); + } - final AppUser currentUser = context.authenticatedUser(); - final String hierarchy = currentUser.getOffice().getHierarchy(); - final String hierarchySearchString = hierarchy + "%"; - - String sql = "select SQL_CALC_FOUND_ROWS " + this.clientMapper.schema() + " where o.hierarchy like ?"; - - final String extraCriteria = buildSqlStringFromClientCriteria(searchParameters); - - if (StringUtils.isNotBlank(extraCriteria)) sql += " and (" + extraCriteria + ")"; - - if (orderby != null && sortOrder != null) { - if (!orderby.equalsIgnoreCase("") && !sortOrder.equalsIgnoreCase("")) { - sql += " order by " + orderby + " " + sortOrder; - } - } else - sql += " order by c.display_name ASC, c.account_no ASC"; - - PaginationHelper ph = new PaginationHelper(); - String sqlCountRows = "SELECT FOUND_ROWS()"; - String sqlFetchRows = sql; - if (limit != 0) sqlFetchRows = sql + " LIMIT " + limit + " OFFSET " + offset; - return ph.fetchPage(jdbcTemplate, sqlCountRows, sqlFetchRows, new Object[] { hierarchySearchString }, clientMapper); + final String sqlCountRows = "SELECT FOUND_ROWS()"; + return this.paginationHelper.fetchPage(this.jdbcTemplate, sqlCountRows, sqlBuilder.toString(), + new Object[] { hierarchySearchString }, this.clientMapper); } private String buildSqlStringFromClientCriteria(final SearchParameters searchParameters) { diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/group/service/SearchParameters.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/group/service/SearchParameters.java index 75dc1563f..28be577fb 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/group/service/SearchParameters.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/group/service/SearchParameters.java @@ -1,6 +1,8 @@ package org.mifosplatform.portfolio.group.service; -public class SearchParameters { +import org.apache.commons.lang.StringUtils; + +public final class SearchParameters { private final String sqlSearch; private final Long officeId; @@ -9,19 +11,32 @@ public class SearchParameters { private final String hierarchy; private final String firstname; private final String lastname; + private final Integer offset; + private final Integer limit; + private final String orderBy; + private final String sortOrder; public static SearchParameters from(final String sqlSearch, final Long officeId, final String externalId, final String name, final String hierarchy) { - return new SearchParameters(sqlSearch, officeId, externalId, name, hierarchy, null, null); + return new SearchParameters(sqlSearch, officeId, externalId, name, hierarchy, null, null, null, null, null, null); } public static SearchParameters forClients(final String sqlSearch, final Long officeId, final String externalId, - final String displayName, final String firstname, final String lastname, final String hierarchy) { - return new SearchParameters(sqlSearch, officeId, externalId, displayName, hierarchy, firstname, lastname); + final String displayName, final String firstname, final String lastname, final String hierarchy, final Integer offset, + final Integer limit, final String orderBy, final String sortOrder) { + + Integer maxLimitAllowed = 200; + if (limit != null && limit < maxLimitAllowed && limit > 0) { + maxLimitAllowed = limit; + } + + return new SearchParameters(sqlSearch, officeId, externalId, displayName, hierarchy, firstname, lastname, offset, maxLimitAllowed, + orderBy, sortOrder); } private SearchParameters(final String sqlSearch, final Long officeId, final String externalId, final String name, - final String hierarchy, final String firstname, final String lastname) { + final String hierarchy, final String firstname, final String lastname, final Integer offset, final Integer limit, + final String orderBy, final String sortOrder) { this.sqlSearch = sqlSearch; this.officeId = officeId; this.externalId = externalId; @@ -29,6 +44,14 @@ public class SearchParameters { this.hierarchy = hierarchy; this.firstname = firstname; this.lastname = lastname; + this.offset = offset; + this.limit = limit; + this.orderBy = orderBy; + this.sortOrder = sortOrder; + } + + public boolean isOrderByRequested() { + return StringUtils.isNotBlank(this.orderBy) && StringUtils.isNotBlank(this.sortOrder); } public String getSqlSearch() { @@ -58,4 +81,28 @@ public class SearchParameters { public String getLastname() { return this.lastname; } + + public Integer getOffset() { + return this.offset; + } + + public Integer getLimit() { + return this.limit; + } + + public String getOrderBy() { + return this.orderBy; + } + + public String getSortOrder() { + return this.sortOrder; + } + + public boolean isLimited() { + return this.limit != null && this.limit.intValue() > 0; + } + + public boolean isOffset() { + return this.offset != null; + } } \ No newline at end of file