KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > objectstyle > cayenne > access > DefaultResultIterator


1 /* ====================================================================
2  *
3  * The ObjectStyle Group Software License, version 1.1
4  * ObjectStyle Group - http://objectstyle.org/
5  *
6  * Copyright (c) 2002-2005, Andrei (Andrus) Adamchik and individual authors
7  * of the software. All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  *
13  * 1. Redistributions of source code must retain the above copyright
14  * notice, this list of conditions and the following disclaimer.
15  *
16  * 2. Redistributions in binary form must reproduce the above copyright
17  * notice, this list of conditions and the following disclaimer in
18  * the documentation and/or other materials provided with the
19  * distribution.
20  *
21  * 3. The end-user documentation included with the redistribution, if any,
22  * must include the following acknowlegement:
23  * "This product includes software developed by independent contributors
24  * and hosted on ObjectStyle Group web site (http://objectstyle.org/)."
25  * Alternately, this acknowlegement may appear in the software itself,
26  * if and wherever such third-party acknowlegements normally appear.
27  *
28  * 4. The names "ObjectStyle Group" and "Cayenne" must not be used to endorse
29  * or promote products derived from this software without prior written
30  * permission. For written permission, email
31  * "andrus at objectstyle dot org".
32  *
33  * 5. Products derived from this software may not be called "ObjectStyle"
34  * or "Cayenne", nor may "ObjectStyle" or "Cayenne" appear in their
35  * names without prior written permission.
36  *
37  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
38  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
39  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
40  * DISCLAIMED. IN NO EVENT SHALL THE OBJECTSTYLE GROUP OR
41  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
42  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
43  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
44  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
45  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
46  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
47  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
48  * SUCH DAMAGE.
49  * ====================================================================
50  *
51  * This software consists of voluntary contributions made by many
52  * individuals and hosted on ObjectStyle Group web site. For more
53  * information on the ObjectStyle Group, please see
54  * <http://objectstyle.org/>.
55  */

56 package org.objectstyle.cayenne.access;
57
58 import java.io.IOException JavaDoc;
59 import java.io.PrintWriter JavaDoc;
60 import java.io.StringWriter JavaDoc;
61 import java.sql.CallableStatement JavaDoc;
62 import java.sql.Connection JavaDoc;
63 import java.sql.ResultSet JavaDoc;
64 import java.sql.SQLException JavaDoc;
65 import java.sql.Statement JavaDoc;
66 import java.util.ArrayList JavaDoc;
67 import java.util.Collections JavaDoc;
68 import java.util.HashMap JavaDoc;
69 import java.util.List JavaDoc;
70 import java.util.Map JavaDoc;
71
72 import org.apache.log4j.Logger;
73 import org.objectstyle.cayenne.CayenneException;
74 import org.objectstyle.cayenne.DataRow;
75 import org.objectstyle.cayenne.access.types.ExtendedType;
76 import org.objectstyle.cayenne.map.DbEntity;
77 import org.objectstyle.cayenne.util.Util;
78
79 /**
80  * Default implementation of ResultIterator interface. Serves as a
81  * factory that creates data rows from <code>java.sql.ResultSet</code>.
82  *
83  * <p><i>For more information see <a HREF="../../../../../../userguide/index.html"
84  * target="_top">Cayenne User Guide.</a></i></p>
85  *
86  * @author Andrei Adamchik
87  * @deprecated Since 1.2 replaced by JDBCResultIterator.
88  */

