All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.sirix.axis.AbstractAxis Maven / Gradle / Ivy

/*
 * Copyright (c) 2011, University of Konstanz, Distributed Systems Group All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification, are permitted
 * provided that the following conditions are met: * Redistributions of source code must retain the
 * above copyright notice, this list of conditions and the following disclaimer. * Redistributions
 * in binary form must reproduce the above copyright notice, this list of conditions and the
 * following disclaimer in the documentation and/or other materials provided with the distribution.
 * * Neither the name of the University of Konstanz nor the names of its contributors may be used to
 * endorse or promote products derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL  BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package io.sirix.axis;

import com.google.common.base.MoreObjects;
import it.unimi.dsi.fastutil.longs.LongIterator;
import org.checkerframework.checker.index.qual.NonNegative;
import io.sirix.api.Axis;
import io.sirix.api.NodeCursor;
import io.sirix.api.NodeReadOnlyTrx;
import io.sirix.api.json.JsonNodeReadOnlyTrx;
import io.sirix.api.visitor.XmlNodeVisitor;
import io.sirix.api.xml.XmlNodeReadOnlyTrx;
import io.sirix.index.path.summary.PathSummaryReader;
import io.sirix.settings.Fixed;

import java.util.NoSuchElementException;

import static com.google.common.base.Preconditions.checkState;
import static java.util.Objects.requireNonNull;

/**
 * 

* Provide standard Java iterator capability compatible with the new enhanced for loop available * since Java 5. *

*

* Override the "template method" {@code nextKey()} to implement an axis. Return {@code done()} if * the axis has no more "elements". *

* * @author Johannes Lichtenberger */ public abstract class AbstractAxis implements Axis { /** Iterate over transaction exclusive to this step. */ protected final NodeCursor nodeCursor; /** Key of next node. */ private long nextNodeKey; /** Key of node where axis started. */ private long startNodeKey; /** Include self? */ private final IncludeSelf includeSelf; /** Current state. */ private State state = State.NOT_READY; /** State of the iterator. */ private enum State { /** We have computed the next element and haven't returned it yet. */ READY, /** We haven't yet computed or have already returned the element. */ NOT_READY, /** We have reached the end of the data and are finished. */ DONE, /** We've suffered an exception and are kaput. */ FAILED, } /** * Bind axis step to transaction. * * @param nodeCursor node cursor * @throws NullPointerException if {@code nodeCursor} is {@code null} */ public AbstractAxis(final NodeCursor nodeCursor) { this.nodeCursor = requireNonNull(nodeCursor); includeSelf = IncludeSelf.NO; reset(nodeCursor.getNodeKey()); } /** * Bind axis step to transaction. * * @param nodeCursor node cursor * @param includeSelf determines if self is included * @throws NullPointerException if {@code nodeCursor} or {@code includeSelf} is {@code null} */ public AbstractAxis(final NodeCursor nodeCursor, final IncludeSelf includeSelf) { this.nodeCursor = requireNonNull(nodeCursor); this.includeSelf = requireNonNull(includeSelf); reset(nodeCursor.getNodeKey()); } @Override public final LongIterator iterator() { return this; } /** * Signals that axis traversal is done, that is {@code hasNext()} must return false. Is callable * from subclasses which implement {@link #nextKey()} to signal that the axis-traversal is done and * {@link #hasNext()} must return false. * * @return null node key to indicate that the travesal is done */ protected long done() { return Fixed.NULL_NODE_KEY.getStandardProperty(); } /** * {@inheritDoc} * *

* During the last call to {@code hasNext()}, that is {@code hasNext()} returns false, the * transaction is reset to the start key. *

* *

* Implementors must implement {@code nextKey()} instead which is a template method called * from this {@code hasNext()} method. *

*/ @Override public final boolean hasNext() { // First check the state. checkState(state != State.FAILED); switch (state) { case DONE: return false; case READY: return true; case FAILED: case NOT_READY: default: } // Reset to last node key. resetToLastKey(); final boolean hasNext = tryToComputeNext(); if (hasNext) { return true; } else { // Reset to the start key before invoking the axis. resetToStartKey(); return false; } } /** * Try to compute the next node key. * * @return {@code true} if next node key exists, {@code false} otherwise */ private boolean tryToComputeNext() { state = State.FAILED; // temporary pessimism // Template method. nextNodeKey = nextKey(); if (nextNodeKey == Fixed.NULL_NODE_KEY.getStandardProperty()) { state = State.DONE; } if (state == State.DONE) { return false; } state = State.READY; return true; } /** * Returns the next node key. Note: the implementation must either call * {@link #done()} when there are no elements left in the iteration or return the node key * {@code EFixed.NULL_NODE.getStandardProperty()}. * *

* The initial invocation of {@link #hasNext()} or {@link #next()} calls this method, as does the * first invocation of {@code hasNext} or {@code next} following each successful call to * {@code next}. Once the implementation either invokes {@link #done()}, returns * {@code EFixed.NULL_NODE.getStandardProperty()} or throws an exception, {@code nextKey()} is * guaranteed to never be called again. *

* *

* If this method throws an exception, it will propagate outward to the {@code hasNext} or * {@code next} invocation that invoked this method. Any further attempts to use the iterator will * result in an {@link IllegalStateException}. *

* *

* The implementation of this method may not invoke the {@code hasNext}, {@code next}, or * {@link #peek()} methods on this instance; if it does, an {@code IllegalStateException} will * result. *

* * @return the next node key * @throws RuntimeException if any unrecoverable error happens. This exception will propagate * outward to the {@code hasNext()}, {@code next()}, or {@code peek()} invocation that * invoked this method. Any further attempts to use the iterator will result in an * {@link IllegalStateException}. */ protected abstract long nextKey(); @Override public final long nextLong() { if (!hasNext()) { throw new NoSuchElementException(); } state = State.NOT_READY; // Move to next. if (nextNodeKey >= 0) { if (!nodeCursor.moveTo(nextNodeKey)) { throw new IllegalStateException("Failed to move to nodeKey: " + nextNodeKey); } } else { nodeCursor.moveTo(nextNodeKey); } return nextNodeKey; } /** * Remove is not supported. */ @Override public final void remove() { throw new UnsupportedOperationException(); } /** * Resetting the nodekey of this axis to a given nodekey. * * @param nodeKey the nodekey where the reset should occur to */ @Override public void reset(@NonNegative final long nodeKey) { startNodeKey = nodeKey; nextNodeKey = nodeKey; state = State.NOT_READY; } @Override public XmlNodeReadOnlyTrx asXmlNodeReadTrx() { if (nodeCursor instanceof XmlNodeReadOnlyTrx) { return (XmlNodeReadOnlyTrx) nodeCursor; } throw new ClassCastException("Node cursor is no XDM node transaction."); } @Override public JsonNodeReadOnlyTrx asJsonNodeReadTrx() { if (nodeCursor instanceof JsonNodeReadOnlyTrx) { return (JsonNodeReadOnlyTrx) nodeCursor; } throw new ClassCastException("Node cursor is no JSON node transaction."); } @Override public PathSummaryReader asPathSummary() { if (nodeCursor instanceof PathSummaryReader) { return (PathSummaryReader) nodeCursor; } throw new ClassCastException("Node cursor is no path summary reader."); } @Override public NodeCursor getCursor() { return nodeCursor; } @Override public NodeReadOnlyTrx getTrx() { if (nodeCursor instanceof NodeReadOnlyTrx) { return (NodeReadOnlyTrx) nodeCursor; } throw new ClassCastException("Node cursor is no transactional cursor."); } /** * Make sure the transaction points to the node it started with. This must be called just before * {@code hasNext() == false}. * * @return key of node where transaction was before the first call of {@code hasNext()} */ private long resetToStartKey() { // No check because of Axis Convention 4. nodeCursor.moveTo(startNodeKey); return startNodeKey; } /** * Make sure the transaction points to the node after the last hasNext(). This must be called first * in hasNext(). * * @return key of node where transaction was after the last call of {@code hasNext()} */ protected final long resetToLastKey() { // No check because of Axis convention 4. if (nodeCursor.getNodeKey() != nextNodeKey) { nodeCursor.moveTo(nextNodeKey); } return nextNodeKey; } @Override public final long peek() { if (!hasNext()) { throw new NoSuchElementException(); } return nextNodeKey; } @Override public final long getStartKey() { return startNodeKey; } @Override public final IncludeSelf includeSelf() { return includeSelf; } /** * Implements a simple foreach-method. * * @param visitor {@link XmlNodeVisitor} implementation */ @Override public final void foreach(final XmlNodeVisitor visitor) { requireNonNull(visitor); if (nodeCursor instanceof XmlNodeReadOnlyTrx) { while (hasNext()) { nextLong(); ((XmlNodeReadOnlyTrx) nodeCursor).acceptVisitor(visitor); } } } @Override public synchronized final long nextNode() { synchronized (nodeCursor) { long retVal = Fixed.NULL_NODE_KEY.getStandardProperty(); if (hasNext()) { retVal = nextLong(); } return retVal; } } @Override public String toString() { return MoreObjects.toStringHelper(this).add("trx", nodeCursor).toString(); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy