001/*
002 * Licensed under the Apache License, Version 2.0 (the "License");
003 * you may not use this file except in compliance with the License.
004 * You may obtain a copy of the License at
005 *
006 *     http://www.apache.org/licenses/LICENSE-2.0
007 *
008 * Unless required by applicable law or agreed to in writing, software
009 * distributed under the License is distributed on an "AS IS" BASIS,
010 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
011 * See the License for the specific language governing permissions and
012 * limitations under the License.
013 */
014package org.gbif.ws.server.provider;
015
016import org.gbif.api.model.common.paging.Pageable;
017import org.gbif.api.model.common.paging.PagingRequest;
018
019import java.util.Map;
020
021import org.slf4j.Logger;
022import org.slf4j.LoggerFactory;
023import org.springframework.web.context.request.WebRequest;
024
025import static org.gbif.api.model.common.paging.PagingConstants.DEFAULT_PARAM_LIMIT;
026import static org.gbif.api.model.common.paging.PagingConstants.DEFAULT_PARAM_OFFSET;
027import static org.gbif.api.model.common.paging.PagingConstants.PARAM_LIMIT;
028import static org.gbif.api.model.common.paging.PagingConstants.PARAM_OFFSET;
029import static org.gbif.ws.util.CommonWsUtils.getFirst;
030
031/**
032 * Provider class that extracts the page size and offset from the query parameters, or provides the default
033 * implementation if necessary.
034 * <p/>
035 * Example resource use:
036 * <pre>
037 * {@code
038 * public List<Checklist> list(Pageable pageable) {
039 *   // do stuff
040 * }
041 * }
042 * </pre>
043 * <p/>
044 */
045public class PageableProvider implements ContextProvider<Pageable> {
046
047  private static final Logger LOG = LoggerFactory.getLogger(PageableProvider.class);
048
049  private final Integer maxPageSize;
050
051  private static final int LIMIT_CAP = 1000;
052
053  public PageableProvider() {
054    this.maxPageSize = LIMIT_CAP;
055  }
056
057  public PageableProvider(Integer maxPageSize) {
058    this.maxPageSize = maxPageSize;
059  }
060
061  @Override
062  public Pageable getValue(WebRequest webRequest) {
063    return getPagingRequest(webRequest, maxPageSize);
064  }
065
066  public static PagingRequest getPagingRequest(WebRequest webRequest, int maxPageSize) {
067    Map<String, String[]> params = webRequest.getParameterMap();
068
069    int limit = DEFAULT_PARAM_LIMIT;
070    String limitParam = getFirst(params, PARAM_LIMIT);
071    if (limitParam != null) {
072      try {
073        limit = Integer.parseInt(limitParam);
074        if (limit < 0) {
075          LOG.info(
076              "Limit parameter was no positive integer [{}]. Using default {}",
077              limitParam,
078              DEFAULT_PARAM_LIMIT);
079          limit = DEFAULT_PARAM_LIMIT;
080        } else if (limit > maxPageSize) {
081          LOG.debug("Limit parameter too high. Use maximum {}", maxPageSize);
082          limit = maxPageSize;
083        }
084      } catch (NumberFormatException e) {
085        LOG.warn(
086            "Unparsable value supplied for limit [{}]. Using default {}",
087            limitParam,
088            DEFAULT_PARAM_LIMIT);
089      }
090    }
091
092    long offset = DEFAULT_PARAM_OFFSET;
093    String offsetParam = getFirst(params, PARAM_OFFSET);
094    if (offsetParam != null) {
095      try {
096        offset = Long.parseLong(offsetParam);
097        if (offset < 0) {
098          LOG.warn(
099              "Offset parameter is a negative integer [{}]. Using default {}",
100              offsetParam,
101              DEFAULT_PARAM_OFFSET);
102          offset = DEFAULT_PARAM_OFFSET;
103        }
104      } catch (NumberFormatException e) {
105        LOG.warn(
106            "Unparsable value supplied for offset [{}]. Using default {}",
107            offsetParam,
108            DEFAULT_PARAM_OFFSET);
109      }
110    }
111    return new PagingRequest(offset, limit);
112  }
113}