89 public class DefaultResultIterator implements ResultIterator {
90     private static Logger logObj = Logger.getLogger(DefaultResultIterator.class);
91
92     // Connection information
93
protected Connection JavaDoc connection;
94     protected Statement JavaDoc statement;
95     protected ResultSet JavaDoc resultSet;
96
97     // Result descriptor
98
protected org.objectstyle.cayenne.access.util.ResultDescriptor descriptor;
99
100     protected int mapCapacity;
101
102     protected boolean closingConnection;
103     protected boolean isClosed;
104
105     protected boolean nextRow;
106     protected int fetchedSoFar;
107     protected int fetchLimit;
108
109     /**
110      * Utility method to read stored procedure out parameters as a map.
111      * Returns an empty map if no out parameters exist.
112      */

113     public static Map JavaDoc readProcedureOutParameters(
114         CallableStatement JavaDoc statement,
115         org.objectstyle.cayenne.access.util.ResultDescriptor resultDescriptor)
116         throws SQLException JavaDoc, Exception JavaDoc {
117
118         int resultWidth = resultDescriptor.getResultWidth();
119         if (resultWidth > 0) {
120             Map JavaDoc dataRow = new HashMap JavaDoc(resultWidth * 2, 0.75f);
121             ExtendedType[] converters = resultDescriptor.getConverters();
122             int[] jdbcTypes = resultDescriptor.getJdbcTypes();
123             String JavaDoc[] names = resultDescriptor.getNames();
124             int[] outParamIndexes = resultDescriptor.getOutParamIndexes();
125
126             // process result row columns,
127
for (int i = 0; i < outParamIndexes.length; i++) {
128                 int index = outParamIndexes[i];
129
130                 // note: jdbc column indexes start from 1, not 0 unlike everywhere else
131
Object JavaDoc val =
132                     converters[index].materializeObject(
133                         statement,
134                         index + 1,
135                         jdbcTypes[index]);
136                 dataRow.put(names[index], val);
137             }
138
139             return dataRow;
140         }
141
142         return Collections.EMPTY_MAP;
143     }
144
145     public DefaultResultIterator(
146         Connection JavaDoc connection,
147         Statement JavaDoc statement,
148         ResultSet JavaDoc resultSet,
149         org.objectstyle.cayenne.access.util.ResultDescriptor descriptor,
150         int fetchLimit)
151         throws SQLException JavaDoc, CayenneException {
152
153         this.connection = connection;
154         this.statement = statement;
155         this.resultSet = resultSet;
156         this.descriptor = descriptor;
157         this.fetchLimit = fetchLimit;
158
159         this.mapCapacity = (int) Math.ceil((descriptor.getNames().length) / 0.75);
160
161         checkNextRow();
162     }
163
164     /**
165      * Moves internal ResultSet cursor position down one row.
166      * Checks if the next row is available.
167      */

168     protected void checkNextRow() throws SQLException JavaDoc, CayenneException {
169         nextRow = false;
170         if ((fetchLimit <= 0 || fetchedSoFar < fetchLimit) && resultSet.next()) {
171             nextRow = true;
172             fetchedSoFar++;
173         }
174     }
175
176     /**
177      * Returns true if there is at least one more record
178      * that can be read from the iterator.
179      */

180     public boolean hasNextRow() {
181         return nextRow;
182     }
183
184     /**
185      * Returns the next result row as a Map.
186      */

187     public Map JavaDoc nextDataRow() throws CayenneException {
188         if (!hasNextRow()) {
189             throw new CayenneException("An attempt to read uninitialized row or past the end of the iterator.");
190         }
191
192         try {
193             // read
194
Map JavaDoc row = readDataRow();
195
196             // rewind
197
checkNextRow();
198
199             return row;
200         }
201         catch (SQLException JavaDoc sqex) {
202             throw new CayenneException("Exception reading ResultSet.", sqex);
203         }
204     }
205
206     /**
207      * Returns the number of columns in the result row.
208      *
209      * @since 1.0.6
210      */

211     public int getDataRowWidth() {
212         return descriptor.getResultWidth();
213     }
214
215     /**
216      * Returns all unread data rows from ResultSet, closing
217      * this iterator if needed.
218      */

219     public List JavaDoc dataRows(boolean close) throws CayenneException {
220         List JavaDoc list = new ArrayList JavaDoc();
221
222         try {
223             while (this.hasNextRow()) {
224                 list.add(this.nextDataRow());
225             }
226             return list;
227         }
228         finally {
229             if (close) {
230                 this.close();
231             }
232         }
233     }
234
235     /**
236      * Reads a row from the internal ResultSet at the current
237      * cursor position.
238      */

239     protected Map JavaDoc readDataRow() throws SQLException JavaDoc, CayenneException {
240         try {
241             Map JavaDoc dataRow = new DataRow(mapCapacity);
242             ExtendedType[] converters = descriptor.getConverters();
243             int[] jdbcTypes = descriptor.getJdbcTypes();
244             String JavaDoc[] names = descriptor.getNames();
245             int resultWidth = names.length;
246
247             // process result row columns,
248
for (int i = 0; i < resultWidth; i++) {
249                 // note: jdbc column indexes start from 1, not 0 unlike everywhere else
250
Object JavaDoc val =
251                     converters[i].materializeObject(resultSet, i + 1, jdbcTypes[i]);
252                 dataRow.put(names[i], val);
253             }
254
255             return dataRow;
256         }
257         catch (CayenneException cex) {
258             // rethrow unmodified
259
throw cex;
260         }
261         catch (Exception JavaDoc otherex) {
262             throw new CayenneException(
263                 "Exception materializing column.",
264                 Util.unwindException(otherex));
265         }
266     }
267
268     /**
269      * Reads a row from the internal ResultSet at the current
270      * cursor position, processing only columns that are part of the ObjectId
271      * of a target class.
272      */

273     protected Map JavaDoc readIdRow(DbEntity entity) throws SQLException JavaDoc, CayenneException {
274         try {
275             Map JavaDoc idRow = new DataRow(2);
276             ExtendedType[] converters = descriptor.getConverters();
277             int[] jdbcTypes = descriptor.getJdbcTypes();
278             String JavaDoc[] names = descriptor.getNames();
279             int[] idIndex = descriptor.getIdIndexes(entity);
280             int len = idIndex.length;
281
282             for (int i = 0; i < len; i++) {
283
284                 // dereference column index
285
int index = idIndex[i];
286
287                 // note: jdbc column indexes start from 1, not 0 as in arrays
288
Object JavaDoc val =
289                     converters[index].materializeObject(
290                         resultSet,
291                         index + 1,
292                         jdbcTypes[index]);
293                 idRow.put(names[index], val);
294             }
295
296             return idRow;
297         }
298         catch (CayenneException cex) {
299             // rethrow unmodified
300
throw cex;
301         }
302         catch (Exception JavaDoc otherex) {
303             logObj.warn("Error", otherex);
304             throw new CayenneException(
305                 "Exception materializing id column.",
306                 Util.unwindException(otherex));
307         }
308     }
309
310     /**
311      * Closes ResultIterator and associated ResultSet. This method must be
312      * called explicitly when the user is finished processing the records.
313      * Otherwise unused database resources will not be released properly.
314      */

315     public void close() throws CayenneException {
316         if (!isClosed) {
317
318             nextRow = false;
319
320             StringWriter JavaDoc errors = new StringWriter JavaDoc();
321             PrintWriter JavaDoc out = new PrintWriter JavaDoc(errors);
322
323             try {
324                 resultSet.close();
325             }
326             catch (SQLException JavaDoc e1) {
327                 out.println("Error closing ResultSet");
328                 e1.printStackTrace(out);
329             }
330
331             if (statement != null) {
332                 try {
333                     statement.close();
334                 }
335                 catch (SQLException JavaDoc e2) {
336                     out.println("Error closing PreparedStatement");
337                     e2.printStackTrace(out);
338                 }
339             }
340
341             // close connection, if this object was explicitly configured to be
342
// responsible for doing it
343
if (connection != null && this.isClosingConnection()) {
344                 try {
345                     connection.close();
346                 }
347                 catch (SQLException JavaDoc e3) {
348                     out.println("Error closing Connection");
349                     e3.printStackTrace(out);
350                 }
351             }
352
353             try {
354                 out.close();
355                 errors.close();
356             }
357             catch (IOException JavaDoc ioex) {
358                 // this is totally unexpected,
359
// after all we are writing to the StringBuffer
360
// in the memory
361
}
362             StringBuffer JavaDoc buf = errors.getBuffer();
363
364             if (buf.length() > 0) {
365                 throw new CayenneException("Error closing ResultIterator: " + buf);
366             }
367
368             isClosed = true;
369         }
370     }
371
372     /**
373      * Returns <code>true</code> if this iterator is responsible
374      * for closing its connection, otherwise a user of the iterator
375      * must close the connection after closing the iterator.
376      */

377     public boolean isClosingConnection() {
378         return closingConnection;
379     }
380
381     /**
382      * Sets the <code>closingConnection</code> property.
383      */

384     public void setClosingConnection(boolean flag) {
385         this.closingConnection = flag;
386     }
387
388     /**
389      * @see org.objectstyle.cayenne.access.ResultIterator#skipDataRow()
390      */

391     public void skipDataRow() throws CayenneException {
392         if (!hasNextRow()) {
393             throw new CayenneException("An attempt to read uninitialized row or past the end of the iterator.");
394         }
395
396         try {
397             checkNextRow();
398         }
399         catch (SQLException JavaDoc sqex) {
400             throw new CayenneException("Exception reading ResultSet.", sqex);
401         }
402     }
403
404     /**
405      * Returns a map of ObjectId values from the next result row.
406      * Primary key columns are determined from the provided DbEntity.
407      *
408      * @since 1.1
409      */

410     public Map JavaDoc nextObjectId(DbEntity entity) throws CayenneException {
411         if (!hasNextRow()) {
412             throw new CayenneException("An attempt to read uninitialized row or past the end of the iterator.");
413         }
414
415         try {
416             // read
417
Map JavaDoc row = readIdRow(entity);
418
419             // rewind
420
checkNextRow();
421
422             return row;
423         }
424         catch (SQLException JavaDoc sqex) {
425             throw new CayenneException("Exception reading ResultSet.", sqex);
426         }
427     }
428 }
429
Popular Tags