KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > jdo > spi > persistence > support > sqlstore > database > oracle > OracleSpecialDBOperation


1 /*
2  * NOTE: This class is not included in the build,
3  * as the Oracle JDBC driver must be present for
4  * compilation. A pre-compiled version is checked in
5  * under
6  * <cmp-basedir>/release/build/OracleSpecialDBOperation.jar.
7  * This archive is unpacked for every build, and
8  * must be updated on every change to this class.
9  * Please see the ant script under
10  * <cmp-basedir>/support/sqlstore/build.xml
11  * for targets to update the pre-compiled version:
12  *
13  * - compile-oracle-special: compiles this class
14  * - clean-oracle-special: cleans OracleSpecialDBOperation classes
15  * - update-oracle-special: updates <cmp-basedir>/release/build/OracleSpecialDBOperation.jar
16  *
17  * Oracle's JDBC driver can be downloaded, e.g. the Oracle
18  * 10.1.0.4 JDBC driver can be retrieved from the URL
19  * http://www.oracle.com/technology/software/tech/java/sqlj_jdbc/htdocs/jdbc101040.html
20  * Please specify the Oracle JDBC driver location by defining
21  * the property 'oracle-jdbc.jar' at the command line when
22  * calling the ant targets.
23  *
24  * The complete instructions to update
25  * OracleSpecialDBOperation.jar (from <cmp-basedir>) are:
26  *
27  * 1. Compile the cmp module, e.g.
28  * maven clean build
29  * 2. Clean the oracle special support classes
30  * ant -f support/sqlstore/build.xml clean-oracle-special
31  * 3. Update <cmp-basedir>/release/build/OracleSpecialDBOperation.jar
32  * ant -Doracle-jdbc.jar=<your location>/ojdbc14.jar -f support/sqlstore/build.xml update-oracle-special
33  *
34  */

35
36 /*
37  * The contents of this file are subject to the terms
38  * of the Common Development and Distribution License
39  * (the License). You may not use this file except in
40  * compliance with the License.
41  *
42  * You can obtain a copy of the license at
43  * https://glassfish.dev.java.net/public/CDDLv1.0.html or
44  * glassfish/bootstrap/legal/CDDLv1.0.txt.
45  * See the License for the specific language governing
46  * permissions and limitations under the License.
47  *
48  * When distributing Covered Code, include this CDDL
49  * Header Notice in each file and include the License file
50  * at glassfish/bootstrap/legal/CDDLv1.0.txt.
51  * If applicable, add the following below the CDDL Header,
52  * with the fields enclosed by brackets [] replaced by
53  * you own identifying information:
54  * "Portions Copyrighted [year] [name of copyright owner]"
55  *
56  * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
57  */

58
59 package com.sun.jdo.spi.persistence.support.sqlstore.database.oracle;
60
61 import java.util.List JavaDoc;
62 import java.util.Arrays JavaDoc;
63 import java.security.AccessController JavaDoc;
64 import java.security.PrivilegedAction JavaDoc;
65 import java.sql.PreparedStatement JavaDoc;
66 import java.sql.DatabaseMetaData JavaDoc;
67 import java.sql.SQLException JavaDoc;
68 import java.sql.Connection JavaDoc;
69 import java.sql.Types JavaDoc;
70 import java.sql.Statement JavaDoc;
71
72 import com.sun.jdo.api.persistence.support.FieldMapping;
73 import com.sun.jdo.spi.persistence.support.sqlstore.LogHelperSQLStore;
74 import com.sun.jdo.spi.persistence.support.sqlstore.ejb.EJBHelper;
75 import com.sun.jdo.spi.persistence.support.sqlstore.database.BaseSpecialDBOperation;
76 import com.sun.jdo.spi.persistence.utility.logging.Logger;
77
78 /**
79  * OracleSpecialDBOperation is derived class for Oracle specific operation.
80  * @author Shing Wai Chan
81  * @author Mitesh Meswani
82  */

