SailClosingIteration.java
/*******************************************************************************
* Copyright (c) 2015 Eclipse RDF4J contributors, Aduna, and others.
*
* 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.base;
import java.lang.reflect.UndeclaredThrowableException;
import java.util.ArrayList;
import java.util.List;
import java.util.NoSuchElementException;
import org.eclipse.rdf4j.common.iteration.CloseableIteration;
import org.eclipse.rdf4j.common.iteration.IterationWrapper;
import org.eclipse.rdf4j.sail.SailException;
/**
* An {@link CloseableIteration} that holds on to a {@link SailClosable} until the Iteration is closed. Upon closing,
* the underlying Iteration is closed before the lock is released. This iterator closes itself as soon as all elements
* have been read.
*
* @author James Leigh
*/
abstract class SailClosingIteration<T> extends IterationWrapper<T> {
/**
* Creates a new {@link CloseableIteration} that automatically closes the given {@link SailClosable}s.
*
* @param iter The underlying Iteration, must not be <var>null</var>.
* @param closes The {@link SailClosable}s to {@link SailClosable#close()} when the itererator is closed.
* @return a {@link CloseableIteration} that closes the given {@link SailClosable}
*/
public static <E> SailClosingIteration<E> makeClosable(
CloseableIteration<? extends E> iter, SailClosable... closes) {
return new SailClosingIteration<>(iter, closes) {
@Override
protected void handleSailException(SailException e) throws SailException {
throw e;
}
};
}
/*-----------*
* Variables *
*-----------*/
/**
* The lock to release when the Iteration is closed.
*/
private final SailClosable[] closes;
/*--------------*
* Constructors *
*--------------*/
/**
* Creates a new {@link CloseableIteration} that automatically closes the given {@link SailClosable}s.
*
* @param iter The underlying Iteration, must not be <var>null</var>.
* @param closes The {@link SailClosable}s to {@link SailClosable#close()} when the itererator is closed.
*/
public SailClosingIteration(CloseableIteration<? extends T> iter, SailClosable... closes) {
super(iter);
this.closes = closes;
}
/*---------*
* Methods *
*---------*/
@Override
public boolean hasNext() {
if (isClosed()) {
return false;
}
boolean result = super.hasNext();
if (!result) {
close();
}
return result;
}
@Override
public T next() {
if (isClosed()) {
throw new NoSuchElementException("Iteration has been closed");
}
try {
return super.next();
} catch (NoSuchElementException e) {
close();
throw e;
}
}
@Override
public void remove() {
if (isClosed()) {
throw new IllegalStateException();
}
try {
super.remove();
} catch (IllegalStateException e) {
close();
throw e;
}
}
@Override
protected void handleClose() {
try {
super.handleClose();
} finally {
// Attempt to call close more often on all SailClosable instances by delaying handling
List<SailException> exceptions = new ArrayList<>();
List<Throwable> extraOrdinaryExceptions = new ArrayList<>();
for (SailClosable closing : closes) {
try {
closing.close();
} catch (SailException e) {
exceptions.add(e);
}
// Delay all other exceptions also, but don't pass them through the handler
catch (Throwable e) {
extraOrdinaryExceptions.add(e);
}
}
for (SailException nextException : exceptions) {
handleSailException(nextException);
}
if (!extraOrdinaryExceptions.isEmpty()) {
throw new UndeclaredThrowableException(extraOrdinaryExceptions.get(0));
}
}
}
/**
* Handler for exceptions generated by the closure of the {@link SailClosable} array given to this object. <br/>
* This method is called after all of the {@link SailClosable} objects have had close called on them.
*
* @param e The {@link SailException} to handle.
*/
protected abstract void handleSailException(SailException e);
}