KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > objectstyle > cayenne > dba > oracle > OracleLOBBatchAction


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.dba.oracle;
57
58 import java.io.OutputStream JavaDoc;
59 import java.io.Writer JavaDoc;
60 import java.lang.reflect.InvocationTargetException JavaDoc;
61 import java.lang.reflect.Method JavaDoc;
62 import java.sql.Blob JavaDoc;
63 import java.sql.Clob JavaDoc;
64 import java.sql.Connection JavaDoc;
65 import java.sql.PreparedStatement JavaDoc;
66 import java.sql.ResultSet JavaDoc;
67 import java.sql.SQLException JavaDoc;
68 import java.sql.Types JavaDoc;
69 import java.util.Collections JavaDoc;
70 import java.util.List JavaDoc;
71
72 import org.apache.log4j.Level;
73 import org.objectstyle.cayenne.CayenneException;
74 import org.objectstyle.cayenne.CayenneRuntimeException;
75 import org.objectstyle.cayenne.access.OperationObserver;
76 import org.objectstyle.cayenne.access.QueryLogger;
77 import org.objectstyle.cayenne.access.trans.LOBBatchQueryBuilder;
78 import org.objectstyle.cayenne.access.trans.LOBBatchQueryWrapper;
79 import org.objectstyle.cayenne.access.trans.LOBInsertBatchQueryBuilder;
80 import org.objectstyle.cayenne.access.trans.LOBUpdateBatchQueryBuilder;
81 import org.objectstyle.cayenne.dba.DbAdapter;
82 import org.objectstyle.cayenne.map.DbAttribute;
83 import org.objectstyle.cayenne.query.BatchQuery;
84 import org.objectstyle.cayenne.query.InsertBatchQuery;
85 import org.objectstyle.cayenne.query.SQLAction;
86 import org.objectstyle.cayenne.query.UpdateBatchQuery;
87 import org.objectstyle.cayenne.util.Util;
88
89 /**
90  * @since 1.2
91  * @author Andrei Adamchik
92  */

