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