001 package org.apache.ojb.broker.platforms;
002
003 /* Copyright 2003-2005 The Apache Software Foundation
004 *
005 * Licensed under the Apache License, Version 2.0 (the "License");
006 * you may not use this file except in compliance with the License.
007 * You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017
018 import org.apache.ojb.broker.util.logging.Logger;
019 import org.apache.ojb.broker.util.logging.LoggerFactory;
020
021 import java.io.*;
022 import java.sql.Connection;
023 import java.lang.reflect.InvocationTargetException;
024
025 /**
026 * Handles the Oracle LOB problems for 9i.
027 *
028 * @author <a href="mailto:mattbaird@yahoo.com">Matthew Baird<a>
029 * @author <a href="mailto:erik@cj.com">Erik Forkalsrud</a>
030 * @author <a href="mailto:martin.kalen@curalia.se">Martin Kalén</a>
031 * @version CVS $Id: Oracle9iLobHandler.java,v 1.1 2007-08-24 22:17:35 ewestfal Exp $
032 */
033 public class Oracle9iLobHandler
034 {
035
036 protected static Logger logger = LoggerFactory.getLogger(Oracle9iLobHandler.class);
037
038 private static ClobWrapper createTempCLOB(Connection connection, ClobWrapper clob)
039 {
040 if (clob == null) {
041 return null;
042 }
043
044 ClobWrapper tempClob = null;
045 try
046 {
047 // Create a temporary CLOB with duration session
048 tempClob = ClobWrapper.createTemporary(connection, true, ClobWrapper.getDurationSessionValue());
049
050 // Open the CLOB in readonly mode
051 clob.open(ClobWrapper.getModeReadOnlyValue());
052
053 // Open the temporary CLOB in readwrite mode to enable writing
054 tempClob.open(ClobWrapper.getModeReadWriteValue());
055
056 // No of bytes read each trip to database
057 int bytesread;
058
059 // Get the input stream for reading from the CLOB
060 Reader clobReader = clob.getCharacterStream();
061
062 // Get the output stream for writing into the CLOB
063 Writer tempClobWriter = tempClob.getCharacterOutputStream();
064
065 // Create a buffer to read data
066 // getBufferSize() returns the optimal buffer size
067 char[] charbuffer = new char[clob.getBufferSize()];
068
069 // Read from the CLOB and write into the temporary CLOB
070 while ((bytesread = clobReader.read(charbuffer)) != -1)
071 {
072 tempClobWriter.write(charbuffer, 0, bytesread);
073 }
074
075 // Flush and close the streams
076 tempClobWriter.flush();
077 tempClobWriter.close();
078 clobReader.close();
079
080 // Close the CLOBs
081 clob.close();
082 tempClob.close();
083 }
084 catch (Exception e)
085 {
086 logger.error("Error during temporary CLOB write", e);
087 freeTempLOB(tempClob, null);
088 }
089 return tempClob;
090 }
091
092 public static String convertCLOBtoString(Connection connection, Object nativeclob)
093 {
094 ClobWrapper temp = new ClobWrapper();
095 temp.setClob(nativeclob);
096 /**
097 * first, convert the clob to another clob. Thanks Oracle, you rule.
098 */
099 ClobWrapper clob = createTempCLOB(connection, temp);
100
101 if (clob == null) {
102 return null;
103 }
104
105 String retval = null;
106 // Buffer to hold the CLOB data
107 StringBuffer clobdata = new StringBuffer();
108 // No of bytes read each trip to database
109 int bytesread = 0;
110 try
111 {
112 // Open the CLOB in readonly mode
113 clob.open(ClobWrapper.getModeReadOnlyValue());
114 // Open the stream to read data
115 Reader clobReader = clob.getCharacterStream();
116 // Buffer size is fixed using the getBufferSize() method which returns
117 // the optimal buffer size to read data from the LOB
118 char[] charbuffer = new char[clob.getBufferSize()];
119 // Keep reading from the CLOB and append it to the stringbuffer till
120 // there is no more to read
121 while ((bytesread = clobReader.read(charbuffer)) != -1)
122 {
123 clobdata.append(charbuffer, 0, bytesread);
124 }
125 // Close the input stream
126 clobReader.close();
127 // Close the CLOB
128 clob.close();
129 retval = clobdata.toString();
130 clobdata = null;
131 }
132 catch (Exception e)
133 {
134 logger.error("Error during CLOB read", e);
135 freeTempLOB(clob, null);
136 }
137 return retval;
138 }
139
140 public static Object createCLOBFromString(Connection conn, String clobData)
141 {
142 if (clobData == null) {
143 return null;
144 }
145 ClobWrapper clob = null;
146 try
147 {
148 clob = ClobWrapper.createTemporary(conn, true, ClobWrapper.getDurationSessionValue());
149 if (clob != null) {
150 // Open the temporary CLOB in readwrite mode to enable writing
151 clob.open(ClobWrapper.getModeReadWriteValue());
152
153 // Clear the previous contents of the CLOB
154 clob.trim(0);
155
156 // Get the output stream to write
157 Writer tempClobWriter = clob.getCharacterOutputStream();
158
159 if (tempClobWriter != null) {
160 // Write the data into the temporary CLOB
161 tempClobWriter.write(clobData);
162
163 // Flush and close the stream
164 tempClobWriter.flush();
165 tempClobWriter.close();
166 }
167
168 // Close the temporary CLOB
169 clob.close();
170 }
171 }
172 catch (InvocationTargetException ite) {
173 Throwable t = ite.getTargetException();
174 freeTempLOB(clob, null);
175 if (t instanceof java.lang.UnsatisfiedLinkError) {
176 logger.error("Oracle JDBC-driver version does not match installed OCI-driver");
177 } else {
178 logger.error("Error during temporary CLOB write", t);
179 }
180 }
181 catch (Exception e)
182 {
183 logger.error("Error during temporary CLOB write", e);
184 freeTempLOB(clob, null);
185 }
186 return clob == null ? null : clob.getClob();
187 }
188
189 private static BlobWrapper createTempBLOB(Connection connection, BlobWrapper blob)
190 {
191 if (blob == null) {
192 return null;
193 }
194
195 BlobWrapper tempBlob = null;
196 try
197 {
198 // Create a temporary BLOB with duration session
199 tempBlob = BlobWrapper.createTemporary(connection, true, BlobWrapper.getDurationSessionValue());
200
201 // Open the CLOB in readonly mode
202 blob.open(BlobWrapper.getModeReadOnlyValue());
203
204 // Open the temporary CLOB in readwrite mode to enable writing
205 tempBlob.open(BlobWrapper.getModeReadWriteValue());
206
207 // No of bytes read each trip to database
208 int bytesread;
209
210 // Get the input stream for reading from the BLOB
211 InputStream blobInputStream = blob.getBinaryStream();
212
213 // Get the output stream for writing into the BLOB
214 OutputStream tempBlobOutputStream = tempBlob.getBinaryOutputStream();
215
216 // Create a buffer to read data
217 // getBufferSize() returns the optimal buffer size
218 byte[] bytebuffer = new byte[blob.getBufferSize()];
219
220 // Read from the BLOB and write into the temporary BLOB
221 while ((bytesread = blobInputStream.read(bytebuffer)) != -1)
222 {
223 tempBlobOutputStream.write(bytebuffer, 0, bytesread);
224 }
225
226 // Flush and close the streams
227 tempBlobOutputStream.flush();
228 tempBlobOutputStream.close();
229 blobInputStream.close();
230
231 // Close the BLOBs
232 blob.close();
233 tempBlob.close();
234 }
235 catch (Exception e)
236 {
237 logger.error("Error during temporary BLOB write", e);
238 freeTempLOB(null, tempBlob);
239 }
240 return tempBlob;
241 }
242
243 public static byte[] convertBLOBtoByteArray(Connection connection, Object nativeblob)
244 {
245 BlobWrapper temp = new BlobWrapper();
246 temp.setBlob(nativeblob);
247 /**
248 * first, convert the blob to another blob. Thanks Oracle, you rule.
249 */
250 BlobWrapper blob = createTempBLOB(connection, temp);
251 if (blob == null) {
252 return null;
253 }
254
255 byte[] retval = null;
256 // Buffer to hold the BLOB data
257 ByteArrayOutputStream blobdata = new ByteArrayOutputStream();
258 // No of bytes read each trip to database
259 int bytesread = 0;
260 try
261 {
262 // Open the BLOB in readonly mode
263 blob.open(BlobWrapper.getModeReadOnlyValue());
264 // Open the stream to read data
265 InputStream blobInputStream = blob.getBinaryStream();
266 // Buffer size is fixed using the getBufferSize() method which returns
267 // the optimal buffer size to read data from the LOB
268 byte[] bytebuffer = new byte[blob.getBufferSize()];
269 // Keep reading from the BLOB and append it to the bytebuffer till
270 // there is no more to read
271 while ((bytesread = blobInputStream.read(bytebuffer)) != -1)
272 {
273 blobdata.write(bytebuffer, 0, bytesread);
274 }
275 // Close the input and output streams stream
276 blobInputStream.close();
277 blobdata.flush();
278 blobdata.close();
279
280 // Close the BLOB
281 blob.close();
282 retval = blobdata.toByteArray();
283 blobdata = null;
284 }
285 catch (Exception e)
286 {
287 logger.error("Error during BLOB read", e);
288 freeTempLOB(null, blob);
289 }
290 return retval;
291 }
292
293 public static Object createBLOBFromByteArray(Connection conn, byte[] blobData)
294 {
295 if (blobData == null) {
296 return null;
297 }
298
299 BlobWrapper blob = null;
300 try
301 {
302 blob = BlobWrapper.createTemporary(conn, true, BlobWrapper.getDurationSessionValue());
303
304 // Open the temporary BLOB in readwrite mode to enable writing
305 blob.open(BlobWrapper.getModeReadWriteValue());
306
307 // Clear the previous contents of the BLOB
308 blob.trim(0);
309
310 // Get the output stream to write
311 OutputStream tempBlobOutputStream = blob.getBinaryOutputStream();
312
313 // Write the data into the temporary BLOB
314 tempBlobOutputStream.write(blobData);
315
316 // Flush and close the stream
317 tempBlobOutputStream.flush();
318 tempBlobOutputStream.close();
319
320 // Close the temporary BLOB
321 blob.close();
322 }
323 catch (InvocationTargetException ite) {
324 Throwable t = ite.getTargetException();
325 freeTempLOB(null, blob);
326 if (t instanceof java.lang.UnsatisfiedLinkError) {
327 logger.error("Oracle JDBC-driver version does not match installed OCI-driver");
328 } else {
329 logger.error("Error during temporary BLOB write", t);
330 }
331 }
332 catch (Exception e)
333 {
334 logger.error("Error during temporary BLOB write", e);
335 freeTempLOB(null, blob);
336 }
337 return blob == null ? null : blob.getBlob();
338 }
339
340 /**
341 * Frees the temporary LOBs when an exception is raised in the application
342 * or when the LOBs are no longer needed. If the LOBs are not freed, the
343 * space used by these LOBs are not reclaimed.
344 * @param clob CLOB-wrapper to free or null
345 * @param blob BLOB-wrapper to free or null
346 */
347 private static void freeTempLOB(ClobWrapper clob, BlobWrapper blob)
348 {
349 try
350 {
351 if (clob != null)
352 {
353 // If the CLOB is open, close it
354 if (clob.isOpen())
355 {
356 clob.close();
357 }
358
359 // Free the memory used by this CLOB
360 clob.freeTemporary();
361 }
362
363 if (blob != null)
364 {
365 // If the BLOB is open, close it
366 if (blob.isOpen())
367 {
368 blob.close();
369 }
370
371 // Free the memory used by this BLOB
372 blob.freeTemporary();
373 }
374 }
375 catch (Exception e)
376 {
377 logger.error("Error during temporary LOB release", e);
378 }
379 }
380
381 }