Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: org/objectstyle/cayenne/dba/oracle/OracleAdapter.java


1   /* ====================================================================
2    *
3    * The ObjectStyle Group Software License, Version 1.0
4    *
5    * Copyright (c) 2002-2003 The ObjectStyle Group
6    * and individual authors of the software.  All rights reserved.
7    *
8    * Redistribution and use in source and binary forms, with or without
9    * modification, are permitted provided that the following conditions
10   * are met:
11   *
12   * 1. Redistributions of source code must retain the above copyright
13   *    notice, this list of conditions and the following disclaimer.
14   *
15   * 2. Redistributions in binary form must reproduce the above copyright
16   *    notice, this list of conditions and the following disclaimer in
17   *    the documentation and/or other materials provided with the
18   *    distribution.
19   *
20   * 3. The end-user documentation included with the redistribution, if
21   *    any, must include the following acknowlegement:
22   *       "This product includes software developed by the
23   *        ObjectStyle Group (http://objectstyle.org/)."
24   *    Alternately, this acknowlegement may appear in the software itself,
25   *    if and wherever such third-party acknowlegements normally appear.
26   *
27   * 4. The names "ObjectStyle Group" and "Cayenne"
28   *    must not be used to endorse or promote products derived
29   *    from this software without prior written permission. For written
30   *    permission, please contact andrus@objectstyle.org.
31   *
32   * 5. Products derived from this software may not be called "ObjectStyle"
33   *    nor may "ObjectStyle" appear in their names without prior written
34   *    permission of the ObjectStyle Group.
35   *
36   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
37   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
38   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
39   * DISCLAIMED.  IN NO EVENT SHALL THE OBJECTSTYLE GROUP OR
40   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
41   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
42   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
43   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
44   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
45   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
46   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
47   * SUCH DAMAGE.
48   * ====================================================================
49   *
50   * This software consists of voluntary contributions made by many
51   * individuals on behalf of the ObjectStyle Group.  For more
52   * information on the ObjectStyle Group, please see
53   * <http://objectstyle.org/>.
54   *
55   */
56  
57  package org.objectstyle.cayenne.dba.oracle;
58  
59  import java.lang.reflect.Field;
60  import java.lang.reflect.Method;
61  import java.sql.Connection;
62  import java.sql.SQLException;
63  import java.sql.Types;
64  
65  import org.apache.log4j.Logger;
66  import org.objectstyle.cayenne.CayenneRuntimeException;
67  import org.objectstyle.cayenne.access.DataNode;
68  import org.objectstyle.cayenne.access.OperationObserver;
69  import org.objectstyle.cayenne.access.trans.QualifierTranslator;
70  import org.objectstyle.cayenne.access.trans.QueryAssembler;
71  import org.objectstyle.cayenne.access.trans.TrimmingQualifierTranslator;
72  import org.objectstyle.cayenne.access.types.ByteArrayType;
73  import org.objectstyle.cayenne.access.types.CharType;
74  import org.objectstyle.cayenne.access.types.ExtendedTypeMap;
75  import org.objectstyle.cayenne.access.util.BatchQueryUtils;
76  import org.objectstyle.cayenne.dba.JdbcAdapter;
77  import org.objectstyle.cayenne.dba.PkGenerator;
78  import org.objectstyle.cayenne.map.DbAttribute;
79  import org.objectstyle.cayenne.map.DbEntity;
80  import org.objectstyle.cayenne.query.BatchQuery;
81  import org.objectstyle.cayenne.query.Query;
82  import org.objectstyle.cayenne.query.SelectQuery;
83  
84  /** 
85   * DbAdapter implementation for <a href="http://www.oracle.com">Oracle RDBMS</a>.
86   * Sample <a target="_top" href="../../../../../../../developerguide/unit-tests.html">connection 
87   * settings</a> to use with Oracle are shown below:
88   * 
89  <pre>
90  test-oracle.cayenne.adapter = org.objectstyle.cayenne.dba.oracle.OracleAdapter
91  test-oracle.jdbc.username = test
92  test-oracle.jdbc.password = secret
93  test-oracle.jdbc.url = jdbc:oracle:thin:@192.168.0.20:1521:ora1 
94  test-oracle.jdbc.driver = oracle.jdbc.driver.OracleDriver
95  </pre>
96   *
97   * @author Andrei Adamchik
98   */
99  public class OracleAdapter extends JdbcAdapter {
100     private static Logger logObj = Logger.getLogger(OracleAdapter.class);
101 
102     public static final String ORACLE_FLOAT = "FLOAT";
103     public static final String ORACLE_BLOB = "BLOB";
104     public static final String ORACLE_CLOB = "CLOB";
105 
106     public static final String TRIM_FUNCTION = "RTRIM";
107     public static final String NEW_CLOB_FUNCTION = "EMPTY_CLOB()";
108     public static final String NEW_BLOB_FUNCTION = "EMPTY_BLOB()";
109 
110     protected static boolean initDone;
111     protected static int oracleCursorType = Integer.MAX_VALUE;
112     protected static Method outputStreamFromBlobMethod;
113     protected static Method writerFromClobMethod;
114     protected static boolean supportsOracleLOB;
115 
116     protected static void initDriverInformation() {
117         initDone = true;
118 
119         // configure static information
120         try {
121             Class oraTypes = Class.forName("oracle.jdbc.driver.OracleTypes");
122             Field cursorField = oraTypes.getField("CURSOR");
123             oracleCursorType = cursorField.getInt(null);
124 
125             outputStreamFromBlobMethod =
126                 Class.forName("oracle.sql.BLOB").getMethod(
127                     "getBinaryOutputStream",
128                     new Class[0]);
129 
130             writerFromClobMethod =
131                 Class.forName("oracle.sql.CLOB").getMethod(
132                     "getCharacterOutputStream",
133                     new Class[0]);
134             supportsOracleLOB = true;
135 
136         } catch (Exception ex) {
137             logObj.info(
138                 "Error getting Oracle driver information, ignoring. "
139                     + "Note that certain adapter features will be disabled.",
140                 ex);
141         }
142     }
143     
144   public static Method getOutputStreamFromBlobMethod() {
145     return outputStreamFromBlobMethod;
146   }
147 
148   public static boolean isSupportsOracleLOB() {
149     return supportsOracleLOB;
150   }
151 
152   public static Method getWriterFromClobMethod() {
153     return writerFromClobMethod;
154   }
155 
156     /**
157      * Returns an Oracle JDBC extension type defined in
158      * oracle.jdbc.driver.OracleTypes.CURSOR. This value is determined
159      * from Oracle driver classes via reflection in runtime, so that
160      * Cayenne code has no compile dependency on the driver. This means
161      * that calling this method when the driver is not available will
162      * result in an exception.
163      */
164     public static int getOracleCursorType() {
165         if (!initDone) {
166             initDriverInformation();
167         }
168 
169         if (oracleCursorType == Integer.MAX_VALUE) {
170             throw new CayenneRuntimeException(
171                 "No information exists about oracle types. "
172                     + "Check that Oracle JDBC driver is available to the application.");
173         }
174 
175         return oracleCursorType;
176     }
177 
178     public OracleAdapter() {
179         // enable batch updates by default
180         setSupportsBatchUpdates(true);
181     }
182 
183     /**
184      * Installs appropriate ExtendedTypes as converters for passing values
185      * between JDBC and Java layers.
186      */
187     protected void configureExtendedTypes(ExtendedTypeMap map) {
188         super.configureExtendedTypes(map);
189 
190         // create specially configured CharType handler
191         map.registerType(new CharType(true, true));
192 
193         // create specially configured ByteArrayType handler
194         map.registerType(new ByteArrayType(true, true));
195 
196         // override date handler with Oracle handler
197         map.registerType(new OracleUtilDateType());
198     }
199 
200     /**
201      * Creates and returns a primary key generator.
202      * Overrides superclass implementation to return an
203      * instance of OraclePkGenerator.
204      */
205     protected PkGenerator createPkGenerator() {
206         return new OraclePkGenerator();
207     }
208 
209     /**
210      * Returns a query string to drop a table corresponding
211      * to <code>ent</code> DbEntity. Changes superclass behavior
212      * to drop all related foreign key constraints.
213      */
214     public String dropTable(DbEntity ent) {
215         return "DROP TABLE "
216             + ent.getFullyQualifiedName()
217             + " CASCADE CONSTRAINTS";
218     }
219 
220     /**
221      * Fixes some reverse engineering problems. Namely if a columns
222      * is created as DECIMAL and has non-positive precision it is
223      * converted to INTEGER.
224      */
225     public DbAttribute buildAttribute(
226         String name,
227         String typeName,
228         int type,
229         int size,
230         int precision,
231         boolean allowNulls) {
232 
233         DbAttribute attr =
234             super.buildAttribute(
235                 name,
236                 typeName,
237                 type,
238                 size,
239                 precision,
240                 allowNulls);
241 
242         if (type == Types.DECIMAL && precision <= 0) {
243             attr.setType(Types.INTEGER);
244             attr.setPrecision(-1);
245         } else if (type == Types.OTHER) {
246             // in this case we need to guess the attribute type 
247             // based on its string value
248             if (ORACLE_FLOAT.equals(typeName)) {
249                 attr.setType(Types.FLOAT);
250             } else if (ORACLE_BLOB.equals(typeName)) {
251                 attr.setType(Types.BLOB);
252             } else if (ORACLE_CLOB.equals(typeName)) {
253                 attr.setType(Types.CLOB);
254             }
255         }
256 
257         return attr;
258     }
259 
260     /** Returns Oracle-specific classes for SELECT queries. */
261     protected Class queryTranslatorClass(Query q) {
262         if (q instanceof SelectQuery) {
263             return OracleSelectTranslator.class;
264         } else {
265             return super.queryTranslatorClass(q);
266         }
267     }
268 
269     /**
270      * Returns a trimming translator.
271      */
272     public QualifierTranslator getQualifierTranslator(QueryAssembler queryAssembler) {
273         return new TrimmingQualifierTranslator(
274             queryAssembler,
275             OracleAdapter.TRIM_FUNCTION);
276     }
277 
278     /**
279      * Creates an instance of OracleDataNode.
280      */
281     public DataNode createDataNode(String name) {
282         DataNode node = new OracleDataNode(name);
283         node.setAdapter(this);
284         return node;
285     }
286 
287     /**
288      * Implements special LOB handling in batches.
289      */
290     public boolean shouldRunBatchQuery(
291         DataNode node,
292         Connection con,
293         BatchQuery query,
294         OperationObserver delegate)
295         throws SQLException, Exception {
296 
297         // special handling for LOB updates
298         if (supportsOracleLOB && BatchQueryUtils.updatesLOBColumns(query)
299             && (node instanceof OracleDataNode)) {
300 
301             OracleDataNode oracleNode = (OracleDataNode) node;
302             oracleNode.runBatchUpdateWithLOBColumns(con, query, delegate);
303 
304             return false;
305         } else {
306             return super.shouldRunBatchQuery(node, con, query, delegate);
307         }
308     }
309 }