Coverage Report - org.melati.poem.PreparedStatementFactory
 
Classes in this File Line Coverage Branch Coverage Complexity
PreparedStatementFactory
83%
25/30
75%
6/8
2.111
 
 1  
 /*
 2  
  * $Source$
 3  
  * $Revision$
 4  
  *
 5  
  * Copyright (C) 2000 William Chesters
 6  
  *
 7  
  * Part of Melati (http://melati.org), a framework for the rapid
 8  
  * development of clean, maintainable web applications.
 9  
  *
 10  
  * Melati is free software; Permission is granted to copy, distribute
 11  
  * and/or modify this software under the terms either:
 12  
  *
 13  
  * a) the GNU General Public License as published by the Free Software
 14  
  *    Foundation; either version 2 of the License, or (at your option)
 15  
  *    any later version,
 16  
  *
 17  
  *    or
 18  
  *
 19  
  * b) any version of the Melati Software License, as published
 20  
  *    at http://melati.org
 21  
  *
 22  
  * You should have received a copy of the GNU General Public License and
 23  
  * the Melati Software License along with this program;
 24  
  * if not, write to the Free Software Foundation, Inc.,
 25  
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA to obtain the
 26  
  * GNU General Public License and visit http://melati.org to obtain the
 27  
  * Melati Software License.
 28  
  *
 29  
  * Feel free to contact the Developers of Melati (http://melati.org),
 30  
  * if you would like to work out a different arrangement than the options
 31  
  * outlined here.  It is our intention to allow Melati to be used by as
 32  
  * wide an audience as possible.
 33  
  *
 34  
  * This program is distributed in the hope that it will be useful,
 35  
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 36  
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 37  
  * GNU General Public License for more details.
 38  
  *
 39  
  * Contact details for copyright holder:
 40  
  *
 41  
  *     William Chesters <williamc At paneris.org>
 42  
  *     http://paneris.org/~williamc
 43  
  *     Obrechtstraat 114, 2517VX Den Haag, The Netherlands
 44  
  */
 45  
 
 46  
 package org.melati.poem;
 47  
 
 48  
 import java.sql.SQLException;
 49  
 import java.sql.ResultSet;
 50  
 import java.sql.PreparedStatement;
 51  
 import java.sql.Connection;
 52  
 import org.melati.poem.util.CachedIndexFactory;
 53  
 
 54  
 /**
 55  
  * Maintains a cache of <code>PreparedStatement</code>s for an SQL
 56  
  * statement string.
 57  
  * <p>
 58  
  * The cached contents are discarded if the database structure has
 59  
  * changed since the cache was created.
 60  
  * <p>
 61  
  * Execution of the statement in a transaction reflects uncommitted
 62  
  * changes in that transaction.
 63  
  * <p>
 64  
  * The supertype dictates that connections can be identified
 65  
  * by index, but this is slightly complicated and the additional
 66  
  * methods rely on transactions instead.
 67  
  */
 68  
 
 69  
 public class PreparedStatementFactory extends CachedIndexFactory {
 70  
 
 71  
 
 72  
   private Database database;
 73  
   private long structureSerial;
 74  
   private String sql;
 75  
 
 76  
   /**
 77  
    * Constructor.
 78  
    * @param database the db we are working with
 79  
    * @param sql the SQL statement
 80  
    */
 81  327
   public PreparedStatementFactory(Database database, String sql) {
 82  327
     this.database = database;
 83  327
     this.structureSerial = database.structureSerial();
 84  327
     this.sql = sql;
 85  327
   }
 86  
 
 87  
   /**
 88  
    * Obtain a fresh <code>PreparedStatement</code> for a connection
 89  
    * identified by an index.
 90  
    * <p>
 91  
    * The index is zero for the committed connection and the
 92  
    * transaction index plus 1 for current transactions.
 93  
    */
 94  
   protected Object reallyGet(int index) {
 95  
     try {
 96  
       @SuppressWarnings("resource") // this is wrong, IMHO
 97  346
       Connection c =
 98  0
         index == 0 ? database.getCommittedConnection()
 99  346
                    : database.poemTransaction(index - 1).getConnection();
 100  346
       return c.prepareStatement(sql);
 101  0
     } catch (SQLException e) {
 102  0
       throw new SQLPoemException(e);
 103  
     }
 104  
   }
 105  
 
 106  
   /**
 107  
    * {@inheritDoc}
 108  
    * @see org.melati.poem.util.CachedIndexFactory#get(int)
 109  
    */
 110  
   public Object get(int index) {
 111  2745
     if (structureSerial != database.structureSerial()) {
 112  19
       invalidate();
 113  19
       structureSerial = database.structureSerial();
 114  
     }
 115  
 
 116  2745
     return super.get(index);
 117  
   }
 118  
 
 119  
   /**
 120  
    * Get a new or cached PreparedStatement. 
 121  
    * @param transaction the PoemTransaction, can be null
 122  
    * @return a new or cached PreparedStatement
 123  
    */
 124  
   public PreparedStatement preparedStatement(PoemTransaction transaction) {
 125  2745
     return (PreparedStatement)get(transaction == null ? 0 : transaction.index + 1);
 126  
   }
 127  
 
 128  
   /**
 129  
    * @return a new or cached PreparedStatement for the current PoemThread's transaction.
 130  
    */
 131  
   public final PreparedStatement preparedStatement() {
 132  1
     return preparedStatement(PoemThread.transaction());
 133  
   }
 134  
 
 135  
   protected ResultSet resultSet(SessionToken token,
 136  
                                 PreparedStatement statement) {
 137  
     try {
 138  2743
       if (database.logSQL())
 139  1916
         database.log(new SQLLogEvent("PS about to:" + statement.toString() + "(" + sql + ")"));
 140  
 
 141  2743
       token.transaction.writeDown();
 142  
 
 143  2743
       ResultSet rs = null;
 144  
       /*
 145  
       if (database.getDbms().toString()
 146  
               .equals("org.melati.poem.dbms.MSAccess")){
 147  
         // This is due to some uncontrollable 
 148  
         // lazy write caching.
 149  
         // On my machine it is taking 4s to 
 150  
         // sync
 151  
         boolean notDone = true;
 152  
         int failCount = 0;
 153  
         while (notDone) {
 154  
           try {
 155  
             rs = statement.executeQuery();
 156  
             notDone = false;
 157  
           } catch (SQLException e) {
 158  
             try {
 159  
               System.err.println("Sleeping");
 160  
               Thread.sleep(1000);
 161  
               failCount++;
 162  
             } catch (InterruptedException e1) {
 163  
               throw new PoemBugPoemException("Sleep interrupted");
 164  
             }
 165  
             if (failCount > 8) {
 166  
               throw new PreparedSQLSeriousPoemException(
 167  
                       statement, e);              
 168  
             }
 169  
           }
 170  
         }
 171  
       } else 
 172  
       */
 173  2743
       rs = statement.executeQuery();
 174  2743
       token.toTidy().add(rs);
 175  2743
       database.incrementQueryCount(statement.toString());
 176  2743
       return rs;
 177  0
     } catch (SQLException e) {
 178  0
       throw new PreparedSQLSeriousPoemException(statement, e);
 179  
     }
 180  
   }
 181  
 
 182  
   protected final ResultSet resultSet(SessionToken token) {
 183  57
     return resultSet(token, preparedStatement(token.transaction));
 184  
   }
 185  
 
 186  
   /**
 187  
    * @return the ResultSet from the PreparedStatement of the PoemThread
 188  
    */
 189  
   public final ResultSet resultSet() {
 190  13
     return resultSet(PoemThread.sessionToken());
 191  
   }
 192  
 
 193  
   /**
 194  
    * {@inheritDoc}
 195  
    * @see java.lang.Object#toString()
 196  
    */
 197  
   public String toString() {
 198  
 
 199  3
     return super.toString() + " (SQL: " + sql + ")";
 200  
   }
 201  
 
 202  
 }