93 class OracleLOBBatchAction implements SQLAction {
94
95     BatchQuery query;
96     DbAdapter adapter;
97
98     OracleLOBBatchAction(BatchQuery query, DbAdapter adapter) {
99         this.adapter = adapter;
100         this.query = query;
101     }
102
103     DbAdapter getAdapter() {
104         return adapter;
105     }
106
107     public void performAction(
108             Connection JavaDoc connection,
109             OperationObserver observer) throws SQLException JavaDoc, Exception JavaDoc {
110
111         LOBBatchQueryBuilder queryBuilder;
112         if (query instanceof InsertBatchQuery) {
113             queryBuilder = new LOBInsertBatchQueryBuilder(getAdapter());
114         }
115         else if (query instanceof UpdateBatchQuery) {
116             queryBuilder = new LOBUpdateBatchQueryBuilder(getAdapter());
117         }
118         else {
119             throw new CayenneException(
120                     "Unsupported batch type for special LOB processing: " + query);
121         }
122
123         queryBuilder.setTrimFunction(OracleAdapter.TRIM_FUNCTION);
124         queryBuilder.setNewBlobFunction(OracleAdapter.NEW_BLOB_FUNCTION);
125         queryBuilder.setNewClobFunction(OracleAdapter.NEW_CLOB_FUNCTION);
126
127         // no batching is done, queries are translated
128
// for each batch set, since prepared statements
129
// may be different depending on whether LOBs are NULL or not..
130

131         LOBBatchQueryWrapper selectQuery = new LOBBatchQueryWrapper(query);
132         List JavaDoc qualifierAttributes = selectQuery.getDbAttributesForLOBSelectQualifier();
133
134         Level logLevel = query.getLoggingLevel();
135         boolean isLoggable = QueryLogger.isLoggable(logLevel);
136
137         query.reset();
138         while (selectQuery.next()) {
139             int updated = 0;
140             String JavaDoc updateStr = queryBuilder.createSqlString(query);
141
142             // 1. run row update
143
QueryLogger.logQuery(logLevel, updateStr, Collections.EMPTY_LIST);
144             PreparedStatement JavaDoc statement = connection.prepareStatement(updateStr);
145             try {
146
147                 if (isLoggable) {
148                     List JavaDoc bindings = queryBuilder.getValuesForLOBUpdateParameters(query);
149                     QueryLogger.logQueryParameters(logLevel, "bind", bindings);
150                 }
151
152                 queryBuilder.bindParameters(statement, query);
153                 updated = statement.executeUpdate();
154                 QueryLogger.logUpdateCount(logLevel, updated);
155             }
156             finally {
157                 try {
158                     statement.close();
159                 }
160                 catch (Exception JavaDoc e) {
161                 }
162             }
163
164             // 2. run row LOB update (SELECT...FOR UPDATE and writing out LOBs)
165
processLOBRow(connection, queryBuilder, selectQuery, qualifierAttributes);
166
167             // finally, notify delegate that the row was updated
168
observer.nextCount(query, updated);
169         }
170     }
171
172     void processLOBRow(
173             Connection JavaDoc con,
174             LOBBatchQueryBuilder queryBuilder,
175             LOBBatchQueryWrapper selectQuery,
176             List JavaDoc qualifierAttributes) throws SQLException JavaDoc, Exception JavaDoc {
177
178         List JavaDoc lobAttributes = selectQuery.getDbAttributesForUpdatedLOBColumns();
179         if (lobAttributes.size() == 0) {
180             return;
181         }
182
183         Level logLevel = selectQuery.getLoggingLevel();
184         boolean isLoggable = QueryLogger.isLoggable(logLevel);
185
186         List JavaDoc qualifierValues = selectQuery.getValuesForLOBSelectQualifier();
187         List JavaDoc lobValues = selectQuery.getValuesForUpdatedLOBColumns();
188         int parametersSize = qualifierValues.size();
189         int lobSize = lobAttributes.size();
190
191         String JavaDoc selectStr = queryBuilder.createLOBSelectString(
192                 selectQuery.getQuery(),
193                 lobAttributes,
194                 qualifierAttributes);
195
196         if (isLoggable) {
197             QueryLogger.logQuery(logLevel, selectStr, qualifierValues);
198             QueryLogger.logQueryParameters(logLevel, "write LOB", lobValues);
199         }
200
201         PreparedStatement JavaDoc selectStatement = con.prepareStatement(selectStr);
202         try {
203             for (int i = 0; i < parametersSize; i++) {
204                 Object JavaDoc value = qualifierValues.get(i);
205                 DbAttribute attribute = (DbAttribute) qualifierAttributes.get(i);
206
207                 adapter.bindParameter(
208                         selectStatement,
209                         value,
210                         i + 1,
211                         attribute.getType(),
212                         attribute.getPrecision());
213             }
214
215             ResultSet JavaDoc result = selectStatement.executeQuery();
216
217             try {
218                 if (!result.next()) {
219                     throw new CayenneRuntimeException("Missing LOB row.");
220                 }
221
222                 // read the only expected row
223

224                 for (int i = 0; i < lobSize; i++) {
225                     DbAttribute attribute = (DbAttribute) lobAttributes.get(i);
226                     int type = attribute.getType();
227
228                     if (type == Types.CLOB) {
229                         Clob JavaDoc clob = result.getClob(i + 1);
230                         Object JavaDoc clobVal = lobValues.get(i);
231
232                         if (clobVal instanceof char[]) {
233                             writeClob(clob, (char[]) clobVal);
234                         }
235                         else {
236                             writeClob(clob, clobVal.toString());
237                         }
238                     }
239                     else if (type == Types.BLOB) {
240                         Blob JavaDoc blob = result.getBlob(i + 1);
241
242                         Object JavaDoc blobVal = lobValues.get(i);
243                         if (blobVal instanceof byte[]) {
244                             writeBlob(blob, (byte[]) blobVal);
245                         }
246                         else {
247                             String JavaDoc className = (blobVal != null) ? blobVal
248                                     .getClass()
249                                     .getName() : null;
250                             throw new CayenneRuntimeException(
251                                     "Unsupported class of BLOB value: " + className);
252                         }
253                     }
254                     else {
255                         throw new CayenneRuntimeException(
256                                 "Only BLOB or CLOB is expected here, got: " + type);
257                     }
258                 }
259
260                 if (result.next()) {
261                     throw new CayenneRuntimeException("More than one LOB row found.");
262                 }
263             }
264             finally {
265                 try {
266                     result.close();
267                 }
268                 catch (Exception JavaDoc e) {
269                 }
270             }
271         }
272         finally {
273             try {
274                 selectStatement.close();
275             }
276             catch (Exception JavaDoc e) {
277             }
278         }
279     }
280
281     /**
282      * Writing of LOBs is not supported prior to JDBC 3.0 and has to be done using Oracle
283      * driver utilities, using reflection.
284      */

285     private void writeBlob(Blob JavaDoc blob, byte[] value) {
286
287         Method JavaDoc getBinaryStreamMethod = OracleAdapter.getOutputStreamFromBlobMethod();
288         try {
289             OutputStream JavaDoc out = (OutputStream JavaDoc) getBinaryStreamMethod.invoke(blob, null);
290             try {
291                 out.write(value);
292                 out.flush();
293             }
294             finally {
295                 out.close();
296             }
297         }
298         catch (InvocationTargetException JavaDoc e) {
299             throw new CayenneRuntimeException("Error processing BLOB.", Util
300                     .unwindException(e));
301         }
302         catch (Exception JavaDoc e) {
303             throw new CayenneRuntimeException("Error processing BLOB.", Util
304                     .unwindException(e));
305         }
306     }
307
308     /**
309      * Writing of LOBs is not supported prior to JDBC 3.0 and has to be done using Oracle
310      * driver utilities.
311      */

312     private void writeClob(Clob JavaDoc clob, char[] value) {
313         // obtain Writer and write CLOB
314
Method JavaDoc getWriterMethod = OracleAdapter.getWriterFromClobMethod();
315         try {
316
317             Writer JavaDoc out = (Writer JavaDoc) getWriterMethod.invoke(clob, null);
318             try {
319                 out.write(value);
320                 out.flush();
321             }
322             finally {
323                 out.close();
324             }
325
326         }
327         catch (InvocationTargetException JavaDoc e) {
328             throw new CayenneRuntimeException("Error processing BLOB.", Util
329                     .unwindException(e));
330         }
331         catch (Exception JavaDoc e) {
332             throw new CayenneRuntimeException("Error processing BLOB.", Util
333                     .unwindException(e));
334         }
335     }
336
337     /**
338      * Writing of LOBs is not supported prior to JDBC 3.0 and has to be done using Oracle
339      * driver utilities.
340      */

341     private void writeClob(Clob JavaDoc clob, String JavaDoc value) {
342         // obtain Writer and write CLOB
343
Method JavaDoc getWriterMethod = OracleAdapter.getWriterFromClobMethod();
344         try {
345
346             Writer JavaDoc out = (Writer JavaDoc) getWriterMethod.invoke(clob, null);
347             try {
348                 out.write(value);
349                 out.flush();
350             }
351             finally {
352                 out.close();
353             }
354
355         }
356         catch (InvocationTargetException JavaDoc e) {
357             throw new CayenneRuntimeException("Error processing BLOB.", Util
358                     .unwindException(e));
359         }
360         catch (Exception JavaDoc e) {
361             throw new CayenneRuntimeException("Error processing BLOB.", Util
362                     .unwindException(e));
363         }
364     }
365 }
Popular Tags