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.occurrence; 015 016import org.gbif.api.model.common.DOI; 017import org.gbif.api.model.registry.PostPersist; 018import org.gbif.api.model.registry.PrePersist; 019import org.gbif.api.vocabulary.License; 020 021import java.io.Serializable; 022import java.util.Date; 023import java.util.EnumSet; 024 025import javax.annotation.Nullable; 026import javax.validation.constraints.NotNull; 027import javax.validation.constraints.Null; 028 029import com.fasterxml.jackson.annotation.JsonIgnore; 030import com.fasterxml.jackson.annotation.JsonInclude; 031 032import io.swagger.v3.oas.annotations.Hidden; 033import io.swagger.v3.oas.annotations.media.Schema; 034import lombok.EqualsAndHashCode; 035import lombok.ToString; 036 037import static com.fasterxml.jackson.annotation.JsonInclude.*; 038 039@ToString 040@EqualsAndHashCode 041public class Download implements Serializable { 042 043 /** 044 * Reflects the possibles statuses of a download during its execution. 045 * The download statuses are: 046 * - PREPARING: the download is in a queue, waiting for other downloads to complete 047 * - RUNNING: the download is being processed 048 * - SUCCEEDED: the file is ready to be downloaded 049 * - CANCELLED: the download was cancelled by the user 050 * - KILLED: the download was killed by the workflow engine 051 * - FAILED: the download failed 052 * - SUSPENDED: the download was paused and its execution will be resumed later 053 * - FILE_ERASED: the download was successful, but the download file has been deleted 054 */ 055 @Schema( 056 description = "The status of the download.\n\n" + 057 "* `PREPARING`: the download is in a queue, waiting for other downloads to complete\n" + 058 "* `RUNNING`: the download is being processed\n" + 059 "* `SUCCEEDED`: the download has completed and the file is ready to be downloaded\n" + 060 "* `CANCELLED`: the download was cancelled by the user\n" + 061 "* `KILLED`: the download was killed by the download engine\n" + 062 "* `FAILED`: the download failed\n" + 063 "* `SUSPENDED`: the download was paused and its execution will be resumed later\n" + 064 "* `FILE_ERASED`: the download was successful, but the download file " + 065 "[has since been deleted](https://www.gbif.org/faq?question=for-how-long-will-does-gbif-store-downloads)." 066 ) 067 public enum Status { 068 PREPARING, 069 RUNNING, 070 SUCCEEDED, 071 CANCELLED, 072 KILLED, 073 FAILED, 074 SUSPENDED, 075 FILE_ERASED; 076 077 /** 078 * Statuses that represent a download that that hasn't finished. 079 */ 080 public static final EnumSet<Status> EXECUTING_STATUSES = EnumSet.of(PREPARING, RUNNING, SUSPENDED); 081 082 /** 083 * Statuses that represent a download that that has finished. 084 */ 085 public static final EnumSet<Status> FINISH_STATUSES = EnumSet.of(SUCCEEDED, CANCELLED, KILLED, FAILED, FILE_ERASED); 086 } 087 088 @Schema( 089 description = "The GBIF key assigned to the download.\n\n" + 090 "Note that citations should instead use the download DOI." 091 ) 092 private String key; 093 094 @Schema( 095 description = "The primary Digital Object Identifier (DOI) for this download.", 096 implementation = String.class, 097 pattern = "(10(?:\\.[0-9]+)+)" + "/(.+)" 098 ) 099 private DOI doi; 100 101 @Schema( 102 description = "The licence applied to the download. This is calculated as the most restrictive licence of any " + 103 " of the data included in the download, other data may be less restrictive." 104 ) 105 private License license; 106 107 @Schema( 108 description = "The filter used to request this download." 109 ) 110 private DownloadRequest request; 111 112 @Schema( 113 description = "The time the download request was submitted." 114 ) 115 private Date created; 116 117 @Schema( 118 description = "The time the download was last modified." 119 ) 120 private Date modified; 121 122 @Schema( 123 description = "A time after which the download [may be deleted](https://www.gbif.org/faq?question=for-how-long-will-does-gbif-store-downloads)." 124 ) 125 private Date eraseAfter; 126 127 @Schema( 128 description = "The most recent time when the creator of the download was notified the download is due to be deleted." 129 ) 130 private Date erasureNotification; 131 132 // Documented in the enumeration above 133 private Status status; 134 135 @Schema( 136 description = "A link to download the data, if the status is `SUCCEEDED`." 137 ) 138 private String downloadLink; 139 140 @Schema( 141 description = "The size, in bytes, of the download data." 142 ) 143 private long size; 144 145 @Schema( 146 description = "The total number of occurrence records included in the download." 147 ) 148 private long totalRecords; 149 150 @Schema( 151 description = "The total number of datasets from which occurrence records were drawn." 152 ) 153 @JsonInclude(Include.NON_NULL) 154 private Long numberDatasets; 155 156 @Schema( 157 description = "The total number of organizations from which occurrence records were drawn." 158 ) 159 @JsonInclude(Include.NON_NULL) 160 private Long numberOrganizations; 161 162 @Schema( 163 description = "The total number of publishing countries from which occurrence records were drawn." 164 ) 165 @JsonInclude(Include.NON_NULL) 166 private Long numberPublishingCountries; 167 168 @Hidden 169 private String source; 170 171 /** 172 * @return timestamp when the download was created 173 */ 174 @Null(groups = {PrePersist.class}) 175 @NotNull(groups = {PostPersist.class}) 176 @Nullable 177 public Date getCreated() { 178 return created; 179 } 180 181 /** 182 * @return the downloadLink 183 */ 184 @Nullable 185 public String getDownloadLink() { 186 return downloadLink; 187 } 188 189 /** 190 * @return unique key that can be used in the REST service to retrieve its status 191 */ 192 @NotNull 193 public String getKey() { 194 return key; 195 } 196 197 /** 198 * @return timestamp when the download result was last modified 199 */ 200 @Null(groups = {PrePersist.class}) 201 @NotNull(groups = {PostPersist.class}) 202 @Nullable 203 public Date getModified() { 204 return modified; 205 } 206 207 /** 208 * @return timestamp after which the download file may be erased 209 */ 210 @Nullable 211 public Date getEraseAfter() { 212 return eraseAfter; 213 } 214 215 /** 216 * @return timestamp when a notification of an impending file erasure was sent 217 */ 218 @Nullable 219 public Date getErasureNotification() { 220 return erasureNotification; 221 } 222 223 /** 224 * Request that originated the download. 225 */ 226 @NotNull 227 public DownloadRequest getRequest() { 228 return request; 229 } 230 231 /** 232 * @return the current download status 233 */ 234 @NotNull 235 public Status getStatus() { 236 return status; 237 } 238 239 /** 240 * @return true if the download is completed and a result is available 241 */ 242 @JsonIgnore 243 public boolean isAvailable() { 244 return status == Status.SUCCEEDED; 245 } 246 247 /** 248 * Size in bytes of the produced file. 249 */ 250 public long getSize() { 251 return size; 252 } 253 254 /** 255 * Number of occurrence records in the download file. 256 */ 257 public long getTotalRecords() { 258 return totalRecords; 259 } 260 261 /** 262 * Number of datasets in the download file. 263 */ 264 @Nullable 265 public Long getNumberDatasets() { 266 return numberDatasets; 267 } 268 269 /** 270 * Source of the download to determine how the download was originated. 271 */ 272 public String getSource() { 273 return source; 274 } 275 276 /** 277 * Occurrence download Digital Object Identifier. 278 */ 279 @Nullable 280 public DOI getDoi() { 281 return doi; 282 } 283 284 /** 285 * Get the license assigned to this occurrence download. 286 */ 287 public License getLicense() { 288 return license; 289 } 290 291 public void setCreated(Date created) { 292 this.created = created; 293 } 294 295 public void setDownloadLink(String downloadLink) { 296 this.downloadLink = downloadLink; 297 } 298 299 public void setKey(String key) { 300 this.key = key; 301 } 302 303 public void setDoi(DOI doi) { 304 this.doi = doi; 305 } 306 307 public void setLicense(License license) { 308 this.license = license; 309 } 310 311 public void setModified(Date modified) { 312 this.modified = modified; 313 } 314 315 public void setEraseAfter(Date eraseAfter) { 316 this.eraseAfter = eraseAfter; 317 } 318 319 public void setErasureNotification(Date erasureNotification) { 320 this.erasureNotification = erasureNotification; 321 } 322 323 public void setRequest(DownloadRequest request) { 324 this.request = request; 325 } 326 327 public void setStatus(Status status) { 328 this.status = status; 329 } 330 331 public void setSize(long size) { 332 this.size = size; 333 } 334 335 public void setTotalRecords(long totalRecords) { 336 this.totalRecords = totalRecords; 337 } 338 339 public void setNumberDatasets(Long numberDatasets) { 340 this.numberDatasets = numberDatasets; 341 } 342 343 public void setSource(String source) { 344 this.source = source; 345 } 346 347 @Nullable 348 public Long getNumberOrganizations() { 349 return numberOrganizations; 350 } 351 352 public void setNumberOrganizations(Long numberOrganizations) { 353 this.numberOrganizations = numberOrganizations; 354 } 355 356 @Nullable 357 public Long getNumberPublishingCountries() { 358 return numberPublishingCountries; 359 } 360 361 public void setNumberPublishingCountries(Long numberPublishingCountries) { 362 this.numberPublishingCountries = numberPublishingCountries; 363 } 364}