001/*
002 * Copyright 2014 Global Biodiversity Information Facility (GBIF)
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package org.gbif.api.model.common.paging;
017
018import java.util.List;
019import javax.annotation.Nullable;
020
021import com.google.common.base.Objects;
022import com.google.common.base.Preconditions;
023import com.google.common.collect.Lists;
024
025/**
026 * Paging response bean.
027 */
028public class PagingResponse<T> extends PageableBase {
029
030  private Boolean endOfRecords;
031  private Long count;
032  private List<T> results = Lists.newArrayList();
033
034  /**
035   * Default constructor with default paging values.
036   */
037  public PagingResponse() {
038  }
039
040  public PagingResponse(Pageable page) {
041    super(page);
042  }
043
044  public PagingResponse(Pageable page, Long count) {
045    super(page);
046    this.count = count;
047  }
048
049  public PagingResponse(long offset, int limit) {
050    super(offset, limit);
051  }
052
053  public PagingResponse(Pageable page, Long count, List<T> results) {
054    super(page);
055    this.results = results;
056    this.count = count;
057  }
058
059  public PagingResponse(long offset, int limit, Long count) {
060    super(offset, limit);
061    this.count = count;
062  }
063
064  public PagingResponse(long offset, int limit, Long count, List<T> results) {
065    super(offset, limit);
066    this.results = results;
067    this.count = count;
068  }
069
070  /**
071   * Gets the count of total results of search operation.
072   */
073  @Nullable
074  public Long getCount() {
075    return count;
076  }
077
078  /**
079   * Sets the total count for all results, not only the ones in this response page.
080   * The method will not set endOfRecords automatically.
081   */
082  public void setCount(Long count) {
083    this.count = count;
084  }
085
086  /**
087   * Gets the list of results.
088   * The type of element of the result are defined by the parameter class type T.
089   *
090   * @return the results list.
091   */
092  public List<T> getResults() {
093    return results;
094  }
095
096  /**
097   * Sets the list of results for the response.
098   * This method will not modify the endOfRecords flag.
099   */
100  public void setResults(List<T> results) {
101    Preconditions.checkNotNull(results, "results can't be null");
102    this.results = results;
103  }
104
105  /**
106   * Flag indicating whether more records do exist.
107   * If the property has never been manually initialised, the flag is determined automatically.
108   * If the total count is set it is used to determine the return value.
109   * If only the result is given, we consider a result size equal to limit as an indication that there are (potentially
110   * at least) more results.
111   *
112   * @return true if all records have been returned otherwise null.
113   */
114  public boolean isEndOfRecords() {
115    if (endOfRecords == null) {
116      // automatically determine end
117      if (count != null) {
118        return count <= offset + limit;
119      } else if (results != null) {
120        return results.size() < limit;
121      } else {
122        // what should this be if we dont have any content?
123        return false;
124      }
125    }
126    return endOfRecords;
127  }
128
129  /**
130   * Manually sets the end of records flag.
131   * Setting the flag to true or false deactivates the automatic calculation in #isEndOfRecords().
132   */
133  public void setEndOfRecords(boolean endOfRecords) {
134    this.endOfRecords = endOfRecords;
135  }
136
137  @Override
138  public boolean equals(Object obj) {
139    if (this == obj) {
140      return true;
141    }
142
143    if (!(obj instanceof PagingResponse)) {
144      return false;
145    }
146
147    PagingResponse<?> that = (PagingResponse<?>) obj;
148    return Objects.equal(count, that.getCount())
149           && Objects.equal(this.results, that.getResults())
150           && Objects.equal(this.getOffset(), that.getOffset())
151           && Objects.equal(this.getLimit(), that.getLimit());
152  }
153
154  @Override
155  public int hashCode() {
156    return Objects.hashCode(count, results, endOfRecords, getLimit(), getOffset());
157  }
158
159  @Override
160  public String toString() {
161    return Objects.toStringHelper(this)
162      .add("count", count)
163      .add("results", results)
164      .add("offset", getOffset())
165      .add("limit", getLimit())
166      .toString();
167  }
168
169}