83 public class OracleSpecialDBOperation extends BaseSpecialDBOperation {
84     /**
85      * The logger
86      */

87     private static Logger logger = LogHelperSQLStore.getLogger();
88
89     /**
90      * Interface used to handle driver specific implementation for various
91      * drivers for Oracle.
92      */

93     private interface DBDriverHandlerFactory {
94         /**
95          * Creates an instance of DBDriverHandler to handle driver specific request
96          * on a <code>PreparedStatement</code>
97          * @param ps Instance of PreparedStatement
98          * @return Instance of DBDriverHandler that corresponds to DBDriver used
99          * to obtain <code>ps</code>
100          *
101          */

102         DBDriverHandler createDBDriverHandler(PreparedStatement JavaDoc ps);
103         /**
104          * Returns true if underlying driver supports defineColumnType() false
105          * otherwise.
106          * @return true if underlying driver supports defineColumnType() false
107          * otherwise.
108          */

109         boolean supportsDefineColumnType();
110     }
111
112     /**
113      * Base implementation for Oracle's driver's handler.
114      */

115     private abstract class OracleDriverHandlerFactory
116         implements DBDriverHandlerFactory {
117         public boolean supportsDefineColumnType() {
118             return true;
119         }
120     }
121
122     private DBDriverHandlerFactory dBDriverHandlerFactory;
123
124
125     private static final boolean oracle816ClassesAvailable;
126     private static final boolean oracle817ClassesAvailable;
127     static {
128         ClassLoader JavaDoc loader = OracleSpecialDBOperation.class.getClassLoader();
129         // OraclePreparedStatement is in the oracle.jdbc.driver package for
130
// oracle 8.1.6 drivers.
131
oracle816ClassesAvailable =
132             loadClass("oracle.jdbc.driver.OraclePreparedStatement", loader) //NOI18N
133
!= null;
134
135         // OraclePreparedStatement is in the oracle.jdbc package for
136
// oracle 8.1.7 (and higher) drivers.
137
oracle817ClassesAvailable =
138             loadClass("oracle.jdbc.OraclePreparedStatement", loader) != null; //NOI18N
139
}
140
141     /**
142      * The SQL statement used to get implementation type of PreparedStatement.
143      */

144     private static final String JavaDoc TEST_STATEMENT = "select 1 from dual";
145
146     public OracleSpecialDBOperation() {
147     }
148
149     /**
150      * Initializes driver specific behavior classes by determining the
151      * characteristics of the jdbc driver used with this DataSource.
152      */

153     public void initialize(DatabaseMetaData JavaDoc metaData,
154         String JavaDoc identifier) throws SQLException JavaDoc {
155         Connection JavaDoc con = metaData.getConnection();
156         // Since the PreparedStatement obtained is directly through
157
// con, there is no need to unwrap it.
158
PreparedStatement JavaDoc testPs = con.prepareStatement(TEST_STATEMENT);
159
160         if (oracle817ClassesAvailable &&
161             testPs instanceof oracle.jdbc.OraclePreparedStatement) {
162             // This DataSource uses a driver version 8.1.7 or higher.
163
// Oracle drivers for version 8.1.7 and higher define interface
164
// oracle.jdbc.OraclePreparedStatement.
165
// OraclePreparedStaement obtained from these drivers implement this
166
// interface. It is possible that in future Oracle might alter
167
// implementation class for OraclePreparedStatement. However, they
168
// should continue implementing this interface. Hence, this
169
// interface should be preferred to communicate with Oracle drivers.
170
dBDriverHandlerFactory = new OracleDriverHandlerFactory() {
171                 public DBDriverHandler createDBDriverHandler(PreparedStatement JavaDoc ps) {
172                     return new Oracle817Handler(ps);
173                 }
174             };
175         } else if (oracle816ClassesAvailable &&
176                     testPs instanceof oracle.jdbc.driver.OraclePreparedStatement) {
177             // This DataSource uses a driver version lower than 8.1.7.
178
// Currently all Oracle drivers return instance of
179
// oracle.jdbc.driver.OraclePreparedStatement for OraclePreparedStatement.
180
dBDriverHandlerFactory = new OracleDriverHandlerFactory() {
181                 public DBDriverHandler createDBDriverHandler(PreparedStatement JavaDoc ps) {
182                     return new Oracle816Handler(ps);
183                 }
184             };
185         } else {
186             // This DataSource uses a non oracle driver.
187
dBDriverHandlerFactory = new DBDriverHandlerFactory() {
188                 public DBDriverHandler createDBDriverHandler(PreparedStatement JavaDoc ps) {
189                     return new NonOracleHandler(ps);
190                 }
191
192                 public boolean supportsDefineColumnType() {
193                     return false;
194                 }
195             };
196             // Warn the user Oracle specific features will be disabled.
197
if(logger.isLoggable(logger.CONFIG)) {
198                 identifier = identifier == null ?
199                     "Connection Factory" : identifier; //NOI18N
200
logger.log(logger.CONFIG,
201                            "sqlstore.database.oracle.nooracleavailable", //NOI18N
202
identifier);
203             }
204         }
205         testPs.close();
206     }
207
208     /**
209      * Defines Column type for result for specified ps.
210      */

211     public void defineColumnTypeForResult(
212         PreparedStatement JavaDoc ps, List JavaDoc columns) throws SQLException JavaDoc {
213         if(dBDriverHandlerFactory.supportsDefineColumnType()) {
214             int size = columns.size();
215             if (size > 0) {
216                 DBDriverHandler driverHandler =
217                     dBDriverHandlerFactory.createDBDriverHandler(ps);
218                 try {
219                     for (int i = 0; i < size; i++) {
220                         FieldMapping fieldMapping = (FieldMapping) columns.get(i);
221                         int type = fieldMapping.getColumnType();
222                         if (type == Types.CHAR || type == Types.VARCHAR) {
223                             int len = fieldMapping.getColumnLength();
224                             if (len > 0) {
225                                 driverHandler.defineColumnType(i + 1, type, len);
226                             } else {
227                                 driverHandler.defineColumnType(i + 1, type);
228                             }
229                         } else {
230                             driverHandler.defineColumnType(i + 1, type);
231                         }
232                     }
233                 } catch (Exception JavaDoc ex) {
234                     if (logger.isLoggable(Logger.INFO)) {
235                         logger.log(Logger.INFO,
236                                    "sqlstore.database.oracle.defineCol", // NOI18N
237
ex);
238                     }
239                     driverHandler.clearDefines();
240                 }
241             }
242         }
243     }
244
245     /**
246      * Implements special handling of char columns on Oracle.
247      */

248     public void bindFixedCharColumn(PreparedStatement JavaDoc stmt,
249         int index, String JavaDoc strVal, int length) throws SQLException JavaDoc {
250         DBDriverHandler driverHandler =
251             dBDriverHandlerFactory.createDBDriverHandler(stmt);
252         driverHandler.bindFixedCharColumn(index, strVal, length);
253     }
254
255     /**
256      * Loads className using loader inside a previleged block.
257      * Returns null if class is not in classpath.
258      */

259     private static Class JavaDoc loadClass(String JavaDoc className, ClassLoader JavaDoc loader) {
260         final ClassLoader JavaDoc finalLoader = loader;
261         final String JavaDoc finalClassName = className;
262         return (Class JavaDoc)AccessController.doPrivileged(
263             new PrivilegedAction JavaDoc() {
264                 public Object JavaDoc run() {
265                     try {
266                         if (finalLoader != null) {
267                             return Class.forName(finalClassName, true,
268                                 finalLoader);
269                         } else {
270                             return Class.forName(finalClassName);
271                         }
272                     } catch(Exception JavaDoc e) {
273                         return null;
274                     }
275                 }
276             }
277         );
278     }
279
280     private interface DBDriverHandler {
281         void defineColumnType(int index, int type) throws SQLException JavaDoc;
282         void defineColumnType( int index, int type, int length)
283             throws SQLException JavaDoc;
284         public void clearDefines() throws SQLException JavaDoc;
285         public void bindFixedCharColumn(int index, String JavaDoc strVal, int length)
286             throws SQLException JavaDoc;
287     }
288
289     private static class Oracle817Handler implements DBDriverHandler {
290         oracle.jdbc.OraclePreparedStatement oraclePreparedStatement;
291
292         public Oracle817Handler(Statement JavaDoc ps) {
293             oraclePreparedStatement = (oracle.jdbc.OraclePreparedStatement)
294                                         EJBHelper.unwrapStatement(ps);
295         }
296         public void defineColumnType(int index, int type) throws SQLException JavaDoc {
297             oraclePreparedStatement.defineColumnType(index, type);
298         }
299         public void defineColumnType( int index, int type,int length)
300             throws SQLException JavaDoc {
301             oraclePreparedStatement.defineColumnType(index, type, length);
302         }
303         public void clearDefines() throws SQLException JavaDoc {
304             oraclePreparedStatement.clearDefines();
305         }
306         public void bindFixedCharColumn(int index, String JavaDoc strVal, int length)
307             throws SQLException JavaDoc {
308             oraclePreparedStatement.setFixedCHAR(index, strVal);
309         }
310     }
311
312     private static class Oracle816Handler implements DBDriverHandler {
313         oracle.jdbc.driver.OraclePreparedStatement oraclePreparedStatement;
314
315         public Oracle816Handler(Statement JavaDoc ps) {
316             oraclePreparedStatement = (oracle.jdbc.driver.OraclePreparedStatement)
317                                         EJBHelper.unwrapStatement(ps);
318         }
319         public void defineColumnType(int index, int type) throws SQLException JavaDoc {
320             oraclePreparedStatement.defineColumnType(index, type);
321         }
322         public void defineColumnType( int index, int type,int length)
323             throws SQLException JavaDoc {
324             oraclePreparedStatement.defineColumnType(index, type, length);
325         }
326         public void clearDefines() throws SQLException JavaDoc {
327             oraclePreparedStatement.clearDefines();
328         }
329         public void bindFixedCharColumn(int index, String JavaDoc strVal, int length)
330             throws SQLException JavaDoc {
331             oraclePreparedStatement.setFixedCHAR(index, strVal);
332         }
333     }
334
335     private static class NonOracleHandler implements DBDriverHandler {
336
337         PreparedStatement JavaDoc ps;
338
339         private NonOracleHandler(PreparedStatement JavaDoc ps) {
340             this.ps = ps;
341         }
342         public void defineColumnType(int index, int type) throws SQLException JavaDoc {}
343         public void defineColumnType( int index, int type,int length)
344             throws SQLException JavaDoc {}
345         public void clearDefines() throws SQLException JavaDoc {}
346         public void bindFixedCharColumn(int index, String JavaDoc strVal, int length)
347             throws SQLException JavaDoc {
348             // We are running on an Oracle database but not using an
349
// Oracle driver. We need to bind a field mapped to a CHAR column by
350
// padding the value with spaces to the length specified in the
351
// dbschema metadata.
352
ps.setString(index, padSpaceChar(strVal, length) );
353             if (logger.isLoggable(Logger.FINE) ) {
354                 logger.log(Logger.FINE, "sqlstore.database.oracle.fixedcharpadded",
355                            strVal, new Integer JavaDoc(length) );
356             }
357         }
358
359         private static final char SPACE_CHAR = ' ';
360         private static final int PAD_STEP_LENGTH = 50;
361         private static final char[] SPACES = new char[PAD_STEP_LENGTH];
362         static {
363             Arrays.fill(SPACES, SPACE_CHAR);
364         }
365         /**
366          * Pads space characters to specified val to increase its length to
367          * specified targetLength.
368          * @param val The input value.
369          * @param targetLength Target length for returned String
370          * @return val padded with space chars.
371          */

372         private static String JavaDoc padSpaceChar(String JavaDoc val, int targetLength) {
373             String JavaDoc retVal = val;
374             int inputLength = val.length();
375
376             if(inputLength < targetLength) {
377                 StringBuffer JavaDoc buf = new StringBuffer JavaDoc(targetLength);
378                 buf.append(val);
379                 int padsize = targetLength - inputLength;
380                 while (padsize >= PAD_STEP_LENGTH) {
381                     buf.append(SPACES);
382                     padsize -= PAD_STEP_LENGTH;
383                 }
384                 buf.append(SPACES, 0, padsize);
385                 retVal = buf.toString();
386             }
387             return retVal;
388         }
389     }
390 }
391
Popular Tags