KickJava   Java API By Example, From Geeks To Geeks.

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


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

19
20 package org.apache.cayenne.dba.oracle;
21
22 import java.lang.reflect.Field JavaDoc;
23 import java.lang.reflect.Method JavaDoc;
24 import java.sql.PreparedStatement JavaDoc;
25 import java.sql.Types JavaDoc;
26 import java.util.Iterator JavaDoc;
27 import java.util.List JavaDoc;
28
29 import org.apache.cayenne.CayenneRuntimeException;
30 import org.apache.cayenne.access.DataNode;
31 import org.apache.cayenne.access.trans.QualifierTranslator;
32 import org.apache.cayenne.access.trans.QueryAssembler;
33 import org.apache.cayenne.access.trans.TrimmingQualifierTranslator;
34 import org.apache.cayenne.access.types.ByteArrayType;
35 import org.apache.cayenne.access.types.ByteType;
36 import org.apache.cayenne.access.types.CharType;
37 import org.apache.cayenne.access.types.DefaultType;
38 import org.apache.cayenne.access.types.ExtendedTypeMap;
39 import org.apache.cayenne.access.types.ShortType;
40 import org.apache.cayenne.dba.JdbcAdapter;
41 import org.apache.cayenne.dba.PkGenerator;
42 import org.apache.cayenne.map.DbAttribute;
43 import org.apache.cayenne.map.DbEntity;
44 import org.apache.cayenne.query.BatchQuery;
45 import org.apache.cayenne.query.InsertBatchQuery;
46 import org.apache.cayenne.query.Query;
47 import org.apache.cayenne.query.SQLAction;
48 import org.apache.cayenne.query.UpdateBatchQuery;
49
50 /**
51  * DbAdapter implementation for <a HREF="http://www.oracle.com">Oracle RDBMS </a>. Sample
52  * <a target="_top" HREF="../../../../../../../developerguide/unit-tests.html">connection
53  * settings </a> to use with Oracle are shown below:
54  *
55  * <pre>
56  *
57  *
58  * test-oracle.cayenne.adapter = org.apache.cayenne.dba.oracle.OracleAdapter
59  * test-oracle.jdbc.username = test
60  * test-oracle.jdbc.password = secret
61  * test-oracle.jdbc.url = jdbc:oracle:thin:@192.168.0.20:1521:ora1
62  * test-oracle.jdbc.driver = oracle.jdbc.driver.OracleDriver
63  *
64  *
65  * </pre>
66  *
67  * @author Andrus Adamchik
68  */

