/** * The contents of this file are subject to the license and copyright * detailed in the LICENSE file at the root of the source * tree and available online at * * https://github.com/keeps/roda */ package org.roda.core.index.utils; import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.NoSuchElementException; import java.util.Set; import org.apache.solr.client.solrj.SolrClient; import org.roda.core.data.common.RodaConstants; import org.roda.core.data.exceptions.GenericException; import org.roda.core.data.exceptions.RequestNotValidException; import org.roda.core.data.v2.index.IndexResult; import org.roda.core.data.v2.index.IsIndexed; import org.roda.core.data.v2.index.facet.FacetFieldResult; import org.roda.core.data.v2.index.facet.Facets; import org.roda.core.data.v2.index.filter.Filter; import org.roda.core.data.v2.index.sort.Sorter; import org.roda.core.data.v2.index.sublist.Sublist; import org.roda.core.data.v2.user.User; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Does search in the index, using the Solr.find() method, and if configured * removes duplicate objects (via uuid comparison) thus providing iterator * * @author Hélder Silva <hsilva@keep.pt> */ public class IterableIndexResult<T extends IsIndexed> implements Iterable<T> { private static final Logger LOGGER = LoggerFactory.getLogger(IterableIndexResult.class); private static final int PAGE_SIZE = RodaConstants.DEFAULT_PAGINATION_VALUE; private SolrClient solrClient; private Class<T> returnClass; private Filter filter; private Sorter sorter; private Sublist sublist; private Facets facets; private User user; private boolean justActive; private List<String> fieldsToReturn; private boolean removeDuplicates = true; private Set<String> uniqueUUIDs = new HashSet<>(); private IndexResult<T> indexResult = null; private List<T> indexResultObjects; private int currentObject = 0; private int currentObjectInPartialList = 0; private long totalObjects = -1; public IterableIndexResult(final SolrClient solrClient, final Class<T> returnClass, final Filter filter, final Sorter sorter, final Facets facets, final boolean removeDuplicates, final List<String> fieldsToReturn) { this(solrClient, returnClass, filter, sorter, Sublist.ALL, facets, null, true, removeDuplicates, fieldsToReturn); } public IterableIndexResult(final SolrClient solrClient, final Class<T> returnClass, final Filter filter, final Sorter sorter, final Sublist sublist, final Facets facets, final User user, final boolean justActive, final boolean removeDuplicates, final List<String> fieldsToReturn) { this.solrClient = solrClient; this.returnClass = returnClass; this.filter = filter; this.sorter = sorter; this.facets = facets; // TODO implement sublist support this.sublist = new Sublist(0, PAGE_SIZE); this.user = user; this.justActive = justActive; this.removeDuplicates = removeDuplicates; this.fieldsToReturn = fieldsToReturn; getResults(this.sublist); } private void getResults(final Sublist sublist) { try { indexResult = SolrUtils.find(solrClient, returnClass, filter, sorter, sublist, facets, user, justActive, fieldsToReturn); if (totalObjects == -1) { totalObjects = indexResult.getTotalCount(); } if (removeDuplicates) { indexResultObjects = new ArrayList<>(); for (T obj : indexResult.getResults()) { if (!uniqueUUIDs.contains(obj.getUUID())) { indexResultObjects.add(obj); uniqueUUIDs.add(obj.getUUID()); } else { totalObjects -= 1; } } } else { indexResultObjects = indexResult.getResults(); } } catch (GenericException | RequestNotValidException e) { // just set index result to null & let iterator return proper values indexResult = null; LOGGER.error("Error while retrieving partial list of results", e); } } public List<FacetFieldResult> getFacetResults() { return indexResult != null ? indexResult.getFacetResults() : Collections.emptyList(); } @Override public Iterator<T> iterator() { return new Iterator<T>() { @Override public boolean hasNext() { return indexResult != null && currentObject < totalObjects; } @Override public T next() { try { final T t = indexResultObjects.get(currentObjectInPartialList); currentObject += 1; currentObjectInPartialList += 1; if (LOGGER.isTraceEnabled()) { LOGGER.trace("({} of {}) Returning object of class '{}' with id '{}'", currentObject, totalObjects, returnClass.getSimpleName(), t.getUUID()); } // see if a new page needs to be obtained if (currentObjectInPartialList == indexResultObjects.size()) { getResults(sublist.setFirstElementIndex(sublist.getFirstElementIndex() + PAGE_SIZE)); currentObjectInPartialList = 0; } return t; } catch (IndexOutOfBoundsException e) { LOGGER.error( "Error while processing next element. filter='{}'; sorter='{}'; sublist='{}'; justActive='{}'; removeDuplicates='{}'; " + "currentObjectInPartialList='{}'; currentObject='{}'; totalObjects='{}'", filter, sorter, sublist, justActive, removeDuplicates, currentObjectInPartialList, currentObject, totalObjects, e); throw new NoSuchElementException("Error while processing next element"); } } }; } public long getTotalObjects() { return totalObjects; } }