KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > sape > carbon > services > sql > DefaultStatementFactoryImpl


1 /*
2  * The contents of this file are subject to the Sapient Public License
3  * Version 1.0 (the "License"); you may not use this file except in compliance
4  * with the License. You may obtain a copy of the License at
5  * http://carbon.sf.net/License.html.
6  *
7  * Software distributed under the License is distributed on an "AS IS" basis,
8  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
9  * the specific language governing rights and limitations under the License.
10  *
11  * The Original Code is The Carbon Component Framework.
12  *
13  * The Initial Developer of the Original Code is Sapient Corporation
14  *
15  * Copyright (C) 2003 Sapient Corporation. All Rights Reserved.
16  */

17
18 package org.sape.carbon.services.sql;
19
20
21 import java.sql.CallableStatement JavaDoc;
22 import java.sql.Connection JavaDoc;
23 import java.sql.PreparedStatement JavaDoc;
24 import java.sql.SQLException JavaDoc;
25 import java.sql.Statement JavaDoc;
26 import java.util.HashMap JavaDoc;
27 import java.util.Map JavaDoc;
28
29 import org.sape.carbon.core.component.ComponentConfiguration;
30 import org.sape.carbon.core.component.lifecycle.Configurable;
31 import org.sape.carbon.core.config.InvalidConfigurationException;
32 import org.sape.carbon.services.sql.connection.ConnectionFactory;
33
34 import org.apache.commons.logging.Log;
35 import org.apache.commons.logging.LogFactory;
36
37
38 /**
39  * The default implementation for the StatementFactory. The configuration
40  * interface for this component is
41  * <code>SqlFactoryConfiguration</code>.
42  * The Component configuration consists of
43  * <ul>
44  * <li> Statement Set
45  * <li> Default Configuration values
46  * </ul>
47  * Sample configuration for the component
48  * <pre>
49  * &lt;!-- Component Configuration for a SQLStatementFactory --&gt;
50  * &lt;Configuration ConfigurationInterface=
51  * &quot;org.sape.carbon.services.sql.SqlFactoryConfiguration&quot;&gt;
52  *
53  * &lt;FunctionalInterface&gt;
54  * org.sape.carbon.services.sql.StatementFactory
55  * &lt;/FunctionalInterface&gt;
56  * &lt;FunctionalImplementationClass&gt;
57  * org.sape.carbon.services.sql.DefaultStatementFactoryImpl
58  * &lt;/FunctionalImplementationClass&gt;
59  * &lt;ConnectionFactory&gt;
60  * ref:///sql/connection/test/StandaloneConnectionFactory
61  * &lt;/ConnectionFactory&gt;
62  * &lt;!-- Default Values for Statement Properties --&gt;
63  * &lt;ResultSetType&gt;TYPE_SCROLL_SENSITIVE&lt;/ResultSetType&gt;
64  * &lt;ResultSetConcurrency&gt;CONCUR_UPDATABLE&lt;/ResultSetConcurrency&gt;
65  * &lt;MaxRows&gt;5&lt;/MaxRows&gt;
66  * &lt;!-- Statement Definitions --&gt;
67  * &lt;Statement&gt;
68  * &lt;!-- Statement Query Name --&gt;
69  * &lt;QueryName&gt;selectAccounts&lt;/QueryName&gt;
70  * &lt;Query&gt;SELECT * FROM accounts&lt;/Query&gt;
71  * &lt;!-- Overriding Parameters --&gt;
72  * &lt;MaxRows&gt;10&lt;/MaxRows&gt;
73  * &lt;/Statement&gt;
74  * &lt;Statement&gt;
75  * &lt;QueryName&gt;Second&lt;/QueryName&gt;
76  * &lt;Query&gt;SELECT * from TEST&lt;/Query&gt;
77  * &lt;/Statement&gt;
78  * &lt;/Configuration&gt;
79  * </pre>
80  * <br>
81  *
82  * Copyright 2002 Sapient
83  * @since carbon 1.0
84  * @author Vivekanand Kirubanandan, June 2002
85  * @author Greg Hinkle, December 2002
86  * @version $Revision: 1.18 $($Author: dvoet $ / $Date: 2003/05/05 21:21:36 $)
87  */

