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.util.iterables;
015
016import java.util.Collections;
017import java.util.Date;
018import java.util.Map;
019import java.util.Optional;
020import java.util.UUID;
021import java.util.function.Function;
022import javax.annotation.Nullable;
023import org.gbif.api.model.collections.Institution;
024import org.gbif.api.model.collections.descriptors.Descriptor;
025import org.gbif.api.model.collections.request.CollectionSearchRequest;
026import org.gbif.api.model.collections.request.DescriptorSearchRequest;
027import org.gbif.api.model.collections.request.InstitutionSearchRequest;
028import org.gbif.api.model.collections.view.CollectionView;
029import org.gbif.api.model.common.paging.Pageable;
030import org.gbif.api.model.common.paging.PagingConstants;
031import org.gbif.api.model.common.paging.PagingRequest;
032import org.gbif.api.model.common.paging.PagingResponse;
033import org.gbif.api.model.occurrence.DownloadStatistics;
034import org.gbif.api.model.registry.Dataset;
035import org.gbif.api.model.registry.DatasetOccurrenceDownloadUsage;
036import org.gbif.api.model.registry.Node;
037import org.gbif.api.model.registry.Organization;
038import org.gbif.api.model.registry.search.DatasetSearchRequest;
039import org.gbif.api.model.registry.search.DatasetSearchResult;
040import org.gbif.api.service.collections.CollectionService;
041import org.gbif.api.service.collections.DescriptorsService;
042import org.gbif.api.service.collections.InstitutionService;
043import org.gbif.api.service.registry.DatasetSearchService;
044import org.gbif.api.service.registry.DatasetService;
045import org.gbif.api.service.registry.InstallationService;
046import org.gbif.api.service.registry.NetworkService;
047import org.gbif.api.service.registry.NodeService;
048import org.gbif.api.service.registry.OccurrenceDownloadService;
049import org.gbif.api.service.registry.OrganizationService;
050import org.gbif.api.vocabulary.Country;
051import org.gbif.api.vocabulary.DatasetType;
052import org.slf4j.Logger;
053import org.slf4j.LoggerFactory;
054
055/** Factory constructing registry entity iterables using specific pagers under the hood. */
056@SuppressWarnings("unused")
057public class Iterables {
058  private static final Logger LOG = LoggerFactory.getLogger(Iterables.class);
059
060  /** Private default constructor. */
061  private Iterables() {
062    // empty private constructor
063  }
064
065  /**
066   * @param key a valid dataset, organization or installation key. If null all datasets will be
067   *     iterated over
068   * @throws IllegalArgumentException if given key is not existing
069   */
070  public static Iterable<Dataset> datasets(
071      @Nullable UUID key,
072      @Nullable DatasetType type,
073      DatasetService ds,
074      OrganizationService os,
075      InstallationService is,
076      NetworkService ns,
077      NodeService nos) {
078    return datasets(key, type, ds, os, is, ns, nos, PagingConstants.DEFAULT_PARAM_LIMIT);
079  }
080
081  /**
082   * Returns a dataset iterable by testing the given registry key first to see whether it is a
083   * dataset, organization or installation. In case of an organization key the published datasets
084   * will be returned.
085   *
086   * @param key a valid dataset, organization or installation key. If null all datasets will be
087   *     iterated over
088   * @param pageSize to use when talking to the registry
089   * @throws IllegalArgumentException if given key is not existing
090   */
091  public static Iterable<Dataset> datasets(
092      @Nullable UUID key,
093      @Nullable DatasetType type,
094      DatasetService ds,
095      OrganizationService os,
096      InstallationService is,
097      NetworkService ns,
098      NodeService nos,
099      int pageSize) {
100    if (key == null) {
101      LOG.info("Iterate over all {} datasets", type == null ? "" : type);
102      return new DatasetPager(ds, type, pageSize);
103
104    } else if (isDataset(key, ds)) {
105      LOG.info("Iterate over dataset {}", key);
106      return Collections.singletonList(ds.get(key));
107
108    } else if (isOrganization(key, os)) {
109      LOG.info("Iterate over all {} datasets published by {}", type == null ? "" : type, key);
110      return new OrgPublishingPager(os, key, type, pageSize);
111
112    } else if (isInstallation(key, is)) {
113      LOG.info(
114          "Iterate over all {} datasets hosted by installation {}", type == null ? "" : type, key);
115      return new InstallationPager(is, key, type, pageSize);
116
117    } else if (isNode(key, nos)) {
118      LOG.info("Iterate over all {} datasets endorsed by node {}", type == null ? "" : type, key);
119      return new NetworkPager(ns, key, type, pageSize);
120
121    } else if (isNetwork(key, ns)) {
122      LOG.info(
123          "Iterate over all {} datasets belonging to network {}", type == null ? "" : type, key);
124      return new NodeDatasetPager(nos, key, type, pageSize);
125    }
126    throw new IllegalArgumentException("Given key is no valid GBIF registry key: " + key);
127  }
128
129  /**
130   * @param type an optional filter to just include the given dataset type
131   */
132  public static Iterable<Dataset> datasets(@Nullable DatasetType type, DatasetService service) {
133    LOG.info("Iterate over all {} datasets", type == null ? "" : type);
134    return new DatasetPager(service, type, PagingConstants.DEFAULT_PARAM_LIMIT);
135  }
136
137  /** Iterates over dataset search results. */
138  public static Iterable<DatasetSearchResult> datasetSearchResults(
139      @Nullable DatasetSearchRequest datasetSearchRequest,
140      DatasetSearchService datasetSearchService,
141      @Nullable Integer limit) {
142    return new DatasetSearchResultsPager(
143        datasetSearchService,
144        datasetSearchRequest,
145        Optional.ofNullable(limit).orElse(PagingConstants.DEFAULT_PARAM_LIMIT));
146  }
147
148  /**
149   * @param key a valid organization key
150   * @param type an optional filter to just include the given dataset type
151   */
152  public static Iterable<Dataset> publishedDatasets(
153      UUID key, @Nullable DatasetType type, OrganizationService service) {
154    LOG.info("Iterate over all {} datasets published by {}", type == null ? "" : type, key);
155    return new OrgPublishingPager(service, key, type, PagingConstants.DEFAULT_PARAM_LIMIT);
156  }
157
158  /**
159   * @param key a valid organization key
160   * @param type an optional filter to just include the given dataset type
161   */
162  public static Iterable<Dataset> hostedDatasets(
163      UUID key, @Nullable DatasetType type, OrganizationService service) {
164    LOG.info(
165        "Iterate over all {} datasets hosted by organization {}", type == null ? "" : type, key);
166    return new OrgHostingPager(service, key, type, PagingConstants.DEFAULT_PARAM_LIMIT);
167  }
168
169  /**
170   * @param key a valid installation key
171   * @param type an optional filter to just include the given dataset type
172   */
173  public static Iterable<Dataset> hostedDatasets(
174      UUID key, @Nullable DatasetType type, InstallationService service) {
175    LOG.info(
176        "Iterate over all {} datasets hosted by installation {}", type == null ? "" : type, key);
177    return new InstallationPager(service, key, type, PagingConstants.DEFAULT_PARAM_LIMIT);
178  }
179
180  /**
181   * @param key a valid dataset key
182   */
183  public static Iterable<Dataset> constituentDatasets(UUID key, DatasetService service) {
184    LOG.info("Iterate over all constituent datasets of {}", key);
185    return new DatasetConstituentPager(service, key, PagingConstants.DEFAULT_PARAM_LIMIT);
186  }
187
188  /**
189   * Iterates over all constituents of a given network.
190   *
191   * @param key a valid network key
192   * @param type an optional filter to just include the given dataset type
193   */
194  public static Iterable<Dataset> networkDatasets(
195      UUID key, @Nullable DatasetType type, NetworkService service) {
196    LOG.info("Iterate over all {} datasets belonging to network {}", type == null ? "" : type, key);
197    return new NetworkPager(service, key, type, PagingConstants.DEFAULT_PARAM_LIMIT);
198  }
199
200  /**
201   * @param nodeKey a valid endorsing node key
202   * @param type an optional filter to just include the given dataset type
203   */
204  public static Iterable<Dataset> endorsedDatasets(
205      UUID nodeKey, @Nullable DatasetType type, NodeService service) {
206    LOG.info("Iterate over all {} datasets endorsed by node {}", type == null ? "" : type, nodeKey);
207    return new NodeDatasetPager(service, nodeKey, type, PagingConstants.DEFAULT_PARAM_LIMIT);
208  }
209
210  /**
211   * @param pager producer function of next page response
212   * @return a dataset iterable based on producer function
213   */
214  public static Iterable<Dataset> datasetsIterable(
215      Function<PagingRequest, PagingResponse<Dataset>> pager) {
216    return new DatasetBasePager(null, PagingConstants.DEFAULT_PARAM_LIMIT) {
217      @Override
218      public PagingResponse<Dataset> nextPage(PagingRequest page) {
219        return pager.apply(page);
220      }
221    };
222  }
223
224  /**
225   * @param country an optional country filter
226   */
227  public static Iterable<Organization> organizations(
228      @Nullable Country country, OrganizationService service) {
229    LOG.info("Iterate over all organizations {}", country == null ? "" : "from country " + country);
230    return new OrganizationPager(service, country, PagingConstants.DEFAULT_PARAM_LIMIT);
231  }
232
233  /**
234   * @param nodeKey a valid endorsing node key
235   */
236  public static Iterable<Organization> endorsedOrganizations(UUID nodeKey, NodeService service) {
237    LOG.info("Iterate over all organizations endorsed by node {}", nodeKey);
238    return new NodeOrganizationPager(service, nodeKey, PagingConstants.DEFAULT_PARAM_LIMIT);
239  }
240
241  /** Iterate over all endorsing nodes */
242  public static Iterable<Node> nodes(NodeService service) {
243    LOG.info("Iterate over all nodes");
244    return new NodePager(service, PagingConstants.DEFAULT_PARAM_LIMIT);
245  }
246
247  /**
248   * Iterable for {@link OccurrenceDownloadService#getDownloadStatistics(Date, Date, Country, UUID,
249   * UUID, Pageable)}.
250   */
251  public static Iterable<DownloadStatistics> downloadStatistics(
252      OccurrenceDownloadService service,
253      @Nullable Date fromDate,
254      @Nullable Date toDate,
255      @Nullable Country publishingCountry,
256      @Nullable UUID datasetKey,
257      @Nullable UUID publishingOrgKey,
258      @Nullable Integer limit) {
259    LOG.info("Iterate over download statistics");
260    return new DownloadStatisticPager(
261        service,
262        fromDate,
263        toDate,
264        publishingCountry,
265        datasetKey,
266        publishingOrgKey,
267        Optional.ofNullable(limit).orElse(PagingConstants.DEFAULT_PARAM_LIMIT));
268  }
269
270  /** Iterable for {@link OccurrenceDownloadService#listDatasetUsages(String, Pageable)}. */
271  public static Iterable<DatasetOccurrenceDownloadUsage> datasetOccurrenceDownloadUsages(
272      OccurrenceDownloadService service, String downloadKey, @Nullable Integer limit) {
273    LOG.info("Iterate over download dataset usages of download {}", downloadKey);
274    return new DatasetOccurrenceDownloadUsagesPager(
275        service,
276        downloadKey,
277        Optional.ofNullable(limit).orElse(PagingConstants.DEFAULT_PARAM_LIMIT));
278  }
279
280  /** Iterable for {@link CollectionService#list(CollectionSearchRequest)}. */
281  public static Iterable<CollectionView> collections(
282      CollectionSearchRequest searchRequest, CollectionService service, @Nullable Integer limit) {
283    LOG.info("Iterating over a collection's search results");
284    return new CollectionsPager(
285        service,
286        searchRequest,
287        Optional.ofNullable(limit).orElse(PagingConstants.DEFAULT_PARAM_LIMIT));
288  }
289
290  /** Iterable for {@link InstitutionService#list(InstitutionSearchRequest)}. */
291  public static Iterable<Institution> institutions(
292      InstitutionSearchRequest searchRequest, InstitutionService service, @Nullable Integer limit) {
293    LOG.info("Iterating over a institution's search results");
294    return new InstitutionsPager(
295        service,
296        searchRequest,
297        Optional.ofNullable(limit).orElse(PagingConstants.DEFAULT_PARAM_LIMIT));
298  }
299
300  /** Iterable for {@link DescriptorsService#listDescriptors(DescriptorSearchRequest)}. */
301  public static Iterable<Descriptor> descriptors(
302      DescriptorsService service, DescriptorSearchRequest searchRequest, @Nullable Integer limit) {
303    LOG.info("Iterating over a collection descriptor's search results");
304    return new CollectionDescriptorPager(
305        service,
306        searchRequest,
307        Optional.ofNullable(limit).orElse(PagingConstants.DEFAULT_PARAM_LIMIT));
308  }
309
310  /**
311   * Iterable for the verbatim fields of {@link
312   * DescriptorsService#listDescriptors(DescriptorSearchRequest)}.
313   */
314  public static Iterable<Map<String, String>> descriptorVerbatims(
315      DescriptorsService service, DescriptorSearchRequest searchRequest, @Nullable Integer limit) {
316    LOG.info("Iterating over a collection descriptor's search results");
317    return new CollectionDescriptorVerbatimPager(
318        service,
319        searchRequest,
320        Optional.ofNullable(limit).orElse(PagingConstants.DEFAULT_PARAM_LIMIT));
321  }
322
323  private static boolean isDataset(UUID key, DatasetService ds) {
324    return ds.get(key) != null;
325  }
326
327  private static boolean isOrganization(UUID key, OrganizationService os) {
328    return os.get(key) != null;
329  }
330
331  private static boolean isInstallation(UUID key, InstallationService is) {
332    return is.get(key) != null;
333  }
334
335  private static boolean isNetwork(UUID key, NetworkService ns) {
336    return ns.get(key) != null;
337  }
338
339  private static boolean isNode(UUID key, NodeService ns) {
340    return ns.get(key) != null;
341  }
342}