KickJava   Java API By Example, From Geeks To Geeks.

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


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
57 package org.objectstyle.cayenne.dba.oracle;
58
59 import java.lang.reflect.Field JavaDoc;
60 import java.lang.reflect.Method JavaDoc;
61 import java.sql.Connection JavaDoc;
62 import java.sql.PreparedStatement JavaDoc;
63 import java.sql.SQLException JavaDoc;
64 import java.sql.Types JavaDoc;
65
66 import org.apache.log4j.Logger;
67 import org.objectstyle.cayenne.CayenneRuntimeException;
68 import org.objectstyle.cayenne.access.DataNode;
69 import org.objectstyle.cayenne.access.OperationObserver;
70 import org.objectstyle.cayenne.access.trans.QualifierTranslator;
71 import org.objectstyle.cayenne.access.trans.QueryAssembler;
72 import org.objectstyle.cayenne.access.trans.TrimmingQualifierTranslator;
73 import org.objectstyle.cayenne.access.types.ByteArrayType;
74 import org.objectstyle.cayenne.access.types.ByteType;
75 import org.objectstyle.cayenne.access.types.CharType;
76 import org.objectstyle.cayenne.access.types.DefaultType;
77 import org.objectstyle.cayenne.access.types.ExtendedTypeMap;
78 import org.objectstyle.cayenne.access.types.ShortType;
79 import org.objectstyle.cayenne.access.util.BatchQueryUtils;
80 import org.objectstyle.cayenne.dba.JdbcAdapter;
81 import org.objectstyle.cayenne.dba.PkGenerator;
82 import org.objectstyle.cayenne.map.DbAttribute;
83 import org.objectstyle.cayenne.map.DbEntity;
84 import org.objectstyle.cayenne.query.BatchQuery;
85 import org.objectstyle.cayenne.query.Query;
86 import org.objectstyle.cayenne.query.SQLAction;
87 import org.objectstyle.cayenne.query.SelectQuery;
88 import org.objectstyle.cayenne.util.Util;
89
90 /**
91  * DbAdapter implementation for <a HREF="http://www.oracle.com">Oracle RDBMS </a>. Sample
92  * <a target="_top" HREF="../../../../../../../developerguide/unit-tests.html">connection
93  * settings </a> to use with Oracle are shown below:
94  *
95  * <pre>
96  *
97  *
98  * test-oracle.cayenne.adapter = org.objectstyle.cayenne.dba.oracle.OracleAdapter
99  * test-oracle.jdbc.username = test
100  * test-oracle.jdbc.password = secret
101  * test-oracle.jdbc.url = jdbc:oracle:thin:@192.168.0.20:1521:ora1
102  * test-oracle.jdbc.driver = oracle.jdbc.driver.OracleDriver
103  *
104  *
105  * </pre>
106  *
107  * @author Andrei Adamchik
108  */

