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&eacute;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    }