Coverage Report - org.apache.ojb.broker.accesslayer.StatementsForClassImpl
 
Classes in this File Line Coverage Branch Coverage Complexity
StatementsForClassImpl
N/A
N/A
4.615
 
 1  
 package org.apache.ojb.broker.accesslayer;
 2  
 
 3  
 /* Copyright 2002-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.sql.Connection;
 19  
 import java.sql.PreparedStatement;
 20  
 import java.sql.ResultSet;
 21  
 import java.sql.SQLException;
 22  
 import java.sql.Statement;
 23  
 
 24  
 import org.apache.ojb.broker.PersistenceBrokerSQLException;
 25  
 import org.apache.ojb.broker.accesslayer.sql.SqlGenerator;
 26  
 import org.apache.ojb.broker.accesslayer.sql.SqlGeneratorFactory;
 27  
 import org.apache.ojb.broker.core.proxy.ProxyHelper;
 28  
 import org.apache.ojb.broker.metadata.ClassDescriptor;
 29  
 import org.apache.ojb.broker.metadata.JdbcConnectionDescriptor;
 30  
 import org.apache.ojb.broker.metadata.ConnectionPoolDescriptor;
 31  
 import org.apache.ojb.broker.platforms.Platform;
 32  
 import org.apache.ojb.broker.platforms.PlatformException;
 33  
 import org.apache.ojb.broker.platforms.PlatformFactory;
 34  
 import org.apache.ojb.broker.query.Query;
 35  
 import org.apache.ojb.broker.util.logging.Logger;
 36  
 import org.apache.ojb.broker.util.logging.LoggerFactory;
 37  
 import org.apache.ojb.broker.util.ExceptionHelper;
 38  
 
 39  
 /**
 40  
  * This class serves as a cache for Statements that are
 41  
  * used for persistence operations on a given class.
 42  
  * @author Thomas Mahler
 43  
  * @version $Id: StatementsForClassImpl.java,v 1.1 2007-08-24 22:17:30 ewestfal Exp $
 44  
  */
 45  
 public class StatementsForClassImpl implements StatementsForClassIF
 46  
 {
 47  
     private Logger log = LoggerFactory.getLogger(StatementsForClassImpl.class);
 48  
 
 49  
     /**
 50  
      * sets the escape processing mode
 51  
      */
 52  
     // protected static boolean ESCAPEPROCESSING = false;
 53  
 
 54  
     protected final ClassDescriptor classDescriptor;
 55  
     protected final SqlGenerator sqlGenerator;
 56  
     protected final Platform platform;
 57  
     protected final Class clazz;
 58  
     protected final int fetchSize;
 59  
     private String deleteSql;
 60  
     private String insertSql;
 61  
     private String updateSql;
 62  
     private String selectByPKSql;
 63  
 
 64  
     /**
 65  
      * force use of JDBC 1.0 statement creation
 66  
      */
 67  
     protected boolean FORCEJDBC1_0 = false;
 68  
 
 69  
     public StatementsForClassImpl(
 70  
         final JdbcConnectionDescriptor jcd,
 71  
         final ClassDescriptor classDescriptor)
 72  
     {
 73  
         this.classDescriptor = classDescriptor;
 74  
         clazz = classDescriptor.getClassOfObject();
 75  
         platform = PlatformFactory.getPlatformFor(jcd);
 76  
         sqlGenerator = SqlGeneratorFactory.getInstance().createSqlGenerator(platform);
 77  
 
 78  
         final ConnectionPoolDescriptor cpd = jcd.getConnectionPoolDescriptor();
 79  
         fetchSize = cpd.getFetchSize();
 80  
 
 81  
         // detect JDBC level
 82  
         double level = jcd.getJdbcLevel();
 83  
         FORCEJDBC1_0 = level == 1.0;
 84  
     }
 85  
 
 86  
     /**
 87  
      * Answer true if a PreparedStatement has to be used
 88  
      * <br>false for a CallableStatement
 89  
      */
 90  
     protected boolean usePreparedDeleteStatement()
 91  
     {
 92  
         return !(classDescriptor.getDeleteProcedure() != null &&
 93  
                 classDescriptor.getDeleteProcedure().hasReturnValues());
 94  
     }
 95  
 
 96  
     public PreparedStatement getDeleteStmt(Connection con) throws SQLException
 97  
     {
 98  
         if (deleteSql == null)
 99  
         {
 100  
             deleteSql = sqlGenerator.getPreparedDeleteStatement(classDescriptor).getStatement();
 101  
         }
 102  
         try
 103  
         {
 104  
             return prepareStatement(con,
 105  
                     deleteSql,
 106  
                     Query.NOT_SCROLLABLE,
 107  
                     usePreparedDeleteStatement(),
 108  
                     StatementManagerIF.FETCH_SIZE_NOT_APPLICABLE);
 109  
         }
 110  
         catch (SQLException ex)
 111  
         {
 112  
             log.error("Can't prepare delete statement: " + deleteSql, ex);
 113  
             throw ex;
 114  
         }
 115  
     }
 116  
 
 117  
     public Statement getGenericStmt(Connection con, boolean scrollable)
 118  
         throws PersistenceBrokerSQLException
 119  
     {
 120  
         Statement stmt;
 121  
         try
 122  
         {
 123  
             stmt = createStatement(con, scrollable,
 124  
                     StatementManagerIF.FETCH_SIZE_NOT_EXPLICITLY_SET);
 125  
         }
 126  
         catch (SQLException ex)
 127  
         {
 128  
             throw ExceptionHelper.generateException("Can't prepare statement:", ex, null, log);
 129  
         }
 130  
         return stmt;
 131  
     }
 132  
 
 133  
     /**
 134  
      * Answer true if a PreparedStatement has to be used
 135  
      * <br>false for a CallableStatement
 136  
      */
 137  
     protected boolean usePreparedInsertStatement()
 138  
     {
 139  
         return !(classDescriptor.getInsertProcedure() != null &&
 140  
                 classDescriptor.getInsertProcedure().hasReturnValues());
 141  
     }
 142  
 
 143  
     public PreparedStatement getInsertStmt(Connection con) throws SQLException
 144  
     {
 145  
         if (insertSql == null)
 146  
         {
 147  
             insertSql = sqlGenerator.getPreparedInsertStatement(classDescriptor).getStatement();
 148  
         }
 149  
         try
 150  
         {
 151  
             return prepareStatement(con,
 152  
                     insertSql,
 153  
                     Query.NOT_SCROLLABLE,
 154  
                     usePreparedInsertStatement(),
 155  
                     StatementManagerIF.FETCH_SIZE_NOT_APPLICABLE);
 156  
         }
 157  
         catch (SQLException ex)
 158  
         {
 159  
             log.error("Can't prepare insert statement: " + insertSql, ex);
 160  
             throw ex;
 161  
         }
 162  
     }
 163  
 
 164  
     public PreparedStatement getPreparedStmt(Connection con, String sql,
 165  
                                              boolean scrollable, int explicitFetchSizeHint, boolean callableStmt)
 166  
         throws PersistenceBrokerSQLException
 167  
     {
 168  
         PreparedStatement stmt;
 169  
         try
 170  
         {
 171  
             stmt = prepareStatement(con, sql, scrollable,
 172  
                     !callableStmt, explicitFetchSizeHint);
 173  
         }
 174  
         catch (SQLException ex)
 175  
         {
 176  
             throw ExceptionHelper.generateException("Can't prepare statement:", ex, sql, log);
 177  
         }
 178  
         return stmt;
 179  
     }
 180  
 
 181  
     public PreparedStatement getSelectByPKStmt(Connection con) throws SQLException
 182  
     {
 183  
         if (selectByPKSql == null)
 184  
         {
 185  
             selectByPKSql = sqlGenerator.getPreparedSelectByPkStatement(classDescriptor).getStatement();
 186  
         }
 187  
         try
 188  
         {
 189  
             return prepareStatement(con, selectByPKSql, Query.NOT_SCROLLABLE, true, 1);
 190  
         }
 191  
         catch (SQLException ex)
 192  
         {
 193  
             log.error(ex);
 194  
             throw ex;
 195  
         }
 196  
     }
 197  
 
 198  
     /**
 199  
      * Answer true if a PreparedStatement has to be used
 200  
      * <br>false for a CallableStatement
 201  
      */
 202  
     protected boolean usePreparedUpdateStatement()
 203  
     {
 204  
         return !(classDescriptor.getUpdateProcedure() != null &&
 205  
                 classDescriptor.getUpdateProcedure().hasReturnValues());
 206  
     }
 207  
 
 208  
     public PreparedStatement getUpdateStmt(Connection con) throws SQLException
 209  
     {
 210  
         if (updateSql == null)
 211  
         {
 212  
             updateSql = sqlGenerator.getPreparedUpdateStatement(classDescriptor).getStatement();
 213  
         }
 214  
         try
 215  
         {
 216  
             return prepareStatement(con,
 217  
                     updateSql,
 218  
                     Query.NOT_SCROLLABLE,
 219  
                     usePreparedUpdateStatement(),
 220  
                     StatementManagerIF.FETCH_SIZE_NOT_APPLICABLE);
 221  
         }
 222  
         catch (SQLException ex)
 223  
         {
 224  
             log.error("Can't prepare update statement: " + updateSql, ex);
 225  
             throw ex;
 226  
         }
 227  
     }
 228  
 
 229  
     /**
 230  
      * Prepares a statement with parameters that should work with most RDBMS.
 231  
      *
 232  
      * @param con the connection to utilize
 233  
      * @param sql the sql syntax to use when creating the statement.
 234  
      * @param scrollable determines if the statement will be scrollable.
 235  
      * @param createPreparedStatement if <code>true</code>, then a
 236  
      * {@link PreparedStatement} will be created. If <code>false</code>, then
 237  
      * a {@link java.sql.CallableStatement} will be created.
 238  
      * @param explicitFetchSizeHint will be used as fetchSize hint
 239  
      * (if applicable) if > 0
 240  
      *
 241  
      * @return a statement that can be used to execute the syntax contained in
 242  
      * the <code>sql</code> argument.
 243  
      */
 244  
     protected PreparedStatement prepareStatement(Connection con,
 245  
                                                  String sql,
 246  
                                                  boolean scrollable,
 247  
                                                  boolean createPreparedStatement,
 248  
                                                  int explicitFetchSizeHint)
 249  
         throws SQLException
 250  
     {
 251  
         PreparedStatement result;
 252  
 
 253  
         // if a JDBC1.0 driver is used the signature
 254  
         // prepareStatement(String, int, int) is  not defined.
 255  
         // we then call the JDBC1.0 variant prepareStatement(String)
 256  
         try
 257  
         {
 258  
             // if necessary use JDB1.0 methods
 259  
             if (!FORCEJDBC1_0)
 260  
             {
 261  
                 if (createPreparedStatement)
 262  
                 {
 263  
                     result =
 264  
                         con.prepareStatement(
 265  
                             sql,
 266  
                             scrollable
 267  
                                 ? ResultSet.TYPE_SCROLL_INSENSITIVE
 268  
                                 : ResultSet.TYPE_FORWARD_ONLY,
 269  
                             ResultSet.CONCUR_READ_ONLY);
 270  
                     afterJdbc2CapableStatementCreate(result, explicitFetchSizeHint);
 271  
                 }
 272  
                 else
 273  
                 {
 274  
                     result =
 275  
                         con.prepareCall(
 276  
                             sql,
 277  
                             scrollable
 278  
                                 ? ResultSet.TYPE_SCROLL_INSENSITIVE
 279  
                                 : ResultSet.TYPE_FORWARD_ONLY,
 280  
                             ResultSet.CONCUR_READ_ONLY);
 281  
                 }
 282  
             }
 283  
             else
 284  
             {
 285  
                 if (createPreparedStatement)
 286  
                 {
 287  
                     result = con.prepareStatement(sql);
 288  
                 }
 289  
                 else
 290  
                 {
 291  
                     result = con.prepareCall(sql);
 292  
                 }
 293  
             }
 294  
         }
 295  
         catch (AbstractMethodError err)
 296  
         {
 297  
             // this exception is raised if Driver is not JDBC 2.0 compliant
 298  
             log.warn("Used driver seems not JDBC 2.0 compatible, use the JDBC 1.0 mode", err);
 299  
             if (createPreparedStatement)
 300  
             {
 301  
                 result = con.prepareStatement(sql);
 302  
             }
 303  
             else
 304  
             {
 305  
                 result = con.prepareCall(sql);
 306  
             }
 307  
             FORCEJDBC1_0 = true;
 308  
         }
 309  
         catch (SQLException eSql)
 310  
         {
 311  
             // there are JDBC Driver that nominally implement JDBC 2.0, but
 312  
             // throw DriverNotCapableExceptions. If we catch one of these
 313  
             // we force usage of JDBC 1.0
 314  
             if (eSql
 315  
                 .getClass()
 316  
                 .getName()
 317  
                 .equals("interbase.interclient.DriverNotCapableException"))
 318  
             {
 319  
                 log.warn("JDBC 2.0 problems with this interbase driver, we use the JDBC 1.0 mode");
 320  
                 if (createPreparedStatement)
 321  
                 {
 322  
                     result = con.prepareStatement(sql);
 323  
                 }
 324  
                 else
 325  
                 {
 326  
                     result = con.prepareCall(sql);
 327  
                 }
 328  
                 FORCEJDBC1_0 = true;
 329  
             }
 330  
             else
 331  
             {
 332  
                 throw eSql;
 333  
             }
 334  
         }
 335  
         try
 336  
         {
 337  
             if (!ProxyHelper.isNormalOjbProxy(result))  // tomdz: What about VirtualProxy
 338  
             {
 339  
                 platform.afterStatementCreate(result);
 340  
             }
 341  
         }
 342  
         catch (PlatformException e)
 343  
         {
 344  
             log.error("Platform dependend failure", e);
 345  
         }
 346  
         return result;
 347  
     }
 348  
 
 349  
     /**
 350  
      * Creates a statement with parameters that should work with most RDBMS.
 351  
      */
 352  
     private Statement createStatement(Connection con, boolean scrollable, int explicitFetchSizeHint)
 353  
         throws java.sql.SQLException
 354  
     {
 355  
         Statement result;
 356  
         try
 357  
         {
 358  
             // if necessary use JDBC1.0 methods
 359  
             if (!FORCEJDBC1_0)
 360  
             {
 361  
                 result =
 362  
                     con.createStatement(
 363  
                         scrollable
 364  
                             ? ResultSet.TYPE_SCROLL_INSENSITIVE
 365  
                             : ResultSet.TYPE_FORWARD_ONLY,
 366  
                         ResultSet.CONCUR_READ_ONLY);
 367  
                 afterJdbc2CapableStatementCreate(result, explicitFetchSizeHint);
 368  
             }
 369  
             else
 370  
             {
 371  
                 result = con.createStatement();
 372  
             }
 373  
         }
 374  
         catch (AbstractMethodError err)
 375  
         {
 376  
             // if a JDBC1.0 driver is used, the signature
 377  
             // createStatement(int, int) is  not defined.
 378  
             // we then call the JDBC1.0 variant createStatement()
 379  
             log.warn("Used driver seems not JDBC 2.0 compatible, use the JDBC 1.0 mode", err);
 380  
             result = con.createStatement();
 381  
             FORCEJDBC1_0 = true;
 382  
         }
 383  
         catch (SQLException eSql)
 384  
         {
 385  
             // there are JDBC Driver that nominally implement JDBC 2.0, but
 386  
             // throw DriverNotCapableExceptions. If we catch one of these
 387  
             // we force usage of JDBC 1.0
 388  
             if (eSql.getClass().getName()
 389  
                 .equals("interbase.interclient.DriverNotCapableException"))
 390  
             {
 391  
                 log.warn("JDBC 2.0 problems with this interbase driver, we use the JDBC 1.0 mode");
 392  
                 FORCEJDBC1_0 = true;
 393  
                 result = con.createStatement();
 394  
             }
 395  
             else
 396  
             {
 397  
                 throw eSql;
 398  
             }
 399  
         }
 400  
         try
 401  
         {
 402  
             platform.afterStatementCreate(result);
 403  
         }
 404  
         catch (PlatformException e)
 405  
         {
 406  
             log.error("Platform dependend failure", e);
 407  
         }
 408  
         return result;
 409  
     }
 410  
 
 411  
     private void afterJdbc2CapableStatementCreate(Statement stmt, int explicitFetchSizeHint)
 412  
             throws SQLException
 413  
     {
 414  
         if (stmt != null)
 415  
         {
 416  
             final int fetchSizeHint;
 417  
             if (explicitFetchSizeHint == StatementManagerIF.FETCH_SIZE_NOT_APPLICABLE)
 418  
             {
 419  
                 fetchSizeHint = StatementManagerIF.FETCH_SIZE_NOT_APPLICABLE;
 420  
             }
 421  
             else if (explicitFetchSizeHint != StatementManagerIF.FETCH_SIZE_NOT_EXPLICITLY_SET)
 422  
             {
 423  
                 fetchSizeHint = explicitFetchSizeHint; // specific for this Statement
 424  
             }
 425  
             else
 426  
             {
 427  
                 fetchSizeHint = fetchSize; // connection pool default
 428  
             }
 429  
             if (fetchSizeHint > 0)
 430  
             {
 431  
                 stmt.setFetchSize(fetchSize);
 432  
             }
 433  
         }
 434  
     }
 435  
 
 436  
 }