109 public class OracleAdapter extends JdbcAdapter {
110
111     private static Logger logObj = Logger.getLogger(OracleAdapter.class);
112
113     public static final String JavaDoc ORACLE_FLOAT = "FLOAT";
114     public static final String JavaDoc ORACLE_BLOB = "BLOB";
115     public static final String JavaDoc ORACLE_CLOB = "CLOB";
116
117     public static final String JavaDoc TRIM_FUNCTION = "RTRIM";
118     public static final String JavaDoc NEW_CLOB_FUNCTION = "EMPTY_CLOB()";
119     public static final String JavaDoc NEW_BLOB_FUNCTION = "EMPTY_BLOB()";
120
121     protected static boolean initDone;
122     protected static int oracleCursorType = Integer.MAX_VALUE;
123     protected static Method JavaDoc outputStreamFromBlobMethod;
124     protected static Method JavaDoc writerFromClobMethod;
125     protected static boolean supportsOracleLOB;
126
127     static {
128         // TODO: as CAY-234 shows, having such initialization done in a static fashion
129
// makes it untestable and any potential problems hard to reproduce. Make this
130
// an instance method (with all the affected vars) and write unit tests.
131
initDriverInformation();
132     }
133
134     protected static void initDriverInformation() {
135         initDone = true;
136
137         // configure static information
138
try {
139             Class JavaDoc oraTypes = Class.forName("oracle.jdbc.driver.OracleTypes");
140             Field JavaDoc cursorField = oraTypes.getField("CURSOR");
141             oracleCursorType = cursorField.getInt(null);
142
143             outputStreamFromBlobMethod = Class
144                     .forName("oracle.sql.BLOB")
145                     .getMethod("getBinaryOutputStream", new Class JavaDoc[0]);
146
147             writerFromClobMethod = Class
148                     .forName("oracle.sql.CLOB")
149                     .getMethod("getCharacterOutputStream", new Class JavaDoc[0]);
150             supportsOracleLOB = true;
151
152         }
153         catch (Throwable JavaDoc th) {
154             logObj.info("Error getting Oracle driver information, ignoring. "
155                     + "Note that certain adapter features will be disabled.", Util
156                     .unwindException(th));
157         }
158     }
159
160     public static Method JavaDoc getOutputStreamFromBlobMethod() {
161         return outputStreamFromBlobMethod;
162     }
163
164     // TODO: rename to something that looks like English ...
165
public static boolean isSupportsOracleLOB() {
166         return supportsOracleLOB;
167     }
168
169     public static Method JavaDoc getWriterFromClobMethod() {
170         return writerFromClobMethod;
171     }
172
173     /**
174      * Returns an Oracle JDBC extension type defined in
175      * oracle.jdbc.driver.OracleTypes.CURSOR. This value is determined from Oracle driver
176      * classes via reflection in runtime, so that Cayenne code has no compile dependency
177      * on the driver. This means that calling this method when the driver is not available
178      * will result in an exception.
179      */

180     public static int getOracleCursorType() {
181
182         if (oracleCursorType == Integer.MAX_VALUE) {
183             throw new CayenneRuntimeException(
184                     "No information exists about oracle types. "
185                             + "Check that Oracle JDBC driver is available to the application.");
186         }
187
188         return oracleCursorType;
189     }
190
191     public OracleAdapter() {
192         // enable batch updates by default
193
setSupportsBatchUpdates(true);
194     }
195
196     /**
197      * Installs appropriate ExtendedTypes as converters for passing values between JDBC
198      * and Java layers.
199      */

200     protected void configureExtendedTypes(ExtendedTypeMap map) {
201         super.configureExtendedTypes(map);
202
203         // create specially configured CharType handler
204
map.registerType(new CharType(true, true));
205
206         // create specially configured ByteArrayType handler
207
map.registerType(new ByteArrayType(true, true));
208
209         // override date handler with Oracle handler
210
map.registerType(new OracleUtilDateType());
211
212         // At least on MacOS X, driver does not handle Short and Byte properly
213
map.registerType(new ShortType(true));
214         map.registerType(new ByteType(true));
215
216         // these two types are needed to replace PreparedStatement binding
217
// via "setObject()" to a call to setInt or setDouble to make
218
// Oracle happy, esp. with the AST* expression classes
219
// that do not evaluate constants to BigDecimals, but rather
220
// Integer and Double
221
map.registerType(new OracleIntegerType());
222         map.registerType(new OracleDoubleType());
223     }
224
225     /**
226      * Creates and returns a primary key generator. Overrides superclass implementation to
227      * return an instance of OraclePkGenerator.
228      */

229     protected PkGenerator createPkGenerator() {
230         return new OraclePkGenerator();
231     }
232
233     /**
234      * Returns a query string to drop a table corresponding to <code>ent</code>
235      * DbEntity. Changes superclass behavior to drop all related foreign key constraints.
236      */

237     public String JavaDoc dropTable(DbEntity ent) {
238         return "DROP TABLE " + ent.getFullyQualifiedName() + " CASCADE CONSTRAINTS";
239     }
240
241     /**
242      * Fixes some reverse engineering problems. Namely if a columns is created as DECIMAL
243      * and has non-positive precision it is converted to INTEGER.
244      */

245     public DbAttribute buildAttribute(
246             String JavaDoc name,
247             String JavaDoc typeName,
248             int type,
249             int size,
250             int precision,
251             boolean allowNulls) {
252
253         DbAttribute attr = super.buildAttribute(name,
254                 typeName,
255                 type,
256                 size,
257                 precision,
258                 allowNulls);
259
260         if (type == Types.DECIMAL && precision <= 0) {
261             attr.setType(Types.INTEGER);
262             attr.setPrecision(-1);
263         }
264         else if (type == Types.OTHER) {
265             // in this case we need to guess the attribute type
266
// based on its string value
267
if (ORACLE_FLOAT.equals(typeName)) {
268                 attr.setType(Types.FLOAT);
269             }
270             else if (ORACLE_BLOB.equals(typeName)) {
271                 attr.setType(Types.BLOB);
272             }
273             else if (ORACLE_CLOB.equals(typeName)) {
274                 attr.setType(Types.CLOB);
275             }
276         }
277
278         return attr;
279     }
280
281     /**
282      * Returns Oracle-specific translator for object SELECT queries.
283      *
284      * @deprecated Since 1.2 this is done via custom SQLActions.
285      */

286     protected Class JavaDoc queryTranslatorClass(Query q) {
287         if (q instanceof SelectQuery) {
288             return OracleSelectTranslator.class;
289         }
290         else {
291             return super.queryTranslatorClass(q);
292         }
293     }
294
295     /**
296      * Returns a trimming translator.
297      */

298     public QualifierTranslator getQualifierTranslator(QueryAssembler queryAssembler) {
299         return new TrimmingQualifierTranslator(
300                 queryAssembler,
301                 OracleAdapter.TRIM_FUNCTION);
302     }
303
304     /**
305      * Uses OracleActionBuilder to create the right action.
306      *
307      * @since 1.2
308      */

309     public SQLAction getAction(Query query, DataNode node) {
310         return query.createSQLAction(new OracleActionBuilder(this, node.getEntityResolver()));
311     }
312
313     /**
314      * Implements special LOB handling in batches.
315      *
316      * @deprecated Since 1.2
317      */

318     public boolean shouldRunBatchQuery(
319             DataNode node,
320             Connection JavaDoc con,
321             BatchQuery query,
322             OperationObserver delegate) throws SQLException JavaDoc, Exception JavaDoc {
323
324         // special handling for LOB updates
325
if (isSupportsOracleLOB()
326                 && BatchQueryUtils.updatesLOBColumns(query)
327                 && (node instanceof OracleDataNode)) {
328
329             OracleDataNode oracleNode = (OracleDataNode) node;
330             oracleNode.runBatchUpdateWithLOBColumns(con, query, delegate);
331
332             return false;
333         }
334         else {
335             return super.shouldRunBatchQuery(node, con, query, delegate);
336         }
337     }
338
339     /**
340      * @since 1.1
341      */

342     final class OracleIntegerType extends DefaultType {
343
344         public OracleIntegerType() {
345             super(Integer JavaDoc.class.getName());
346         }
347
348         public void setJdbcObject(
349                 PreparedStatement JavaDoc st,
350                 Object JavaDoc val,
351                 int pos,
352                 int type,
353                 int precision) throws Exception JavaDoc {
354
355             if (val != null) {
356                 st.setInt(pos, ((Number JavaDoc) val).intValue());
357             }
358             else {
359                 super.setJdbcObject(st, val, pos, type, precision);
360             }
361         }
362     }
363
364     /**
365      * @since 1.1
366      */

367     final class OracleDoubleType extends DefaultType {
368
369         public OracleDoubleType() {
370             super(Double JavaDoc.class.getName());
371         }
372
373         public void setJdbcObject(
374                 PreparedStatement JavaDoc st,
375                 Object JavaDoc val,
376                 int pos,
377                 int type,
378                 int precision) throws Exception JavaDoc {
379
380             if (val != null) {
381                 st.setDouble(pos, ((Number JavaDoc) val).doubleValue());
382             }
383             else {
384                 super.setJdbcObject(st, val, pos, type, precision);
385             }
386         }
387     }
388 }
Popular Tags