/* * Copyright Aduna (http://www.aduna-software.com/) (c) 1997-2007. * * Licensed under the Aduna BSD-style license. */ package org.openrdf.sail.memory.model; import java.util.NoSuchElementException; import info.aduna.iteration.CloseableIterationBase; import info.aduna.lang.ObjectUtil; /** * A StatementIterator that can iterate over a list of Statement objects. This * iterator compares Resource and Literal objects using the '==' operator, which * is possible thanks to the extensive sharing of these objects in the * MemoryStore. */ public class MemStatementIterator<X extends Exception> extends CloseableIterationBase<MemStatement, X> { /*-----------* * Variables * *-----------*/ /** * The lists of statements over which to iterate. */ private MemStatementList statementList; /** * The subject of statements to return, or null if any subject is OK. */ private MemResource subject; /** * The predicate of statements to return, or null if any predicate is OK. */ private MemURI predicate; /** * The object of statements to return, or null if any object is OK. */ private MemValue object; /** * The context of statements to return, or null if any context is OK. */ private MemResource[] contexts; /** * Flag indicating whether this iterator should only return explicitly added * statements. */ private boolean explicitOnly; /** * Indicates which snapshot should be iterated over. */ private int snapshot; /** * Flag indicating whether or not the iterator should read any non-committed * changes to the data. */ private ReadMode readMode; /** * The statement to return next. */ private MemStatement nextStatement; /** * The index of the next statement to return. */ private int nextStatementIdx; /*--------------* * Constructors * *--------------*/ /** * Creates a new MemStatementIterator that will iterate over the statements * contained in the supplied MemStatementList searching for statements that * match the specified pattern of subject, predicate, object and context. * * @param statementList * the statements over which to iterate. * @param subject * subject of pattern. * @param predicate * predicate of pattern. * @param object * object of pattern. * @param context * context of pattern. */ public MemStatementIterator(MemStatementList statementList, MemResource subject, MemURI predicate, MemValue object, boolean explicitOnly, int snapshot, ReadMode readMode, MemResource... contexts) { this.statementList = statementList; this.subject = subject; this.predicate = predicate; this.object = object; this.contexts = contexts; this.explicitOnly = explicitOnly; this.snapshot = snapshot; this.readMode = readMode; this.nextStatementIdx = -1; } /*---------* * Methods * *---------*/ /** * Searches through statementList, starting from index * <tt>_nextStatementIdx + 1</tt>, for statements that match the * constraints that have been set for this iterator. If a matching statement * has been found it will be stored in <tt>_nextStatement</tt> and * <tt>_nextStatementIdx</tt> points to the index of this statement in * <tt>_statementList</tt>. Otherwise, <tt>_nextStatement</tt> will set * to <tt>null</tt>. */ private void findNextStatement() { nextStatementIdx++; for (; nextStatementIdx < statementList.size(); nextStatementIdx++) { nextStatement = statementList.get(nextStatementIdx); if (nextStatement.isInSnapshot(snapshot) && (subject == null || subject == nextStatement.getSubject()) && (predicate == null || predicate == nextStatement.getPredicate()) && (object == null || object == nextStatement.getObject())) { // A matching statement has been found, check if it should be // skipped due to explicitOnly, contexts and readMode requirements if (contexts != null && contexts.length > 0) { boolean matchingContext = false; for (int i = 0; i < contexts.length && !matchingContext; i++) { matchingContext = ObjectUtil.nullEquals(nextStatement.getContext(), contexts[i]); } if (!matchingContext) { // statement does not appear in one of the specified contexts, // skip it. continue; } } if (ReadMode.COMMITTED.equals(readMode)) { // Only read committed statements if (nextStatement.getTxnStatus() == TxnStatus.NEW) { // Uncommitted statements, skip it continue; } if (explicitOnly && !nextStatement.isExplicit()) { // Explicit statements only; skip inferred ones continue; } } else if (ReadMode.TRANSACTION.equals(readMode)) { // Pretend that the transaction has already been committed TxnStatus txnStatus = nextStatement.getTxnStatus(); if (TxnStatus.DEPRECATED.equals(txnStatus) || TxnStatus.ZOMBIE.equals(txnStatus)) { // Statement scheduled for removal, skip it continue; } if (explicitOnly) { if (!nextStatement.isExplicit() && !TxnStatus.EXPLICIT.equals(txnStatus) || TxnStatus.INFERRED.equals(txnStatus)) { // Explicit statements only; skip inferred ones continue; } } } else if (ReadMode.RAW.equals(readMode)) { // Ignore the statement's transaction status, only check the // explicitOnly requirement if (explicitOnly && !nextStatement.isExplicit()) { // Explicit statements only; skip inferred ones continue; } } return; } } // No more matching statements. nextStatement = null; } public boolean hasNext() { if (nextStatement == null && statementList != null && nextStatementIdx < statementList.size()) { findNextStatement(); } return nextStatement != null; } public MemStatement next() { if (statementList == null) { throw new NoSuchElementException("Iterator has been closed"); } if (nextStatement == null && nextStatementIdx < statementList.size()) { findNextStatement(); } if (nextStatement == null) { throw new NoSuchElementException("No more statements"); } MemStatement result = nextStatement; nextStatement = null; return result; } /** * Throws an UnsupportedOperationException. */ public void remove() { throw new UnsupportedOperationException(); } @Override protected void handleClose() throws X { nextStatement = null; statementList = null; subject = null; predicate = null; object = null; contexts = null; super.handleClose(); } }