KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > jcorporate > expresso > core > dataobjects > jdbc > LobField


1 /* ====================================================================
2  * The Jcorporate Apache Style Software License, Version 1.2 05-07-2002
3  *
4  * Copyright (c) 1995-2002 Jcorporate Ltd. All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright
11  * notice, this list of conditions and the following disclaimer.
12  *
13  * 2. Redistributions in binary form must reproduce the above copyright
14  * notice, this list of conditions and the following disclaimer in
15  * the documentation and/or other materials provided with the
16  * distribution.
17  *
18  * 3. The end-user documentation included with the redistribution,
19  * if any, must include the following acknowledgment:
20  * "This product includes software developed by Jcorporate Ltd.
21  * (http://www.jcorporate.com/)."
22  * Alternately, this acknowledgment may appear in the software itself,
23  * if and wherever such third-party acknowledgments normally appear.
24  *
25  * 4. "Jcorporate" and product names such as "Expresso" must
26  * not be used to endorse or promote products derived from this
27  * software without prior written permission. For written permission,
28  * please contact info@jcorporate.com.
29  *
30  * 5. Products derived from this software may not be called "Expresso",
31  * or other Jcorporate product names; nor may "Expresso" or other
32  * Jcorporate product names appear in their name, without prior
33  * written permission of Jcorporate Ltd.
34  *
35  * 6. No product derived from this software may compete in the same
36  * market space, i.e. framework, without prior written permission
37  * of Jcorporate Ltd. For written permission, please contact
38  * partners@jcorporate.com.
39  *
40  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
41  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
42  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
43  * DISCLAIMED. IN NO EVENT SHALL JCORPORATE LTD OR ITS CONTRIBUTORS
44  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
45  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
46  * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
47  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
48  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
49  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
50  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
51  * SUCH DAMAGE.
52  * ====================================================================
53  *
54  * This software consists of voluntary contributions made by many
55  * individuals on behalf of the Jcorporate Ltd. Contributions back
56  * to the project(s) are encouraged when you make modifications.
57  * Please send them to support@jcorporate.com. For more information
58  * on Jcorporate Ltd. and its products, please see
59  * <http://www.jcorporate.com/>.
60  *
61  * Portions of this software are based upon other open source
62  * products and are subject to their respective licenses.
63  */

64 package com.jcorporate.expresso.core.dataobjects.jdbc;
65
66 import com.jcorporate.expresso.core.dataobjects.DataException;
67 import com.jcorporate.expresso.core.dataobjects.DataFieldMetaData;
68 import com.jcorporate.expresso.core.db.DBConnection;
69 import com.jcorporate.expresso.core.db.DBConnectionPool;
70 import com.jcorporate.expresso.core.db.DBException;
71 import com.jcorporate.expresso.core.db.TypeMapper;
72 import com.jcorporate.expresso.kernel.util.FastStringBuffer;
73 import org.apache.log4j.Logger;
74
75 import java.io.IOException JavaDoc;
76 import java.io.InputStream JavaDoc;
77 import java.io.OutputStream JavaDoc;
78 import java.io.StringReader JavaDoc;
79 import java.io.Writer JavaDoc;
80 import java.lang.reflect.InvocationTargetException JavaDoc;
81 import java.lang.reflect.Method JavaDoc;
82 import java.sql.Blob JavaDoc;
83 import java.sql.Clob JavaDoc;
84 import java.sql.PreparedStatement JavaDoc;
85 import java.sql.ResultSet JavaDoc;
86 import java.sql.SQLException JavaDoc;
87
88 /**
89  * This class provides a low level BLOB capability while still keeping the
90  * programmer isolated from SQL syntax details.
91  * <p>The general usage is as follows:<br/>
92  * <code>
93  * &nbsp;MyDBObject myObj.setField("key1",1);<br/>
94  * &nbsp;LobField query = new LobField();<br/>
95  * &nbsp;query.setCriteria(myObj);<br/>
96  * &nbsp;java.io.InputStream inputStream = getBlobStream("blobFieldName");
97  * &nbsp; //Do whatever you want with the stream <br/>
98  * &nbsp; inputStream.flush();
99  * &nbsp; inputStream.close();
100  * &nbsp; query.close();
101  * </code>
102  * </p>
103  * <p>This class requires a JDBC 2 compliant driver for the BLOB/CLOB data types.
104  * Some drivers do not support these features, at which point you'll want
105  * to use the getBlobStream/getClobStream/getClobAsciiStream methods instead
106  * </p>
107  *
108  * @author Michael Rimov
109  * @since $DatabaseSchema $Date: 2004/11/18 02:03:27 $
110  */

