001: /*
002: * (c) Copyright 2003, 2004, 2005 2006, 2007, 2008 Hewlett-Packard Development Company, LP
003: * All rights reserved.
004: *
005: *
006: */
007:
008: //=======================================================================
009: // Package
010: package com.hp.hpl.jena.db.impl;
011:
012: //=======================================================================
013: // Imports
014: import java.sql.*;
015: import java.util.*;
016: import com.hp.hpl.jena.util.iterator.*;
017: import com.hp.hpl.jena.shared.*;
018:
019: import org.apache.commons.logging.Log;
020: import org.apache.commons.logging.LogFactory;
021:
022: //=======================================================================
023: /**
024: * Iterates over an SQL result set returning each row as an ArrayList of
025: * objects. The returned array is shared at each iteration so calling next() or even hasNext()
026: * changes the array contents. When the iterator terminates the resources
027: * are cleaned up and the underlying SQL PreparedStatement is returned to
028: * the SQLCache pool from whence it came.
029: *
030: * <p>Override the extractRow, getRow, and remove methods in subclasses
031: * to return an object collection derived from the row contents instead
032: * of the raw row contents.
033: *
034: * @author <a href="mailto:der@hplb.hpl.hp.com">Dave Reynolds</a>
035: * @version $Revision: 1.14 $ on $Date: 2008/01/02 12:08:24 $
036: */
037:
038: public class ResultSetIterator implements ExtendedIterator {
039:
040: /** The ResultSet being iterated over */
041: protected ResultSet m_resultSet;
042:
043: /** The originating SQLcache to return the statement to, can be null */
044: protected SQLCache m_sqlCache;
045:
046: /** The source Statement to be cleaned up when the iterator finishes - return it to cache or close it if no cache */
047: protected PreparedStatement m_statement;
048:
049: /** If true, clean/close the prepared statement when iterator is closed */
050: protected boolean m_statementClean = true;
051:
052: /** The name of the original operation that lead to this statement, can be null if SQLCache is null */
053: protected String m_opname;
054:
055: /** The contents of the current row */
056: protected ArrayList m_row;
057:
058: /** The number of columns in this result set */
059: protected int m_nCols;
060:
061: /** Flag that the iteration has finished */
062: protected boolean m_finished = false;
063:
064: /** Flag if we have prefeteched the next row but not yet returned it */
065: protected boolean m_prefetched = false;
066:
067: protected static Log logger = LogFactory
068: .getLog(ResultSetIterator.class);
069:
070: /**
071: * Create an empty iterator.
072: * Needs to be initialized by reset
073: * before it can be accessed. Useful to allow generic functions like
074: * {@link SQLCache#runSQLQuery runSQLQuery}
075: * to return different iterator types to the client.
076: */
077: public ResultSetIterator() {
078: m_finished = true; // Prevent reading until reset
079: }
080:
081: /**
082: * Iterate over the results of a PreparedStatement generated by an SQLCache
083: * @param resultSet the result set being iterated over
084: * @param sourceStatement The source Statement to be cleaned up when the iterator finishes - return it to cache or close it if no cache
085: * @param cache The originating SQLcache to return the statement to, can be null
086: * @param opname The name of the original operation that lead to this statement, can be null if SQLCache is null
087: */
088: public ResultSetIterator(ResultSet resultSet,
089: PreparedStatement sourceStatement, SQLCache cache,
090: String opname) {
091: m_resultSet = resultSet;
092: m_sqlCache = cache;
093: m_statement = sourceStatement;
094: m_opname = opname;
095: }
096:
097: /**
098: * Iterate over the results of a PreparedStatement, close the statement when finished.
099: * @param resultSet the result set being iterated over
100: * @param sourceStatement The source Statement to be closed when the iterator finishes
101: */
102: public ResultSetIterator(ResultSet resultSet,
103: PreparedStatement sourceStatement) {
104: m_resultSet = resultSet;
105: m_statement = sourceStatement;
106: }
107:
108: /**
109: * Reset an existing iterator to scan a new result set.
110: * @param resultSet the result set being iterated over
111: * @param sourceStatement The source Statement to be cleaned up when the iterator finishes - return it to cache or close it if no cache
112: * @param cache The originating SQLcache to return the statement to, can be null
113: * @param opname The name of the original operation that lead to this statement, can be null if SQLCache is null
114: */
115: public void reset(ResultSet resultSet,
116: PreparedStatement sourceStatement, SQLCache cache,
117: String opname) {
118: m_resultSet = resultSet;
119: m_sqlCache = cache;
120: m_statement = sourceStatement;
121: m_opname = opname;
122: m_finished = false;
123: m_prefetched = false;
124: m_row = null;
125: m_statementClean = true;
126: }
127:
128: /**
129: * Reset an existing iterator to scan a new result set.
130: * @param resultSet the result set being iterated over
131: * @param sourceStatement The source Statement to be cleaned up when the iterator finishes - return it to cache or close it if no cache
132: * note: the sourceStatement is not closed or returned when the iterator is closed.
133: */
134: public void reset(ResultSet resultSet,
135: PreparedStatement sourceStatement) {
136: m_resultSet = resultSet;
137: m_sqlCache = null;
138: m_statement = sourceStatement;
139: m_opname = null;
140: m_finished = false;
141: m_prefetched = false;
142: m_row = null;
143: m_statementClean = false;
144: }
145:
146: /**
147: * Test if there is a next result to return
148: */
149: public boolean hasNext() {
150: if (!m_finished && !m_prefetched)
151: moveForward();
152: return !m_finished;
153: }
154:
155: public Object removeNext() {
156: cantRemove();
157: return null;
158: }
159:
160: /**
161: * Return the current row
162: */
163: public Object next() {
164: if (!m_finished && !m_prefetched)
165: moveForward();
166: m_prefetched = false;
167: if (m_finished) {
168: throw new NoSuchElementException();
169: }
170: return getRow();
171: }
172:
173: /**
174: * Delete the current row entry
175: */
176: public void remove() {
177: cantRemove();
178: }
179:
180: protected void cantRemove() {
181: throw new UnsupportedOperationException(
182: "ResultSetIterator can't remove database rows");
183: }
184:
185: /**
186: * More forward one row. Sets the m_finished flag if there is no more to fetch
187: */
188: protected void moveForward() {
189: try {
190: if (!m_finished && m_resultSet.next()) {
191: extractRow();
192: m_prefetched = true;
193: } else {
194: close();
195: }
196: } catch (Exception e) {
197: // TODO do we need this catch at all?
198: logger.warn("Problem in iterator over db result set, op = "
199: + m_opname, e);
200: // Added by kers for debugging
201: throw new JenaException(e);
202: }
203: }
204:
205: /**
206: * Extract the current row
207: * Override in subclasses.
208: */
209: protected void extractRow() throws Exception {
210: if (m_row == null) {
211: m_nCols = m_resultSet.getMetaData().getColumnCount();
212: m_row = new ArrayList(m_nCols);
213: for (int i = 0; i < m_nCols; i++)
214: m_row.add(null);
215: }
216: for (int i = 0; i < m_nCols; i++) {
217: m_row.set(i, m_resultSet.getObject(i + 1));
218: }
219: }
220:
221: /**
222: * Return the current row,should have already been extracted.
223: * Override in subclasses.
224: */
225: protected Object getRow() {
226: return m_row;
227: }
228:
229: /**
230: * Clean up the allocated resources - result set and statement.
231: * If we know of an SQLCache return the statement there, otherwise close it.
232: */
233: public void close() {
234: if (!m_finished) {
235: if (m_resultSet != null) {
236: try {
237: m_resultSet.close();
238: m_resultSet = null;
239: } catch (SQLException e) {
240: logger
241: .warn(
242: "Error while finalizing result set iterator",
243: e);
244: }
245: }
246: if (m_statementClean) {
247: if (m_sqlCache != null && m_opname != null) {
248: m_sqlCache.returnPreparedSQLStatement(m_statement);
249: } else {
250: try {
251: m_statement.close();
252: } catch (SQLException e) {
253: logger
254: .warn(
255: "Error while finalizing result set iterator",
256: e);
257: }
258: }
259: }
260: }
261: m_finished = true;
262: }
263:
264: /**
265: * Get a singleton result (single column from single row) and close the iterator.
266: * This may be too specialized but seems to come up a lot - rethink.
267: */
268: public Object getSingleton() throws SQLException {
269: List row = (List) next();
270: close();
271: return row.get(0);
272: }
273:
274: /**
275: * Clean up the database cursor. Noramlly the client should read to the end
276: * or explicity close but....
277: */
278: protected void finalize() throws SQLException {
279: if (!m_finished && m_resultSet != null)
280: close();
281: }
282:
283: /**
284: return a new iterator which delivers all the elements of this iterator and
285: then all the elements of the other iterator. Does not copy either iterator;
286: they are consumed as the result iterator is consumed.
287: */
288: public ExtendedIterator andThen(ClosableIterator other) {
289: return NiceIterator.andThen(this , other);
290: }
291:
292: public Set toSet() {
293: return NiceIterator.asSet(this );
294: }
295:
296: public List toList() {
297: return NiceIterator.asList(this );
298: }
299:
300: /* (non-Javadoc)
301: * @see com.hp.hpl.jena.util.iterator.ExtendedIterator#filterKeep(com.hp.hpl.jena.util.iterator.Filter)
302: */
303: public ExtendedIterator filterKeep(Filter f) {
304: return new FilterIterator(f, this );
305: }
306:
307: /* (non-Javadoc)
308: * @see com.hp.hpl.jena.util.iterator.ExtendedIterator#filterDrop(com.hp.hpl.jena.util.iterator.Filter)
309: */
310: public ExtendedIterator filterDrop(final Filter f) {
311: Filter notF = new Filter() {
312: public boolean accept(Object x) {
313: return !f.accept(x);
314: }
315: };
316: return new FilterIterator(notF, this );
317: }
318:
319: /* (non-Javadoc)
320: * @see com.hp.hpl.jena.util.iterator.ExtendedIterator#mapWith(com.hp.hpl.jena.util.iterator.Map1)
321: */
322: public ExtendedIterator mapWith(Map1 map1) {
323: return new Map1Iterator(map1, this );
324: }
325:
326: } // End class
327:
328: /*
329: * (c) Copyright 2003, 2004, 2005, 2006, 2007, 2008 Hewlett-Packard Development Company, LP
330: * All rights reserved.
331: *
332: * Redistribution and use in source and binary forms, with or without
333: * modification, are permitted provided that the following conditions
334: * are met:
335: * 1. Redistributions of source code must retain the above copyright
336: * notice, this list of conditions and the following disclaimer.
337: * 2. Redistributions in binary form must reproduce the above copyright
338: * notice, this list of conditions and the following disclaimer in the
339: * documentation and/or other materials provided with the distribution.
340: * 3. The name of the author may not be used to endorse or promote products
341: * derived from this software without specific prior written permission.
342:
343: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
344: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
345: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
346: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
347: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
348: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
349: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
350: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
351: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
352: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
353: */
|