001: /*
002: * Copyright Aduna (http://www.aduna-software.com/) (c) 1997-2007.
003: *
004: * Licensed under the Aduna BSD-style license.
005: */
006: package org.openrdf.sail.memory.model;
007:
008: import java.util.NoSuchElementException;
009:
010: import info.aduna.iteration.CloseableIterationBase;
011: import info.aduna.lang.ObjectUtil;
012:
013: /**
014: * A StatementIterator that can iterate over a list of Statement objects. This
015: * iterator compares Resource and Literal objects using the '==' operator, which
016: * is possible thanks to the extensive sharing of these objects in the
017: * MemoryStore.
018: */
019: public class MemStatementIterator<X extends Exception> extends
020: CloseableIterationBase<MemStatement, X> {
021:
022: /*-----------*
023: * Variables *
024: *-----------*/
025:
026: /**
027: * The lists of statements over which to iterate.
028: */
029: private MemStatementList statementList;
030:
031: /**
032: * The subject of statements to return, or null if any subject is OK.
033: */
034: private MemResource subject;
035:
036: /**
037: * The predicate of statements to return, or null if any predicate is OK.
038: */
039: private MemURI predicate;
040:
041: /**
042: * The object of statements to return, or null if any object is OK.
043: */
044: private MemValue object;
045:
046: /**
047: * The context of statements to return, or null if any context is OK.
048: */
049: private MemResource[] contexts;
050:
051: /**
052: * Flag indicating whether this iterator should only return explicitly added
053: * statements.
054: */
055: private boolean explicitOnly;
056:
057: /**
058: * Indicates which snapshot should be iterated over.
059: */
060: private int snapshot;
061:
062: /**
063: * Flag indicating whether or not the iterator should read any non-committed
064: * changes to the data.
065: */
066: private ReadMode readMode;
067:
068: /**
069: * The statement to return next.
070: */
071: private MemStatement nextStatement;
072:
073: /**
074: * The index of the next statement to return.
075: */
076: private int nextStatementIdx;
077:
078: /*--------------*
079: * Constructors *
080: *--------------*/
081:
082: /**
083: * Creates a new MemStatementIterator that will iterate over the statements
084: * contained in the supplied MemStatementList searching for statements that
085: * match the specified pattern of subject, predicate, object and context.
086: *
087: * @param statementList
088: * the statements over which to iterate.
089: * @param subject
090: * subject of pattern.
091: * @param predicate
092: * predicate of pattern.
093: * @param object
094: * object of pattern.
095: * @param context
096: * context of pattern.
097: */
098: public MemStatementIterator(MemStatementList statementList,
099: MemResource subject, MemURI predicate, MemValue object,
100: boolean explicitOnly, int snapshot, ReadMode readMode,
101: MemResource... contexts) {
102: this .statementList = statementList;
103: this .subject = subject;
104: this .predicate = predicate;
105: this .object = object;
106: this .contexts = contexts;
107: this .explicitOnly = explicitOnly;
108: this .snapshot = snapshot;
109: this .readMode = readMode;
110:
111: this .nextStatementIdx = -1;
112: }
113:
114: /*---------*
115: * Methods *
116: *---------*/
117:
118: /**
119: * Searches through statementList, starting from index
120: * <tt>_nextStatementIdx + 1</tt>, for statements that match the
121: * constraints that have been set for this iterator. If a matching statement
122: * has been found it will be stored in <tt>_nextStatement</tt> and
123: * <tt>_nextStatementIdx</tt> points to the index of this statement in
124: * <tt>_statementList</tt>. Otherwise, <tt>_nextStatement</tt> will set
125: * to <tt>null</tt>.
126: */
127: private void findNextStatement() {
128: nextStatementIdx++;
129:
130: for (; nextStatementIdx < statementList.size(); nextStatementIdx++) {
131: nextStatement = statementList.get(nextStatementIdx);
132:
133: if (nextStatement.isInSnapshot(snapshot)
134: && (subject == null || subject == nextStatement
135: .getSubject())
136: && (predicate == null || predicate == nextStatement
137: .getPredicate())
138: && (object == null || object == nextStatement
139: .getObject())) {
140: // A matching statement has been found, check if it should be
141: // skipped due to explicitOnly, contexts and readMode requirements
142:
143: if (contexts != null && contexts.length > 0) {
144: boolean matchingContext = false;
145: for (int i = 0; i < contexts.length
146: && !matchingContext; i++) {
147: matchingContext = ObjectUtil
148: .nullEquals(nextStatement.getContext(),
149: contexts[i]);
150: }
151: if (!matchingContext) {
152: // statement does not appear in one of the specified contexts,
153: // skip it.
154: continue;
155: }
156: }
157:
158: if (ReadMode.COMMITTED.equals(readMode)) {
159: // Only read committed statements
160:
161: if (nextStatement.getTxnStatus() == TxnStatus.NEW) {
162: // Uncommitted statements, skip it
163: continue;
164: }
165: if (explicitOnly && !nextStatement.isExplicit()) {
166: // Explicit statements only; skip inferred ones
167: continue;
168: }
169: } else if (ReadMode.TRANSACTION.equals(readMode)) {
170: // Pretend that the transaction has already been committed
171:
172: TxnStatus txnStatus = nextStatement.getTxnStatus();
173:
174: if (TxnStatus.DEPRECATED.equals(txnStatus)
175: || TxnStatus.ZOMBIE.equals(txnStatus)) {
176: // Statement scheduled for removal, skip it
177: continue;
178: }
179:
180: if (explicitOnly) {
181: if (!nextStatement.isExplicit()
182: && !TxnStatus.EXPLICIT
183: .equals(txnStatus)
184: || TxnStatus.INFERRED.equals(txnStatus)) {
185: // Explicit statements only; skip inferred ones
186: continue;
187: }
188: }
189: } else if (ReadMode.RAW.equals(readMode)) {
190: // Ignore the statement's transaction status, only check the
191: // explicitOnly requirement
192:
193: if (explicitOnly && !nextStatement.isExplicit()) {
194: // Explicit statements only; skip inferred ones
195: continue;
196: }
197: }
198:
199: return;
200: }
201: }
202:
203: // No more matching statements.
204: nextStatement = null;
205: }
206:
207: public boolean hasNext() {
208: if (nextStatement == null && statementList != null
209: && nextStatementIdx < statementList.size()) {
210: findNextStatement();
211: }
212:
213: return nextStatement != null;
214: }
215:
216: public MemStatement next() {
217: if (statementList == null) {
218: throw new NoSuchElementException("Iterator has been closed");
219: }
220: if (nextStatement == null
221: && nextStatementIdx < statementList.size()) {
222: findNextStatement();
223: }
224: if (nextStatement == null) {
225: throw new NoSuchElementException("No more statements");
226: }
227:
228: MemStatement result = nextStatement;
229: nextStatement = null;
230: return result;
231: }
232:
233: /**
234: * Throws an UnsupportedOperationException.
235: */
236: public void remove() {
237: throw new UnsupportedOperationException();
238: }
239:
240: @Override
241: protected void handleClose() throws X {
242: nextStatement = null;
243: statementList = null;
244:
245: subject = null;
246: predicate = null;
247: object = null;
248: contexts = null;
249:
250: super.handleClose();
251: }
252: }
|