111
112 public class LobField {
113
114     /**
115      * The dataobject to use to build the SQL search/update statements.
116      */

117     protected JDBCDataObject criteria = null;
118
119     /**
120      * The log4j Logger to use.
121      */

122     private Logger log = Logger.getLogger(LobField.class);
123
124     boolean alreadyInTransaction = false;
125
126     protected DBConnection myConnection = null;
127
128     /**
129      * Default constructor. Currently does nothing.
130      */

131     public LobField() {
132
133     }
134
135     /**
136      * Set the search criteria for the blob. All key fields must be present
137      * as this does a full retrieve() rather than a search on the data. Otherwise
138      * the object will throw an exception .
139      *
140      * @param newCriteria a filled out JDBCObject (DBObject derived classes work)
141      * with all keys present
142      * @throws DataException if all keys are not present.
143      */

144     public void setCriteria(JDBCDataObject newCriteria) throws DataException {
145         if (newCriteria == null) {
146             throw new IllegalArgumentException JavaDoc("Criteria cannot be null");
147         }
148
149         criteria = newCriteria;
150         if (newCriteria.getLocalConnection() != null) {
151             myConnection = newCriteria.getLocalConnection();
152         }
153     }
154
155
156     /**
157      * Protected method to get at the criteria object from any derived classes
158      *
159      * @return JDBCDataObject or null if no criteria has been set
160      */

161     protected JDBCDataObject getCriteria() {
162         return criteria;
163     }
164
165
166     /**
167      * Retrieves a <code>java.sql.Blob</code> object given the criteria object
168      * set previously.
169      *
170      * @param fieldName the name of the field to retrieve
171      * @return java.sql.Blob for the field
172      * @throws DataException if there is an error finding the object, an error
173      * retrieving the Blob from the system, or other database communication
174      * errors.
175      */

176     public Blob JavaDoc getBlob(String JavaDoc fieldName) throws DataException {
177         if (getCriteria() == null) {
178             throw new IllegalArgumentException JavaDoc("Criteria must be set before calling getBLob");
179         }
180
181         try {
182             if (myConnection == null) {
183                 myConnection = DBConnectionPool.getInstance(getCriteria()
184                         .getMappedDataContext()).getConnection("LOB Field Connection");
185             }
186         } catch (DBException ex) {
187             throw new DataException("Error getting Database" +
188                     " Connection for BLOB Retrieval", ex);
189         }
190
191         return getBLOB(getCriteria(), fieldName, myConnection);
192     }
193
194     /**
195      * Retrieves a <code>java.sql.Clob</code> object given the criteria object
196      * set previously.
197      *
198      * @param fieldName the name of the field to retrieve
199      * @return java.sql.Clob for the field
200      * @throws DataException if there is an error finding the object, an error
201      * retrieving the Clob from the system, or other database communication
202      * errors.
203      */

204     public Clob JavaDoc getClob(String JavaDoc fieldName) throws DataException {
205         if (getCriteria() == null) {
206             throw new IllegalArgumentException JavaDoc("Criteria must be set before calling getClob");
207         }
208
209         try {
210             if (myConnection == null) {
211                 myConnection = DBConnectionPool.getInstance(getCriteria()
212                         .getMappedDataContext()).getConnection("LOB Field Connection");
213             }
214         } catch (DBException ex) {
215             throw new DataException("Error getting Database" +
216                     " Connection for CLOB Retrieval", ex);
217         }
218
219         return getCLOB(getCriteria(), fieldName, myConnection);
220     }
221
222
223     /**
224      * Retrieve an input stream for a binary object stored in the database.
225      *
226      * @param fieldName the field name to retrieve.
227      * @return java.io.InputStream representing the BLOB object
228      * @throws DataException upon error
229      */

230     public InputStream JavaDoc getBlobStream(String JavaDoc fieldName) throws DataException {
231         if (getCriteria() == null) {
232             throw new IllegalArgumentException JavaDoc("Criteria must be set before calling getBLob");
233         }
234
235         try {
236             if (myConnection == null) {
237                 myConnection = DBConnectionPool.getInstance(getCriteria()
238                         .getMappedDataContext()).getConnection("LOB Field Connection");
239             }
240         } catch (DBException ex) {
241             throw new DataException("Error getting Database" +
242                     " Connection for BLOB Retrieval", ex);
243         }
244
245         try {
246             prepSelectResultSet(getCriteria(), fieldName, myConnection);
247             if (myConnection.next()) {
248                 return myConnection.getBinaryStream(1);
249             } else {
250                 return null;
251             }
252         } catch (DBException ex) {
253             throw new DataException("Error getting binary stream", ex);
254         }
255
256     }
257
258     /**
259      * Retrieve a java.io.Reader a.k.a Unicode stream for a CLOB field.
260      *
261      * @param fieldName the name of the field to retrieve.
262      * @return java.io.Reader for the Unicode CLOB stream stored in the database
263      * @throws DataException upon error retrieving the CLOB
264      */

265     public java.io.Reader JavaDoc getClobStream(String JavaDoc fieldName) throws DataException {
266         if (getCriteria() == null) {
267             throw new IllegalArgumentException JavaDoc("Criteria must be set before calling getBLob");
268         }
269
270         try {
271             if (myConnection == null) {
272                 myConnection = DBConnectionPool.getInstance(getCriteria()
273                         .getMappedDataContext()).getConnection("LOB Field Connection");
274             }
275         } catch (DBException ex) {
276             throw new DataException("Error getting Database" +
277                     " Connection for BLOB Retrieval", ex);
278         }
279
280         return this.getCLOBReader(getCriteria(), fieldName, myConnection);
281     }
282
283     /**
284      * CLOB convenience method. Reads the entire stream into a string. Note
285      * that if your field is large, this may take large amounts of memory
286      * to perform this operation. It is recommended to use getClobStream()
287      * for most purposes.
288      * <p>Note that this method is not supported by InterBase/InterClient 2 which
289      * does not support Unicode streams. Use getClobAsciiStream instead</p>
290      *
291      * @param fieldName the name of the field to retrieve
292      * @return java.lang.String containing the entire contents of the CLOB
293      * field.
294      * @throws DataException upon error.
295      */

296     public String JavaDoc getClobString(String JavaDoc fieldName) throws DataException {
297         java.io.Reader JavaDoc is = this.getClobStream(fieldName);
298         if (is == null) {
299             return null;
300         }
301
302         FastStringBuffer fsb = FastStringBuffer.getInstance();
303         try {
304
305             char[] buf = new char[1024]; // 1K buffer
306
int bytesRead;
307
308             while ((bytesRead = is.read(buf)) != -1) {
309                 fsb.append(buf, 0, bytesRead);
310             }
311
312             return fsb.toString();
313         } catch (java.io.IOException JavaDoc ex) {
314             throw new DataException("I/O Exception reading Character Stream");
315         } finally {
316             fsb.release();
317         }
318
319     }
320
321     /**
322      * Retrieve a java.io.InputStream a.k.a. ASCII stream for a CLOB field.
323      *
324      * @param fieldName the name of the field to retrieve.
325      * @return java.io.Reader for the ASCII CLOB stream stored in the database
326      * @throws DataException upon error retrieving the CLOB
327      */

328     public InputStream JavaDoc getClobAsciiStream(String JavaDoc fieldName) throws DataException {
329         try {
330             Clob JavaDoc theClob = getClob(fieldName);
331             return theClob.getAsciiStream();
332         } catch (SQLException JavaDoc ex) {
333             throw new DataException("Error getting clob ascii stream: " + fieldName, ex);
334         }
335     }
336
337
338     /**
339      * Saves an InputStream into the database given the criteria and the fieldname
340      * (Criteria should have been previously set).
341      *
342      * @param fieldName The name of the field to save the Stream to.
343      * @param data a java.io.InputStream object to save to the field. May be null
344      * if you want the field to be null.
345      * @param dataSize the length of the stream to save.
346      * @throws DataException upon database communications error.
347      * @throws IllegalArgumentException if fieldName is null.
348      */

349     public void saveBlob(String JavaDoc fieldName, InputStream JavaDoc data, int dataSize) throws DataException {
350         try {
351             if (myConnection == null) {
352                 myConnection = DBConnectionPool.getInstance(getCriteria()
353                         .getMappedDataContext()).getConnection("LOB Field Connection");
354
355                 if ("org.hsqldb.jdbcDriver".equals(myConnection.getDBDriver())) {
356                     //check the database size.
357
//Hypersonic has a maximum practical capability of 200K MAX
358
if (dataSize > 1024 * 200) {
359                         throw new DataException("HSQLDB can only store maxium of 200K files");
360                     }
361                 }
362             }
363         } catch (DBException ex) {
364             throw new DataException("Error getting Database" +
365                     " Connection for BLOB Retrieval", ex);
366         }
367
368         try {
369             alreadyInTransaction = !(myConnection.getAutoCommit());
370         } catch (DBException ex) {
371             throw new DataException("Error getting Database" +
372                     " Connection transaction parameter for BLOB Retrieval", ex);
373         }
374
375         // if running Oracle, use Oracle specific methods because of Oracle's
376
// incompatibility with standard jdbc LOB mothods
377
if ("oracle.jdbc.driver.OracleDriver".equals(myConnection.getDBDriver())) {
378             oracleSaveBlob(fieldName, data, dataSize);
379             return;
380         }
381
382
383         PreparedStatement JavaDoc preparedStatement = prepUpdate(getCriteria(), fieldName, myConnection);
384
385         try {
386             if (data == null) {
387                 DataFieldMetaData metaData = getCriteria().getFieldMetaData(fieldName);
388                 int typeCode = TypeMapper.getInstance(getCriteria().getMappedDataContext())
389                         .getJavaSQLType(metaData.getTypeString());
390                 preparedStatement.setNull(1, typeCode);
391             } else {
392                 preparedStatement.setBinaryStream(1, data, dataSize);
393             }
394         } catch (SQLException JavaDoc ex) {
395             throw new DataException("Unable to set CharacterStream to CLOB object.", ex);
396         } catch (DBException ex) {
397             throw new DataException("Unable to get Type Mapping information for Clob field", ex);
398         }
399
400         finalizeUpdate(myConnection);
401
402     }
403
404     /**
405      * Saves a <code>java.sql.Blob</code> to the record matching the criteria
406      * earlier set.
407      *
408      * @param fieldName the name of the field to save to
409      * @param data the <code>java.sql.Blob</code> based object to save to the
410      * database.
411      * @throws DataException upon database communication error
412      * @throws IllegalArgumentException if data is null
413      */

414     public void saveBlob(String JavaDoc fieldName, Blob JavaDoc data) throws DataException {
415         try {
416             if (myConnection == null) {
417                 myConnection = DBConnectionPool.getInstance(getCriteria()
418                         .getMappedDataContext()).getConnection("LOB Field Connection");
419             }
420         } catch (DBException ex) {
421             throw new DataException("Error getting Database" +
422                     " Connection for BLOB Retrieval", ex);
423         }
424
425         try {
426             alreadyInTransaction = !(myConnection.getAutoCommit());
427         } catch (DBException ex) {
428             throw new DataException("Error getting Database" +
429                     " Connection transaction parameter for BLOB Retrieval", ex);
430         }
431         PreparedStatement JavaDoc preparedStatement = prepUpdate(getCriteria(), fieldName, myConnection);
432
433         try {
434             if (data == null) {
435                 DataFieldMetaData metaData = getCriteria().getFieldMetaData(fieldName);
436                 int typeCode = TypeMapper.getInstance(getCriteria().getMappedDataContext())
437                         .getJavaSQLType(metaData.getTypeString());
438                 preparedStatement.setNull(1, typeCode);
439             } else {
440                 preparedStatement.setBlob(1, data);
441             }
442         } catch (SQLException JavaDoc ex) {
443             throw new DataException("Unable to set CharacterStream to CLOB object.", ex);
444         } catch (DBException ex) {
445             throw new DataException("Unable to get type mapping information", ex);
446         }
447
448         finalizeUpdate(myConnection);
449
450     }
451
452     /**
453      * Saves an InputStream into the database given the criteria and the fieldname
454      * (Criteria should have been previously set).
455      *
456      * @param fieldName The name of the field to save the Stream to.
457      * @param data a java.io.InputStream object to save to the field. May be null
458      * if you want the field to be null.
459      * @param length The size of the CLOB stream to save to the database
460      * @throws IllegalArgumentException if fieldName is null.
461      * @throws DataException upon database communications error.
462      */

463     public void saveClob(String JavaDoc fieldName, InputStream JavaDoc data, int length) throws DataException {
464
465         try {
466             if (myConnection == null) {
467                 myConnection = DBConnectionPool.getInstance(getCriteria()
468                         .getMappedDataContext()).getConnection("LOB Field Connection");
469             }
470         } catch (DBException ex) {
471             throw new DataException("Error getting Database" +
472                     " Connection for BLOB Retrieval", ex);
473         }
474
475         try {
476             alreadyInTransaction = !(myConnection.getAutoCommit());
477         } catch (DBException ex) {
478             throw new DataException("Error getting Database" +
479                     " Connection transaction parameter for BLOB Retrieval", ex);
480         }
481
482         // if running Oracle, use Oracle specific methods because of Oracle's incompatibility
483
// with standard jdbc LOB methods
484
if ("oracle.jdbc.driver.OracleDriver".equals(myConnection.getDBDriver())) {
485             oracleSaveClob(fieldName, data, length);
486             return;
487         }
488
489         PreparedStatement JavaDoc preparedStatement = prepUpdate(getCriteria(), fieldName, myConnection);
490
491         try {
492             if (data == null) {
493                 DataFieldMetaData metaData = getCriteria().getFieldMetaData(fieldName);
494                 int typeCode = TypeMapper.getInstance(getCriteria().getMappedDataContext())
495                         .getJavaSQLType(metaData.getTypeString());
496                 preparedStatement.setNull(1, typeCode);
497             } else {
498                 preparedStatement.setAsciiStream(1, data, length);
499             }
500         } catch (SQLException JavaDoc ex) {
501             throw new DataException("Unable to set CharacterStream to CLOB object.", ex);
502         } catch (DBException ex) {
503             throw new DataException("Unable to get type mapping information for CLOB object", ex);
504         }
505
506         finalizeUpdate(myConnection);
507
508     }
509
510     /**
511      * Saves an InputStream into the database given the criteria and the fieldname
512      * (Criteria should have been previously set).
513      *
514      * @param fieldName The name of the field to save the Stream to.
515      * @param data a java.io.Reader object to save to the field. May be null
516      * if you want the field to be null.
517      * @param length The size of the data stream to save to the database
518      * @throws DataException upon database communications error.
519      * @throws IllegalArgumentException if fieldName is null.
520      */

521     public void saveClob(String JavaDoc fieldName, java.io.Reader JavaDoc data, int length) throws DataException {
522
523         try {
524             if (myConnection == null) {
525                 myConnection = DBConnectionPool.getInstance(getCriteria()
526                         .getMappedDataContext()).getConnection("LOB Field Connection");
527             }
528         } catch (DBException ex) {
529             throw new DataException("Error getting Database" +
530                     " Connection for BLOB Retrieval", ex);
531         }
532
533         try {
534             alreadyInTransaction = !(myConnection.getAutoCommit());
535         } catch (DBException ex) {
536             throw new DataException("Error getting Database" +
537                     " Connection transaction parameter for BLOB Retrieval", ex);
538         }
539
540         if ("interbase.interclient.Driver".equals(myConnection.getDBDriver())) {
541             throw new DataException("InterBase Interclient 2 cannot support unicode data. " +
542                     " Must use saveClob(String, InputStream, length)" +
543                     "instead");
544         }
545
546         // if running Oracle, use Oracle specific methods because of Oracle's
547
// incompatibility with standard jdbc LOB mothods
548
if ("oracle.jdbc.driver.OracleDriver".equals(myConnection.getDBDriver())) {
549             if (data == null) {
550                 oracleSaveClob(fieldName, (StringReader JavaDoc) null, 0);
551             } else {
552                 oracleSaveClob(fieldName, data, length);
553             }
554             return;
555         }
556
557         PreparedStatement JavaDoc preparedStatement = prepUpdate(getCriteria(), fieldName, myConnection);
558
559         try {
560             if (data == null) {
561                 DataFieldMetaData metaData = getCriteria().getFieldMetaData(fieldName);
562                 int typeCode = TypeMapper.getInstance(getCriteria().getMappedDataContext())
563                         .getJavaSQLType(metaData.getTypeString());
564                 preparedStatement.setNull(1, typeCode);
565             } else {
566                 preparedStatement.setCharacterStream(1, data, length);
567             }
568         } catch (SQLException JavaDoc ex) {
569             throw new DataException("Unable to set CharacterStream to CLOB object.", ex);
570         } catch (DBException ex) {
571             throw new DataException("Unable to get type mapping information for CLOB field", ex);
572         }
573
574         finalizeUpdate(myConnection);
575     }
576
577     /**
578      * Saves a string to a CLOB field.
579      *
580      * @param fieldName the name of the field to save to.
581      * @param data the String value to save to the field.
582      * @throws DataException upon error
583      */

584     public void saveClob(String JavaDoc fieldName, String JavaDoc data) throws DataException {
585         try {
586             if (myConnection == null) {
587                 myConnection = DBConnectionPool.getInstance(getCriteria()
588                         .getMappedDataContext()).getConnection("LOB Field Connection");
589             }
590         } catch (DBException ex) {
591             throw new DataException("Error getting Database" +
592                     " Connection for BLOB Retrieval", ex);
593         }
594
595         try {
596             alreadyInTransaction = !(myConnection.getAutoCommit());
597         } catch (DBException ex) {
598             throw new DataException("Error getting Database" +
599                     " Connection transaction parameter for BLOB Retrieval", ex);
600         }
601
602         // if running Oracle, use Oracle specific methods because of Oracle's
603
// incompatibility with standard jdbc LOB mothods
604
if ("oracle.jdbc.driver.OracleDriver".equals(myConnection.getDBDriver())) {
605             if (data == null) {
606                 oracleSaveClob(fieldName, (StringReader JavaDoc) null, 0);
607             } else {
608                 oracleSaveClob(fieldName, new StringReader JavaDoc(data), data.length());
609             }
610             return;
611         }
612
613         PreparedStatement JavaDoc preparedStatement = prepUpdate(getCriteria(), fieldName, myConnection);
614
615         try {
616             if (data == null) {
617                 DataFieldMetaData metaData = getCriteria().getFieldMetaData(fieldName);
618                 int typeCode = TypeMapper.getInstance(getCriteria().getMappedDataContext())
619                         .getJavaSQLType(metaData.getTypeString());
620                 preparedStatement.setNull(1, typeCode);
621             } else {
622                 if ("interbase.interclient.Driver".equals(myConnection.getDBDriver())) {
623                     //
624
//Workaround, interclient 2 doesn't support setCharacterStream()
625
//
626
byte[] dataArray = data.getBytes();
627                     java.io.ByteArrayInputStream JavaDoc bis = new java.io.ByteArrayInputStream JavaDoc(dataArray);
628                     preparedStatement.setAsciiStream(1, bis, dataArray.length);
629                 } else {
630                     java.io.Reader JavaDoc r = new java.io.StringReader JavaDoc(data);
631                     preparedStatement.setCharacterStream(1, r, data.length());
632                 }
633             }
634         } catch (SQLException JavaDoc ex) {
635             throw new DataException("Unable to set CharacterStream to CLOB object.", ex);
636         } catch (DBException ex) {
637             throw new DataException("Unable to get type information for CLOB field", ex);
638         }
639
640         finalizeUpdate(myConnection);
641
642     }
643
644     /**
645      * Saves an InputStream into the database given the criteria and the fieldname
646      * (Criteria should have been previously set).
647      *
648      * @param fieldName The name of the field to save the Stream to.
649      * @param data a java.io.Reader object to save to the field. May be null
650      * if you want the field to be null.
651      * @throws DataException upon database communications error.
652      * @throws IllegalArgumentException if fieldName is null.
653      */

654     public void saveClob(String JavaDoc fieldName, Clob JavaDoc data) throws DataException {
655
656         try {
657             if (myConnection == null) {
658                 myConnection = DBConnectionPool.getInstance(getCriteria()
659                         .getMappedDataContext()).getConnection("LOB Field Connection");
660             }
661         } catch (DBException ex) {
662             throw new DataException("Error getting Database" +
663                     " Connection for BLOB Retrieval", ex);
664         }
665
666         try {
667             alreadyInTransaction = !(myConnection.getAutoCommit());
668         } catch (DBException ex) {
669             throw new DataException("Error getting Database" +
670                     " Connection transaction parameter for BLOB Retrieval", ex);
671         }
672
673         PreparedStatement JavaDoc preparedStatement = prepUpdate(getCriteria(), fieldName, myConnection);
674
675         try {
676             if (data == null) {
677                 DataFieldMetaData metaData = getCriteria().getFieldMetaData(fieldName);
678                 int typeCode = TypeMapper.getInstance(getCriteria().getMappedDataContext())
679                         .getJavaSQLType(metaData.getTypeString());
680                 preparedStatement.setNull(1, typeCode);
681             } else {
682                 preparedStatement.setClob(1, data);
683             }
684         } catch (SQLException JavaDoc ex) {
685             throw new DataException("Unable to set CharacterStream to CLOB object.", ex);
686         } catch (DBException ex) {
687             throw new DataException("Unable to get type mapping information for CLOB field", ex);
688         }
689
690         finalizeUpdate(myConnection);
691     }
692
693
694     /**
695      * Close the query resources held by the object. This should be wrapped
696      * in a try/finally block so that database connection resources are not
697      * left floating in limbo.
698      */

699     public void close() {
700         if (myConnection != null) {
701             if (log.isDebugEnabled()) {
702                 log.debug("Closing and releasing LOB connection");
703             }
704             try {
705                 if (!alreadyInTransaction && myConnection.supportsTransactions()) {
706                     myConnection.release();
707                 }
708             } catch (DBException ex) {
709 // throw new DataException("Error getting Database" +
710
// " Connection transaction parameter for BLOB Retrieval", ex);
711
}
712             myConnection = null;
713         }
714     }
715
716     /**
717      * Override of base object finalization to make sure that the database
718      * resources are closed if for some reason they haven't had this done
719      * to them already.
720      */

721     protected void finalize() throws java.lang.Throwable JavaDoc {
722         if (myConnection != null) {
723             log.warn("LobField was not closed before Garbage Collection!");
724             close();
725         }
726         super.finalize();
727     }
728
729
730     /**
731      * Retrieves the CLOB data for the specified DBObject and the specified
732      * fieldName
733      *
734      * @param baseObject The dbobject containing all the table information, and
735      * key fields set.
736      * @param fieldName The name of the field to retrieve as a LOB.
737      * @param theConnection a <code>DBConnection</code> object that has already
738      * been retrieved from the <code>DBConnectionPool</code>
739      * @return a java.sql.CLOB object.
740      * @throws DataException if there's an error executing the statement
741      */

742     private Clob JavaDoc getCLOB(JDBCDataObject baseObject,
743                          String JavaDoc fieldName,
744                          DBConnection theConnection) throws DataException {
745         prepSelectResultSet(baseObject, fieldName, theConnection);
746
747         try {
748             if (theConnection.next()) {
749                 return theConnection.getClob(fieldName);
750             }
751         } catch (DBException ex) {
752             throw new DataException("Error getting CLOB object from connection", ex);
753         }
754
755         return null;
756     }
757
758     /**
759      * Retrieves the CLOB data for the specified DBObject and the specified
760      * fieldName
761      *
762      * @param baseObject The dbobject containing all the table information, and
763      * key fields set.
764      * @param fieldName The name of the field to retrieve as a LOB.
765      * @param theConnection a <code>DBConnection</code> object that has already
766      * been retrieved from the <code>DBConnectionPool</code>
767      * @return a Reader object.
768      * @throws DataException if there's an error executing the statement
769      */

770     private java.io.Reader JavaDoc getCLOBReader(JDBCDataObject baseObject,
771                                          String JavaDoc fieldName,
772