KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > ojb > broker > platforms > PlatformWLOracle9iImpl


1 package org.apache.ojb.broker.platforms;
2
3 /* Copyright 2004-2005 The Apache Software Foundation
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */

17
18 import java.io.ByteArrayInputStream JavaDoc;
19 import java.lang.reflect.Method JavaDoc;
20 import java.sql.Connection JavaDoc;
21 import java.sql.PreparedStatement JavaDoc;
22 import java.sql.SQLException JavaDoc;
23 import java.sql.Types JavaDoc;
24 import java.util.Collections JavaDoc;
25 import java.util.Map JavaDoc;
26 import java.util.WeakHashMap JavaDoc;
27
28 import org.apache.ojb.broker.metadata.JdbcType;
29 import org.apache.ojb.broker.util.ClassHelper;
30 import org.apache.ojb.broker.metadata.JdbcTypesHelper;
31
32 /**
33  * This class is a concrete implementation of <code>Platform</code>. Provides
34  * an implementation that works around some issues with Oracle running within WebLogic. As
35  * WebLogic wraps the Oracle physical connection with its own logical connection it is necessary to
36  * retrieve the underlying physical connection before creating a CLOB or BLOB.
37  *
38  * NOTE : When you use the physical connection WebLogic by default marks it as "infected" and discards it when
39  * the logicical connection is closed. You can change this behavior by setting the
40  * RemoveInfectedConnectionsEnabled attribute on a connection pool.
41  * see http://e-docs.bea.com/wls/docs81/jdbc/thirdparty.html#1043646
42  *
43  * Optimization: Oracle Batching (not standard JDBC batching)
44  * see http://technet.oracle.com/products/oracle9i/daily/jun07.html
45  *
46  * Optimization: Oracle Prefetching
47  * see http://otn.oracle.com/sample_code/tech/java/sqlj_jdbc/files/advanced/RowPrefetchSample/Readme.html
48  *
49  * TODO: Optimization: use ROWNUM to minimize the effects of not having server side cursors
50  * see http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:127412348064
51  *
52  * @author <a HREF="mailto:mattbaird@yahoo.com">Matthew Baird</a>
53  * @author <a HREF="mailto:erik@cj.com">Erik Forkalsrud</a>
54  * @author <a HREF="mailto:martin.kalen@curalia.se">Martin Kal&eacute;n</a>
55  * @author <a HREF="mailto:d441-6iq2@spamex.com">Dougall Squair</a>
56  * @version CVS $Id: PlatformWLOracle9iImpl.java,v 1.2.2.3 2005/12/21 22:26:40 tomdz Exp $
57  * @see Platform
58  * @see PlatformDefaultImpl
59  * @see PlatformOracleImpl
60  * @see PlatformOracle9iImpl
61  *
62  * @deprecated since OJB 1.0.2 the default {@link PlatformOracle9iImpl} should be usable in WebLogic
63  */

