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.ArrayList; 017import java.util.List; 018import java.util.Objects; 019import java.util.StringJoiner; 020 021import javax.annotation.Nullable; 022 023import io.swagger.v3.oas.annotations.media.Schema; 024 025/** 026 * Paging response bean. 027 */ 028public class PagingResponse<T> extends PageableBase { 029 030 @Schema( 031 description = "True if this page of search results is the final page." 032 ) 033 private Boolean endOfRecords; 034 035 @Schema( 036 description = "The total number of records returned by the search." 037 ) 038 private Long count; 039 040 @Schema( 041 description = "Search results." 042 ) 043 private List<T> results = new ArrayList<>(); 044 045 /** 046 * Default constructor with default paging values. 047 */ 048 public PagingResponse() { 049 } 050 051 public PagingResponse(Pageable page) { 052 super(page); 053 } 054 055 public PagingResponse(Pageable page, Long count) { 056 super(page); 057 this.count = count; 058 } 059 060 public PagingResponse(long offset, int limit) { 061 super(offset, limit); 062 } 063 064 public PagingResponse(Pageable page, Long count, List<T> results) { 065 super(page); 066 this.results = results; 067 this.count = count; 068 } 069 070 public PagingResponse(long offset, int limit, Long count) { 071 super(offset, limit); 072 this.count = count; 073 } 074 075 public PagingResponse(long offset, int limit, Long count, List<T> results) { 076 super(offset, limit); 077 this.results = results; 078 this.count = count; 079 } 080 081 /** 082 * Gets the count of total results of search operation. 083 */ 084 @Nullable 085 public Long getCount() { 086 return count; 087 } 088 089 /** 090 * Sets the total count for all results, not only the ones in this response page. 091 * The method will not set endOfRecords automatically. 092 */ 093 public void setCount(Long count) { 094 this.count = count; 095 } 096 097 /** 098 * Gets the list of results. 099 * The type of element of the result are defined by the parameter class type T. 100 * 101 * @return the results list. 102 */ 103 public List<T> getResults() { 104 return results; 105 } 106 107 /** 108 * Sets the list of results for the response. 109 * This method will not modify the endOfRecords flag. 110 */ 111 public void setResults(List<T> results) { 112 Objects.requireNonNull(results, "results can't be null"); 113 this.results = results; 114 } 115 116 /** 117 * Flag indicating whether more records do exist. 118 * If the property has never been manually initialised, the flag is determined automatically. 119 * If the total count is set it is used to determine the return value. 120 * If only the result is given, we consider a result size equal to limit as an indication that there are (potentially 121 * at least) more results. 122 * 123 * @return true if all records have been returned otherwise null. 124 */ 125 public boolean isEndOfRecords() { 126 if (endOfRecords == null) { 127 // automatically determine end 128 if (count != null) { 129 return count <= offset + limit; 130 } else if (results != null) { 131 return results.size() < limit; 132 } else { 133 // what should this be if we dont have any content? 134 return false; 135 } 136 } 137 return endOfRecords; 138 } 139 140 /** 141 * Manually sets the end of records flag. 142 * Setting the flag to true or false deactivates the automatic calculation in #isEndOfRecords(). 143 */ 144 public void setEndOfRecords(boolean endOfRecords) { 145 this.endOfRecords = endOfRecords; 146 } 147 148 @Override 149 public boolean equals(Object o) { 150 if (this == o) { 151 return true; 152 } 153 if (o == null || getClass() != o.getClass()) { 154 return false; 155 } 156 if (!super.equals(o)) { 157 return false; 158 } 159 PagingResponse<?> that = (PagingResponse<?>) o; 160 return Objects.equals(endOfRecords, that.endOfRecords) && 161 Objects.equals(count, that.count) && 162 Objects.equals(results, that.results); 163 } 164 165 @Override 166 public int hashCode() { 167 return Objects.hash(super.hashCode(), endOfRecords, count, results); 168 } 169 170 @Override 171 public String toString() { 172 return new StringJoiner(", ", PagingResponse.class.getSimpleName() + "[", "]") 173 .add("count=" + count) 174 .add("results=" + results) 175 .add("offset=" + offset) 176 .add("limit=" + limit) 177 .toString(); 178 } 179}