001/*
002 * Copyright 2020 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.util.iterables;
017
018import static org.gbif.api.util.PreconditionUtils.checkArgument;
019
020import java.util.ArrayList;
021import java.util.Iterator;
022import java.util.List;
023import java.util.Map;
024import lombok.extern.slf4j.Slf4j;
025import org.gbif.api.model.collections.descriptors.Descriptor;
026import org.gbif.api.model.collections.request.DescriptorSearchRequest;
027import org.gbif.api.model.common.paging.PagingRequest;
028import org.gbif.api.service.collections.DescriptorsService;
029
030/** Iterates over results of {@link DescriptorsService#listDescriptors(DescriptorSearchRequest)}. */
031@Slf4j
032public class CollectionDescriptorVerbatimPager implements Iterable<Map<String, String>> {
033
034  private final DescriptorsService service;
035  private final DescriptorSearchRequest searchRequest;
036  private final int pageSize;
037
038  public CollectionDescriptorVerbatimPager(
039      DescriptorsService service, DescriptorSearchRequest searchRequest, int pageSize) {
040    checkArgument(pageSize > 0, "pageSize must be at least 1");
041    this.pageSize = pageSize;
042    this.searchRequest = searchRequest;
043    this.service = service;
044  }
045
046  @Override
047  public Iterator<Map<String, String>> iterator() {
048    return new ResponseIterator();
049  }
050
051  class ResponseIterator implements Iterator<Map<String, String>> {
052    private final PagingRequest page = new PagingRequest(0, pageSize);
053    private List<Map<String, String>> resp = null;
054    private Iterator<Map<String, String>> iter;
055    private Map<String, String> next;
056
057    public ResponseIterator() {
058      loadPage();
059      next = nextEntity();
060    }
061
062    @Override
063    public boolean hasNext() {
064      return next != null && !next.isEmpty();
065    }
066
067    @Override
068    public Map<String, String> next() {
069      Map<String, String> entity = next;
070      next = nextEntity();
071      return entity;
072    }
073
074    @Override
075    public void remove() {
076      throw new UnsupportedOperationException();
077    }
078
079    private Map<String, String> nextEntity() {
080      while (true) {
081        if (!iter.hasNext()) {
082          if (resp.isEmpty()) {
083            // no more records to load, stop!
084            return null;
085          } else {
086            loadPage();
087          }
088        }
089        if (iter.hasNext()) {
090          return iter.next();
091        }
092      }
093    }
094
095    private void loadPage() {
096      log.debug("Loading page {}-{}", page.getOffset(), page.getOffset() + page.getLimit());
097      resp = nextPage(page);
098      iter = resp.iterator();
099      page.nextPage();
100    }
101  }
102
103  public List<Map<String, String>> nextPage(PagingRequest page) {
104    searchRequest.setLimit(page.getLimit());
105    searchRequest.setOffset(page.getOffset());
106
107    List<Map<String, String>> result = new ArrayList<>();
108    for (Descriptor d : service.listDescriptors(searchRequest).getResults()) {
109      result.add(d.getVerbatim());
110    }
111    return result;
112  }
113}