69 public class OracleAdapter extends JdbcAdapter {
70
71     public static final String JavaDoc ORACLE_FLOAT = "FLOAT";
72     public static final String JavaDoc ORACLE_BLOB = "BLOB";
73     public static final String JavaDoc ORACLE_CLOB = "CLOB";
74
75     public static final String JavaDoc TRIM_FUNCTION = "RTRIM";
76     public static final String JavaDoc NEW_CLOB_FUNCTION = "EMPTY_CLOB()";
77     public static final String JavaDoc NEW_BLOB_FUNCTION = "EMPTY_BLOB()";
78
79     protected static boolean initDone;
80     protected static int oracleCursorType = Integer.MAX_VALUE;
81     protected static Method JavaDoc outputStreamFromBlobMethod;
82     protected static Method JavaDoc writerFromClobMethod;
83     protected static boolean supportsOracleLOB;
84
85     static {
86         // TODO: as CAY-234 shows, having such initialization done in a static fashion
87
// makes it untestable and any potential problems hard to reproduce. Make this
88
// an instance method (with all the affected vars) and write unit tests.
89
initDriverInformation();
90     }
91
92     protected static void initDriverInformation() {
93         initDone = true;
94
95         // configure static information
96
try {
97             Class JavaDoc oraTypes = Class.forName("oracle.jdbc.driver.OracleTypes");
98             Field JavaDoc cursorField = oraTypes.getField("CURSOR");
99             oracleCursorType = cursorField.getInt(null);
100
101             outputStreamFromBlobMethod = Class.forName("oracle.sql.BLOB").getMethod(
102                     "getBinaryOutputStream",
103                     new Class JavaDoc[0]);
104
105             writerFromClobMethod = Class.forName("oracle.sql.CLOB").getMethod(
106                     "getCharacterOutputStream",
107                     new Class JavaDoc[0]);
108             supportsOracleLOB = true;
109
110         }
111         catch (Throwable JavaDoc th) {
112             // ignoring...
113
}
114     }
115
116     public static Method JavaDoc getOutputStreamFromBlobMethod() {
117         return outputStreamFromBlobMethod;
118     }
119
120     // TODO: rename to something that looks like English ...
121
public static boolean isSupportsOracleLOB() {
122         return supportsOracleLOB;
123     }
124
125     /**
126      * Utility method that returns <code>true</code> if the query will update at least
127      * one BLOB or CLOB DbAttribute.
128      *
129      * @since 1.2
130      */

131     static boolean updatesLOBColumns(BatchQuery query) {
132         boolean isInsert = query instanceof InsertBatchQuery;
133         boolean isUpdate = query instanceof UpdateBatchQuery;
134
135         if (!isInsert && !isUpdate) {
136             return false;
137         }
138
139         List JavaDoc updatedAttributes = (isInsert)
140                 ? query.getDbAttributes()
141                 : ((UpdateBatchQuery) query).getUpdatedAttributes();
142
143         Iterator JavaDoc it = updatedAttributes.iterator();
144         while (it.hasNext()) {
145             int type = ((DbAttribute) it.next()).getType();
146             if (type == Types.CLOB || type == Types.BLOB) {
147                 return true;
148             }
149         }
150
151         return false;
152     }
153
154     public static Method JavaDoc getWriterFromClobMethod() {
155         return writerFromClobMethod;
156     }
157
158     /**
159      * Returns an Oracle JDBC extension type defined in
160      * oracle.jdbc.driver.OracleTypes.CURSOR. This value is determined from Oracle driver
161      * classes via reflection in runtime, so that Cayenne code has no compile dependency
162      * on the driver. This means that calling this method when the driver is not available
163      * will result in an exception.
164      */

165     public static int getOracleCursorType() {
166
167         if (oracleCursorType == Integer.MAX_VALUE) {
168             throw new CayenneRuntimeException(
169                     "No information exists about oracle types. "
170                             + "Check that Oracle JDBC driver is available to the application.");
171         }
172
173         return oracleCursorType;
174     }
175
176     public OracleAdapter() {
177         // enable batch updates by default
178
setSupportsBatchUpdates(true);
179     }
180
181     /**
182      * Installs appropriate ExtendedTypes as converters for passing values between JDBC
183      * and Java layers.
184      */

185     protected void configureExtendedTypes(ExtendedTypeMap map) {
186         super.configureExtendedTypes(map);
187
188         // create specially configured CharType handler
189
map.registerType(new CharType(true, true));
190
191         // create specially configured ByteArrayType handler
192
map.registerType(new ByteArrayType(true, true));
193
194         // override date handler with Oracle handler
195
map.registerType(new OracleUtilDateType());
196
197         // At least on MacOS X, driver does not handle Short and Byte properly
198
map.registerType(new ShortType(true));
199         map.registerType(new ByteType(true));
200
201         // these two types are needed to replace PreparedStatement binding
202
// via "setObject()" to a call to setInt or setDouble to make
203
// Oracle happy, esp. with the AST* expression classes
204
// that do not evaluate constants to BigDecimals, but rather
205
// Integer and Double
206
map.registerType(new OracleIntegerType());
207         map.registerType(new OracleDoubleType());
208     }
209
210     /**
211      * Creates and returns a primary key generator. Overrides superclass implementation to
212      * return an instance of OraclePkGenerator.
213      */

214     protected PkGenerator createPkGenerator() {
215         return new OraclePkGenerator();
216     }
217
218     /**
219      * Returns a query string to drop a table corresponding to <code>ent</code>
220      * DbEntity. Changes superclass behavior to drop all related foreign key constraints.
221      */

222     public String JavaDoc dropTable(DbEntity ent) {
223         return "DROP TABLE " + ent.getFullyQualifiedName() + " CASCADE CONSTRAINTS";
224     }
225
226     /**
227      * Fixes some reverse engineering problems. Namely if a columns is created as DECIMAL
228      * and has non-positive precision it is converted to INTEGER.
229      */

230     public DbAttribute buildAttribute(
231             String JavaDoc name,
232             String JavaDoc typeName,
233             int type,
234             int size,
235             int scale,
236             boolean allowNulls) {
237
238         DbAttribute attr = super.buildAttribute(
239                 name,
240                 typeName,
241                 type,
242                 size,
243                 scale,
244                 allowNulls);
245
246         if (type == Types.DECIMAL && scale <= 0) {
247             attr.setType(Types.INTEGER);
248             attr.setScale(-1);
249         }
250         else if (type == Types.OTHER) {
251             // in this case we need to guess the attribute type
252
// based on its string value
253
if (ORACLE_FLOAT.equals(typeName)) {
254                 attr.setType(Types.FLOAT);
255             }
256             else if (ORACLE_BLOB.equals(typeName)) {
257                 attr.setType(Types.BLOB);
258             }
259             else if (ORACLE_CLOB.equals(typeName)) {
260                 attr.setType(Types.CLOB);
261             }
262         }
263         else if (type == Types.DATE) {
264             // Oracle DATE can store JDBC TIMESTAMP
265
if ("DATE".equals(typeName)) {
266                 attr.setType(Types.TIMESTAMP);
267             }
268         }
269
270         return attr;
271     }
272
273     /**
274      * Returns a trimming translator.
275      */

276     public QualifierTranslator getQualifierTranslator(QueryAssembler queryAssembler) {
277         return new TrimmingQualifierTranslator(
278                 queryAssembler,
279                 OracleAdapter.TRIM_FUNCTION);
280     }
281
282     /**
283      * Uses OracleActionBuilder to create the right action.
284      *
285      * @since 1.2
286      */

287     public SQLAction getAction(Query query, DataNode node) {
288         return query.createSQLAction(new OracleActionBuilder(this, node
289                 .getEntityResolver()));
290     }
291
292     /**
293      * @since 1.1
294      */

295     final class OracleIntegerType extends DefaultType {
296
297         public OracleIntegerType() {
298             super(Integer JavaDoc.class.getName());
299         }
300
301         public void setJdbcObject(
302                 PreparedStatement JavaDoc st,
303                 Object JavaDoc val,
304                 int pos,
305                 int type,
306                 int precision) throws Exception JavaDoc {
307
308             if (val != null) {
309                 st.setInt(pos, ((Number JavaDoc) val).intValue());
310             }
311             else {
312                 super.setJdbcObject(st, val, pos, type, precision);
313             }
314         }
315     }
316
317     /**
318      * @since 1.1
319      */

320     final class OracleDoubleType extends DefaultType {
321
322         public OracleDoubleType() {
323             super(Double JavaDoc.class.getName());
324         }
325
326         public void setJdbcObject(
327                 PreparedStatement JavaDoc st,
328                 Object JavaDoc val,
329                 int pos,
330                 int type,
331                 int precision) throws Exception JavaDoc {
332
333             if (val != null) {
334                 st.setDouble(pos, ((Number JavaDoc) val).doubleValue());
335             }
336             else {
337                 super.setJdbcObject(st, val, pos, type, precision);
338             }
339         }
340     }
341 }
342
Popular Tags