64 public class PlatformWLOracle9iImpl extends PlatformOracleImpl
65 {
66     protected static final int ROW_PREFETCH_SIZE = 100;
67
68     // From Oracle9i JDBC Developer's Guide and Reference:
69
// "Batch values between 5 and 30 tend to be the most effective."
70
protected static final int STATEMENTS_PER_BATCH = 20;
71     protected static Map JavaDoc m_batchStatementsInProgress = Collections.synchronizedMap(new WeakHashMap JavaDoc(STATEMENTS_PER_BATCH));
72
73     protected static final Class JavaDoc[] PARAM_TYPE_INTEGER = {Integer.TYPE};
74     protected static final Class JavaDoc[] PARAM_TYPE_BOOLEAN = {Boolean.TYPE};
75     protected static final Class JavaDoc[] PARAM_TYPE_STRING = {String JavaDoc.class};
76
77     protected static final Object JavaDoc[] PARAM_ROW_PREFETCH_SIZE = new Object JavaDoc[]{new Integer JavaDoc(ROW_PREFETCH_SIZE)};
78     protected static final Object JavaDoc[] PARAM_STATEMENT_BATCH_SIZE = new Object JavaDoc[]{new Integer JavaDoc(STATEMENTS_PER_BATCH)};
79     protected static final Object JavaDoc[] PARAM_BOOLEAN_TRUE = new Object JavaDoc[]{Boolean.TRUE};
80
81     protected static final JdbcType BASE_CLOB = JdbcTypesHelper.getJdbcTypeByName("clob");
82     protected static final JdbcType BASE_BLOB = JdbcTypesHelper.getJdbcTypeByName("blob");
83
84
85
86     /**
87      * Enables Oracle row prefetching if supported.
88      * See http://otn.oracle.com/sample_code/tech/java/sqlj_jdbc/files/advanced/RowPrefetchSample/Readme.html.
89      * This is RDBMS server-to-client prefetching and thus one layer below
90      * the OJB-internal prefetching-to-cache introduced in version 1.0rc5.
91      * @param stmt the statement just created
92      * @throws PlatformException upon JDBC failure
93      */

94     public void afterStatementCreate(java.sql.Statement JavaDoc stmt) throws PlatformException
95     {
96         super.afterStatementCreate(stmt);
97
98         // Check for OracleStatement-specific row prefetching support
99
final Method JavaDoc methodSetRowPrefetch;
100         methodSetRowPrefetch = ClassHelper.getMethod(stmt, "setRowPrefetch", PARAM_TYPE_INTEGER);
101
102         final boolean rowPrefetchingSupported = methodSetRowPrefetch != null;
103         if (rowPrefetchingSupported)
104         {
105             try
106             {
107                 // Set number of prefetched rows
108
methodSetRowPrefetch.invoke(stmt, PARAM_ROW_PREFETCH_SIZE);
109             }
110             catch (Exception JavaDoc e)
111             {
112                 throw new PlatformException(e.getLocalizedMessage(), e);
113             }
114         }
115     }
116
117     /**
118      * Try Oracle update batching and call setExecuteBatch or revert to
119      * JDBC update batching. See 12-2 Update Batching in the Oracle9i
120      * JDBC Developer's Guide and Reference.
121      * @param stmt the prepared statement to be used for batching
122      * @throws PlatformException upon JDBC failure
123      */

124     public void beforeBatch(PreparedStatement JavaDoc stmt) throws PlatformException
125     {
126         // Check for Oracle batching support
127
final Method JavaDoc methodSetExecuteBatch;
128         final Method JavaDoc methodSendBatch;
129         methodSetExecuteBatch = ClassHelper.getMethod(stmt, "setExecuteBatch", PARAM_TYPE_INTEGER);
130         methodSendBatch = ClassHelper.getMethod(stmt, "sendBatch", null);
131
132         final boolean statementBatchingSupported = methodSetExecuteBatch != null && methodSendBatch != null;
133         if (statementBatchingSupported)
134         {
135             try
136             {
137                 // Set number of statements per batch
138
methodSetExecuteBatch.invoke(stmt, PARAM_STATEMENT_BATCH_SIZE);
139                 m_batchStatementsInProgress.put(stmt, methodSendBatch);
140             }
141             catch (Exception JavaDoc e)
142             {
143                 throw new PlatformException(e.getLocalizedMessage(), e);
144             }
145         }
146         else
147         {
148             super.beforeBatch(stmt);
149         }
150     }
151
152     /**
153      * Try Oracle update batching and call executeUpdate or revert to
154      * JDBC update batching.
155      * @param stmt the statement beeing added to the batch
156      * @throws PlatformException upon JDBC failure
157      */

158     public void addBatch(PreparedStatement JavaDoc stmt) throws PlatformException
159     {
160         // Check for Oracle batching support
161
final boolean statementBatchingSupported = m_batchStatementsInProgress.containsKey(stmt);
162         if (statementBatchingSupported)
163         {
164             try
165             {
166                 stmt.executeUpdate();
167             }
168             catch (SQLException JavaDoc e)
169             {
170                 throw new PlatformException(e.getLocalizedMessage(), e);
171             }
172         }
173         else
174         {
175             super.addBatch(stmt);
176         }
177     }
178
179     /**
180      * Try Oracle update batching and call sendBatch or revert to
181      * JDBC update batching.
182      * @param stmt the batched prepared statement about to be executed
183      * @return always <code>null</code> if Oracle update batching is used,
184      * since it is impossible to dissolve total row count into distinct
185      * statement counts. If JDBC update batching is used, an int array is
186      * returned containing number of updated rows for each batched statement.
187      * @throws PlatformException upon JDBC failure
188      */

189     public int[] executeBatch(PreparedStatement JavaDoc stmt) throws PlatformException
190     {
191         // Check for Oracle batching support
192
final Method JavaDoc methodSendBatch = (Method JavaDoc) m_batchStatementsInProgress.remove(stmt);
193         final boolean statementBatchingSupported = methodSendBatch != null;
194
195         int[] retval = null;
196         if (statementBatchingSupported)
197         {
198             try
199             {
200                 // sendBatch() returns total row count as an Integer
201
methodSendBatch.invoke(stmt, null);
202             }
203             catch (Exception JavaDoc e)
204             {
205                 throw new PlatformException(e.getLocalizedMessage(), e);
206             }
207         }
208         else
209         {
210             retval = super.executeBatch(stmt);
211         }
212         return retval;
213     }
214
215     /** @see Platform#setObjectForStatement */
216     public void setObjectForStatement(PreparedStatement JavaDoc ps, int index, Object JavaDoc value, int sqlType) throws SQLException JavaDoc
217     {
218         boolean blobHandlingSupported = false;
219         boolean clobHandlingSupported = false;
220         Method JavaDoc methodSetBlob = null;
221         Method JavaDoc methodSetClob = null;
222         Method JavaDoc methodGetVendorConnection = null;
223
224         // Check for Oracle JDBC-driver LOB-support
225
if (sqlType == Types.CLOB)
226         {
227             try
228             {
229                 Class JavaDoc clobClass = ClassHelper.getClass("oracle.sql.CLOB", false);
230                 methodSetClob = ClassHelper.getMethod(ps, "setCLOB", new Class JavaDoc[]{Integer.TYPE, clobClass});
231                 methodGetVendorConnection = ClassHelper.getMethod(ps.getConnection(), "getVendorConnection",
232                         new Class JavaDoc[]{});
233                 clobHandlingSupported = methodSetClob != null && methodGetVendorConnection != null;
234             }
235             catch (Exception JavaDoc ignore)
236             {
237                 // ignore it
238
}
239         }
240         else if (sqlType == Types.BLOB)
241         {
242             try
243             {
244                 Class JavaDoc blobClass = ClassHelper.getClass("oracle.sql.BLOB", false);
245                 methodSetBlob = ClassHelper.getMethod(ps, "setBLOB", new Class JavaDoc[]{Integer.TYPE, blobClass});
246                 methodGetVendorConnection = ClassHelper.getMethod(ps.getConnection(), "getVendorConnection",
247                         new Class JavaDoc[]{});
248                 blobHandlingSupported = methodSetBlob != null && methodGetVendorConnection != null;
249             }
250             catch (Exception JavaDoc ignore)
251             {
252                 // ignore it
253
}
254         }
255
256         // Type-specific Oracle conversions
257
if (((sqlType == Types.VARBINARY) || (sqlType == Types.LONGVARBINARY)) && (value instanceof byte[]))
258         {
259             byte buf[] = (byte[]) value;
260             ByteArrayInputStream JavaDoc inputStream = new ByteArrayInputStream JavaDoc(buf);
261             super.changePreparedStatementResultSetType(ps);
262             ps.setBinaryStream(index, inputStream, buf.length);
263         }
264         else if (value instanceof Double JavaDoc)
265         {
266             // workaround for the bug in Oracle thin driver
267
ps.setDouble(index, ((Double JavaDoc) value).doubleValue());
268         }
269         else if (sqlType == Types.BIGINT && value instanceof Integer JavaDoc)
270         {
271             // workaround: Oracle thin driver problem when expecting long
272
ps.setLong(index, ((Integer JavaDoc) value).intValue());
273         }
274         else if (sqlType == Types.INTEGER && value instanceof Long JavaDoc)
275         {
276             ps.setLong(index, ((Long JavaDoc) value).longValue());
277         }
278         else if (sqlType == Types.CLOB && clobHandlingSupported && value instanceof String JavaDoc)
279         {
280             // TODO: If using Oracle update batching with the thin driver, throw exception on 4k limit
281
try
282             {
283                 Connection JavaDoc vendorConnection = (Connection JavaDoc) methodGetVendorConnection.invoke(ps.getConnection(),
284                         new Object JavaDoc[]{});
285                 Object JavaDoc clob = Oracle9iLobHandler.createCLOBFromString(vendorConnection, (String JavaDoc) value);
286                 methodSetClob.invoke(ps, new Object JavaDoc[]{new Integer JavaDoc(index), clob});
287             }
288             catch (Exception JavaDoc e)
289             {
290                 throw new SQLException JavaDoc(e.getLocalizedMessage());
291             }
292         }
293         else if (sqlType == Types.BLOB && blobHandlingSupported && value instanceof byte[])
294         {
295             // TODO: If using Oracle update batching with the thin driver, throw exception on 2k limit
296
try
297             {
298                 Connection JavaDoc vendorConnection = (Connection JavaDoc) methodGetVendorConnection.invoke(ps.getConnection(),
299                         new Object JavaDoc[]{});
300                 Object JavaDoc blob = Oracle9iLobHandler.createBLOBFromByteArray(vendorConnection, (byte[]) value);
301                 methodSetBlob.invoke(ps, new Object JavaDoc[]{new Integer JavaDoc(index), blob});
302             }
303             catch (Exception JavaDoc e)
304             {
305                 throw new SQLException JavaDoc(e.getLocalizedMessage());
306             }
307         }
308         else
309         {
310             // Fall-through to superclass
311
super.setObjectForStatement(ps, index, value, sqlType);
312         }
313     }
314
315 }
316
Popular Tags