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.api.model.common.paging;
015
016import java.util.Objects;
017import java.util.StringJoiner;
018
019import io.swagger.v3.oas.annotations.media.Schema;
020
021import static org.gbif.api.model.common.paging.PagingConstants.DEFAULT_PARAM_LIMIT;
022import static org.gbif.api.model.common.paging.PagingConstants.DEFAULT_PARAM_OFFSET;
023
024/**
025 * Generically is a class that contains attributes used by operations that are aware of pagination.
026 * Its properties are final to allow calculations in other setter methods.
027 */
028public class PageableBase implements Pageable {
029
030  @Schema(
031    description = "The offset of the results within all the search results.\n\n" +
032      "Subsequent pages can be retrieved by using `offset + count` as the new offset."
033  )
034  protected long offset;
035
036  @Schema(
037    description = "The limit used.  Note the limit returned may be lower than the limit " +
038      "requested."
039  )
040  protected int limit;
041
042  /**
043   * Default constructor with default paging values.
044   */
045  protected PageableBase() {
046    offset = DEFAULT_PARAM_OFFSET;
047    limit = DEFAULT_PARAM_LIMIT;
048  }
049
050  /**
051   * Full constructor based on a request.
052   *
053   * @throws IllegalArgumentException if negative offset or limit.
054   */
055  protected PageableBase(Pageable page) {
056    setOffset(page.getOffset());
057    setLimit(page.getLimit());
058  }
059
060  /**
061   * Full constructor.
062   *
063   * @throws IllegalArgumentException if negative offset or limit.
064   */
065  protected PageableBase(long offset, int limit) {
066    setOffset(offset);
067    setLimit(limit);
068  }
069
070  /**
071   * Total of rows that are returned.
072   */
073  @Override
074  public int getLimit() {
075    return limit;
076  }
077
078  /**
079   * @param limit the non negative limit to set
080   *
081   * @throws IllegalArgumentException if negative
082   */
083  public void setLimit(int limit) {
084    if (limit < 0) {
085      throw new IllegalArgumentException("Limit cannot be negative");
086    }
087    this.limit = limit;
088  }
089
090  /**
091   * Defines how many items to skip before beginning to return rows.
092   */
093  @Override
094  public long getOffset() {
095    return offset;
096  }
097
098  /**
099   * @param offset the non negative offset to set
100   *
101   * @throws IllegalArgumentException if negative
102   */
103  public void setOffset(long offset) {
104    if (offset < 0) {
105      throw new IllegalArgumentException("Offset cannot be negative");
106    }
107    this.offset = offset;
108  }
109
110  /**
111   * Adds to existing offset, setting offset to zero if it would be negative.
112   *
113   * @param offsetDiff to be added to existing offset.
114   */
115  public void addOffset(long offsetDiff) {
116    offset += offsetDiff;
117    if (offset < 0) {
118      offset = 0;
119    }
120  }
121
122  /**
123   * Utility method to copy paging values.
124   */
125  public void copyPagingValues(Pageable pageable) {
126    limit = pageable.getLimit();
127    offset = pageable.getOffset();
128  }
129
130  @Override
131  public boolean equals(Object o) {
132    if (this == o) {
133      return true;
134    }
135    if (o == null || getClass() != o.getClass()) {
136      return false;
137    }
138    PageableBase that = (PageableBase) o;
139    return offset == that.offset &&
140      limit == that.limit;
141  }
142
143  @Override
144  public int hashCode() {
145    return Objects.hash(offset, limit);
146  }
147
148  @Override
149  public String toString() {
150    return new StringJoiner(", ", PageableBase.class.getSimpleName() + "[", "]")
151      .add("offset=" + offset)
152      .add("limit=" + limit)
153      .toString();
154  }
155}