ValidationResultIterator.java

/*******************************************************************************
 * Copyright (c) 2020 Eclipse RDF4J contributors.
 *
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Distribution License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/org/documents/edl-v10.php.
 *
 * SPDX-License-Identifier: BSD-3-Clause
 *******************************************************************************/

package org.eclipse.rdf4j.sail.shacl.results.lazy;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import org.eclipse.rdf4j.common.annotation.InternalUseOnly;
import org.eclipse.rdf4j.common.iteration.CloseableIteration;
import org.eclipse.rdf4j.common.iteration.CloseableIteratorIteration;
import org.eclipse.rdf4j.sail.shacl.ast.planNodes.ValidationTuple;
import org.eclipse.rdf4j.sail.shacl.results.ValidationResult;

@InternalUseOnly
public class ValidationResultIterator implements Iterator<ValidationResult> {

	private final long limit;
	private long counter = 0;
	private boolean conforms = true;
	private boolean truncated = false;

	private Iterator<ValidationResult> next = Collections.emptyIterator();
	private CloseableIteration<? extends ValidationTuple> tupleIterator;

	public ValidationResultIterator(CloseableIteration<? extends ValidationTuple> tupleIterator,
			long limit) {
		this.limit = limit;
		this.tupleIterator = tupleIterator;
		getTuples();

	}

	private void calculateNext() {
		if (tupleIterator.hasNext()) {
			conforms = false;
		}
		if (next.hasNext()) {
			return;
		}

		if (tupleIterator.hasNext()) {
			if (limit < 0 || counter < limit) {
				ValidationTuple invalidTuple = tupleIterator.next();

				Set<ValidationTuple> invalidTuples;

				if (!invalidTuple.getCompressedTuples().isEmpty()) {
					invalidTuples = invalidTuple.getCompressedTuples();
				} else {
					invalidTuples = Collections.singleton(invalidTuple);
				}

				Set<ValidationResult> validationResultsRet = new HashSet<>();

				for (ValidationTuple tuple : invalidTuples) {
					List<ValidationResult> validationResults = tuple.getValidationResult();

					assert !validationResults.isEmpty();

					validationResultsRet.addAll(validationResults);

					counter++;
				}

				next = validationResultsRet.iterator();

			}

			if (limit >= 0 && counter >= limit && tupleIterator.hasNext()) {
				truncated = true;
			}

		}
	}

	public List<ValidationTuple> getTuples() {
		List<ValidationTuple> actualList = new ArrayList<>();
		long localCounter = 0;
		while (tupleIterator.hasNext() && (limit < 0 || localCounter++ < limit + 1)) {
			actualList.add(tupleIterator.next());
		}

		tupleIterator = new CloseableIteratorIteration<>(actualList.iterator());
		return Collections.unmodifiableList(actualList);
	}

	public boolean conforms() {
		calculateNext();
		return conforms;
	}

	public boolean isTruncated() {
		return truncated;
	}

	@Override
	public boolean hasNext() {
		calculateNext();
		return next.hasNext();
	}

	@Override
	public ValidationResult next() {
		calculateNext();
		if (!next.hasNext()) {
			throw new IllegalStateException();
		}

		return next.next();
	}

	@Override
	public void remove() {
		throw new UnsupportedOperationException();
	}
}