88 public class DefaultStatementFactoryImpl
89         implements StatementFactory, Configurable {
90
91
92     /**
93      * Provides a handle to Apache-commons logger
94      */

95     private Log log = LogFactory.getLog(this.getClass());
96
97     /**
98      * The name of this factory.
99      */

100     protected String JavaDoc statementFactoryName;
101
102     /**
103      * Holds a reference to this factories configuration.
104      */

105     protected StatementFactoryConfiguration config;
106
107     /**
108      * Holds the map of all query name to StatementConfigurations.
109      */

110     protected Map JavaDoc statementsMap;
111
112     /**
113      * Holds the error message displayed if the user has not properly
114      * configured the result set type and concurrency.
115      */

116     protected static final String JavaDoc RESULT_SET_CONFIGURATION_ERROR =
117         "You must either configure both the ResultSet Type and it's "
118         + "Concurrency, or neither.";
119
120     /**
121      * Holds the error message displayed if the user has not properly
122      * configured a connection factory.
123      */

124     protected static final String JavaDoc CONNECTION_FACTORY_CONFIGURATION_ERROR =
125         "You must configure a valid Configuration Factory reference in "
126         + "either the main StatementFactoryConfiguration or in the specific "
127         + "StatementConfiguration.";
128
129
130     /**
131      * Builds a prepared statement for the given configuration
132      * with the connection given.
133      *
134      * @param statementConfig configuration to build the statement from
135      * @param connection a connection to execute with.
136      * @return a PreparedStatement constructed for the queryName given
137      * @throws SQLException indicates an error
138      * creating the CallableStatement
139      */

140     protected PreparedStatement JavaDoc buildPreparedStatement(
141         StatementConfiguration statementConfig,
142         Connection JavaDoc connection)
143     throws SQLException JavaDoc {
144
145         ResultSetConcurrencyEnum concurrency = null;
146         ResultSetTypeEnum type = null;
147
148         concurrency =
149             (statementConfig.getResultSetConcurrency() != null)
150                 ? statementConfig.getResultSetConcurrency()
151                 : config.getResultSetConcurrency();
152
153         type =
154             (statementConfig.getResultSetType() != null)
155                 ? statementConfig.getResultSetType()
156                 : config.getResultSetType();
157
158         PreparedStatement JavaDoc statement = null;
159         if ((concurrency != null) && (type != null)) {
160              statement = connection.prepareStatement(
161                 statementConfig.getQuery(),
162                 statementConfig.getResultSetType().getOrdinal(),
163                 statementConfig.getResultSetConcurrency().getOrdinal());
164         } else if ((concurrency != null) || (type != null)) {
165             throw new InvalidConfigurationException(
166                 this.getClass(),
167                 this.config.getConfigurationName(),
168                 "ResultSet(Type|Concurrency)",
169                 RESULT_SET_CONFIGURATION_ERROR);
170         } else {
171             statement = connection.prepareStatement(
172                 statementConfig.getQuery());
173         }
174         return statement;
175     }
176
177     /**
178      * Creates a prepared statement for the given query name
179      * with the connection given.
180      *
181      * @param queryName query to create a CallableStatement for.
182      * @param connection a connection to execute with.
183      * @return a PreparedStatement constructed for the queryName given
184      * @throws StatementFactoryException indicates an error
185      * creating the CallableStatement
186      */

187     public PreparedStatement JavaDoc createPreparedStatement(
188         String JavaDoc queryName,
189         Connection JavaDoc connection)
190     throws StatementFactoryException {
191
192         PreparedStatement JavaDoc statement = null;
193
194         StatementConfiguration statementConfig =
195             retrieveConfiguration(queryName, this.getClass());
196         try {
197
198             statement = buildPreparedStatement(statementConfig, connection);
199
200             configureStatement(statement, statementConfig);
201
202         } catch (SQLException JavaDoc se) {
203             throw new StatementFactoryException(this.getClass(),
204                 "Failure to create PreparedStatement "
205                     + buildDebugMessage(statementConfig), se);
206         }
207
208         if (log.isTraceEnabled()) {
209             log.trace("Prepared Statement created: "
210                 + buildDebugMessage(statementConfig));
211         }
212
213         return statement;
214     }
215
216
217     /**
218      * Creates a prepared statement for the given query name using
219      * the default connection in the factories configuration.
220      *
221      * <p>When using this interface to create a statement it is
222      * important to remember to get back and close the connection
223      * that is created. This should be done with:</p>
224      * <p><code>statement.getConnection().close()</code</p>
225      *
226      * @param queryName query to create a CallableStatement for.
227      * @return a PreparedStatement constructed for the queryName given
228      * @throws StatementFactoryException indicates an error
229      * creating the CallableStatement
230      */

231      public PreparedStatement JavaDoc createPreparedStatement(String JavaDoc queryName)
232             throws StatementFactoryException {
233
234         PreparedStatement JavaDoc statement = null;
235
236         StatementConfiguration statementConfig =
237             retrieveConfiguration(queryName, this.getClass());
238
239         Connection JavaDoc connection = null;
240
241         try {
242             ConnectionFactory connectionFactory =
243                 (statementConfig.getConnectionFactory() != null)
244                     ? statementConfig.getConnectionFactory()
245                     : this.config.getConnectionFactory();
246
247             if (connectionFactory == null) {
248                 throw new InvalidConfigurationException(
249                     this.getClass(), this.config.getConfigurationName(),
250                     "ConnectionFactory",
251                     CONNECTION_FACTORY_CONFIGURATION_ERROR);
252             }
253
254             // 1) get a connection
255
connection = connectionFactory.getConnection();
256
257             // 2) build the statement
258
// If this line fails, we will release the connection below
259
statement = buildPreparedStatement(statementConfig, connection);
260
261             // 3) configure it with the appropriate settings
262
configureStatement(statement, statementConfig);
263
264         } catch (SQLException JavaDoc se) {
265             // Close the connection we retrieved if there was a failure
266
// to build the statement.
267
if (connection != null) {
268                 try {
269                     connection.close();
270                 } catch (SQLException JavaDoc se2) {
271                     // ignore
272
}
273             }
274             throw new StatementFactoryException(this.getClass(),
275                 "Failure to create prepared statement "
276                     + buildDebugMessage(statementConfig),
277                 se);
278         }
279         if (log.isTraceEnabled()) {
280             log.trace("Prepared Statement created: "
281                 + buildDebugMessage(statementConfig));
282         }
283         return statement;
284     }
285
286     /**
287      * Builds a callable statement for the given configuration
288      * with the connection given.
289      *
290      * @param statementConfig configuration to build the statement from
291      * @param connection a connection to execute with.
292      * @return a CallableStatement constructed for the queryName given
293      * @throws SQLException indicates an error
294      * creating the CallableStatement
295      */

296     protected CallableStatement JavaDoc buildCallableStatement(
297         StatementConfiguration statementConfig,
298         Connection JavaDoc connection)
299     throws SQLException JavaDoc {
300
301         ResultSetConcurrencyEnum concurrency = null;
302         ResultSetTypeEnum type = null;
303
304         concurrency =
305             (statementConfig.getResultSetConcurrency() != null)
306                 ? statementConfig.getResultSetConcurrency()
307                 : config.getResultSetConcurrency();
308
309         type =
310             (statementConfig.getResultSetType() != null)
311                 ? statementConfig.getResultSetType()
312                 : config.getResultSetType();
313
314         CallableStatement JavaDoc statement = null;
315         if ((concurrency != null) && (type != null)) {
316              statement = connection.prepareCall(
317                 statementConfig.getQuery(),
318                 statementConfig.getResultSetType().getOrdinal(),
319                 statementConfig.getResultSetConcurrency().getOrdinal());
320
321         } else if ((concurrency != null) || (type != null)) {
322             throw new InvalidConfigurationException(
323                 this.getClass(),
324                 this.config.getConfigurationName(),
325                 "ResultSet(Type|Concurrency)",
326                 RESULT_SET_CONFIGURATION_ERROR);
327
328         } else {
329             statement = connection.prepareCall(
330                 statementConfig.getQuery());
331         }
332         return statement;
333     }
334
335     /**
336      * Creates a callable statement for the given query name
337      * with the connection given.
338      *
339      * @param queryName query to create a CallableStatement for.
340      * @param connection a connection to execute with.
341      * @return a CallableStatement constructed for the queryName given
342      * @throws StatementFactoryException indicates an error
343      * creating the CallableStatement
344      */

345     public CallableStatement JavaDoc createCallableStatement(
346         String JavaDoc queryName,
347         Connection JavaDoc connection)
348     throws StatementFactoryException {
349
350         CallableStatement JavaDoc statement = null;
351         StatementConfiguration statementConfig =
352             retrieveConfiguration(queryName, this.getClass());
353
354         try {
355             statement = buildCallableStatement(statementConfig, connection);
356
357             configureStatement(statement, statementConfig);
358
359         } catch (SQLException JavaDoc se) {
360             throw new StatementFactoryException(this.getClass(),
361                 "Failure to create callable statement "
362                     + buildDebugMessage(statementConfig),
363                 se);
364         }
365
366         if (log.isTraceEnabled()) {
367             log.trace("Callable Statement created "
368                 + buildDebugMessage(statementConfig));
369         }
370
371         return statement;
372     }
373
374     /**
375      * Creates a callable statement for the given query name using
376      * the default connection in the factories configuration.
377      *
378      * <p>When using this interface to create a statement it is
379      * important to remember to get back and close the connection
380      * that is created. This should be done with:</p>
381      * <p><code>statement.getConnection().close()</code</p>
382      *
383      * @param queryName query to create a CallableStatement for.
384      * @return a CallableStatement constructed for the queryName given
385      * @throws StatementFactoryException indicates an error
386      * creating the CallableStatement
387      */

388     public CallableStatement JavaDoc createCallableStatement(String JavaDoc queryName)
389             throws StatementFactoryException {
390
391         CallableStatement JavaDoc statement = null;
392         StatementConfiguration statementConfig =
393             retrieveConfiguration(queryName, this.getClass());
394
395         Connection JavaDoc connection = null;
396         try {
397             ConnectionFactory connectionFactory =
398                 (statementConfig.getConnectionFactory() != null)
399                     ? statementConfig.getConnectionFactory()
400                     : this.config.getConnectionFactory();
401
402             if (connectionFactory == null) {
403                 throw new InvalidConfigurationException(
404                     this.getClass(), this.config.getConfigurationName(),
405                     "ConnectionFactory",
406                     CONNECTION_FACTORY_CONFIGURATION_ERROR);
407             }
408
409             connection = connectionFactory.getConnection();
410
411             statement = createCallableStatement(queryName, connection);
412
413             configureStatement(statement, statementConfig);
414
415         } catch (SQLException JavaDoc se) {
416             // Close the connection we retrieved if there was a failure
417
// to build the statement.
418
if (connection != null) {
419                 try {
420                     connection.close();
421                 } catch (SQLException JavaDoc se2) {
422                     // ignore
423
}
424             }
425             throw new StatementFactoryException(this.getClass(),
426                 "Failure to create callable statement "
427                     + buildDebugMessage(statementConfig),
428                 se);
429         }
430
431         if (log.isTraceEnabled()) {
432             log.trace("Callable Statement created "
433                 + buildDebugMessage(statementConfig));
434         }
435         return statement;
436     }
437
438
439     /**
440      * Looks up a statement configuration based on the name of
441      * the configuration.
442      *
443      * @param queryName name of the query to lookup
444      * @param sourceClass class to use when throwing an exception
445      * @return a StatementConfiguration for the given queryName
446      * @throws StatementNotConfiguredException indicates the queryName had no
447      * configured statement associated with it.
448      */

449     protected StatementConfiguration retrieveConfiguration(
450         String JavaDoc queryName,
451         Class JavaDoc sourceClass)
452     throws StatementNotConfiguredException {
453
454         StatementConfiguration statementConfiguration =
455             (StatementConfiguration)
456             this.statementsMap.get(queryName);
457
458         if (statementConfiguration == null) {
459             throw new StatementNotConfiguredException(
460                 sourceClass, queryName, this.statementFactoryName);
461         }
462
463         return statementConfiguration;
464     }
465
466     /**
467      * Configure the component. This is preceded and followed by the suspend and
468      * resume operations if they are available on the component.
469      *
470      * @param configuration A SqlFactoryConfiguration
471      */

472     public void configure(ComponentConfiguration configuration) {
473         StatementConfiguration[] statements;
474
475         this.config = (StatementFactoryConfiguration) configuration;
476
477         this.statementsMap = new HashMap JavaDoc();
478
479         StatementFactoryConfiguration config =
480             (StatementFactoryConfiguration) configuration;
481
482         this.statementFactoryName = config.getConfigurationName();
483
484         statements = config.getStatement();
485
486         for (int i = 0; i < statements.length; i++) {
487             this.statementsMap.put(statements[i].getQueryName(), statements[i]);
488         }
489
490         if (log.isTraceEnabled()) {
491             log.trace("Configured statement factory ["
492                 + this.statementFactoryName + "] with [ "
493                 + statements.length + "] Statements");
494         }
495     }
496
497     /**
498      * <p>Configure the statement based on the configuration specified in the
499      * sqlStatement or using the default values.</p>
500      *
501      * @param statement A <code>PreparedStatement</code> or a
502      * <code>CallableStatement></code>
503      * @param sqlStatement The configuration information for the statement.
504      * @return Statement A configured statement
505      * @throws SQLException indicates an error configuring the statement
506      */

507     protected Statement JavaDoc configureStatement(
508         Statement JavaDoc statement,
509         StatementConfiguration sqlStatement)
510     throws SQLException JavaDoc {
511
512         Integer JavaDoc maxRows =
513             (sqlStatement.getMaxRows() != null)
514                 ? sqlStatement.getMaxRows()
515                 : this.config.getMaxRows();
516
517         if (maxRows != null) {
518             statement.setMaxRows(maxRows.intValue());
519         }
520
521         Integer JavaDoc fetchSize =
522             (sqlStatement.getFetchSize() != null)
523                 ? sqlStatement.getFetchSize()
524                 : this.config.getFetchSize();
525
526         if (fetchSize != null) {
527             statement.setFetchSize(fetchSize.intValue());
528         }
529
530
531         Integer JavaDoc maxFieldSize =
532             (sqlStatement.getMaxFieldSize() != null)
533                 ? sqlStatement.getMaxFieldSize()
534                 : this.config.getMaxFieldSize();
535
536         if (maxFieldSize != null) {
537             statement.setMaxFieldSize(maxFieldSize.intValue());
538         }
539
540         Integer JavaDoc queryTimeout =
541             (sqlStatement.getQueryTimeOut() != null)
542                 ? sqlStatement.getQueryTimeOut()
543                 : this.config.getQueryTimeOut();
544
545         if (queryTimeout != null) {
546             statement.setQueryTimeout(queryTimeout.intValue());
547         }
548
549         return statement;
550     }
551
552
553     /**
554      * Builds a debug message containg the configuration status of the supplied
555      * configured statement.
556      *
557      * @param statementConfig statement configuration to build debug
558      * message for
559      * @return a debug message describing the statement config
560      */

561     protected String JavaDoc buildDebugMessage(StatementConfiguration statementConfig) {
562         StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
563         buf.append("StatementFactory [");
564         buf.append(this.statementFactoryName);
565         buf.append("], Query Name [");
566         buf.append(statementConfig.getQueryName());
567         buf.append("] configured: {");
568         buf.append("Fetch Size: ");
569         buf.append(statementConfig.getFetchSize());
570         buf.append(", Max Field Size: ");
571         buf.append(statementConfig.getMaxFieldSize());
572         buf.append(", Max Rows: ");
573         buf.append(statementConfig.getMaxRows());
574         buf.append(", Query Timeout: ");
575         buf.append(statementConfig.getQueryTimeOut());
576         buf.append(", Concurrency: ");
577         buf.append(statementConfig.getResultSetConcurrency());
578         buf.append(", Result Set Type: ");
579         buf.append(statementConfig.getResultSetType());
580         buf.append(", Sql Query: ");
581         buf.append(statementConfig.getQuery());
582
583         return buf.toString();
584     }
585 }
Popular Tags