KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > opensubsystems > core > persist > db > DatabaseReadOperation


1 /*
2  * Copyright (c) 2003 - 2007 OpenSubsystems s.r.o. Slovak Republic. All rights reserved.
3  *
4  * Project: OpenSubsystems
5  *
6  * $Id: DatabaseReadOperation.java,v 1.11 2007/01/28 06:54:42 bastafidli Exp $
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; version 2 of the License.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20  */

21
22 package org.opensubsystems.core.persist.db;
23
24 import java.sql.Connection JavaDoc;
25 import java.sql.PreparedStatement JavaDoc;
26 import java.sql.SQLException JavaDoc;
27
28 import org.opensubsystems.core.error.OSSDatabaseAccessException;
29 import org.opensubsystems.core.error.OSSException;
30 import org.opensubsystems.core.util.DatabaseUtils;
31 import org.opensubsystems.core.util.GlobalConstants;
32
33 /**
34  * Adapter to simplify writing of database reads, which takes care of
35  * requesting and returning connections, transaction management and
36  * exception handling. To use this adapter you just need to define anonymous
37  * class and override method performOperation to provide the actual database
38  * read. Optionally you may want to override one of the handleXXX methods to
39  * provide custom error handling.
40  *
41  * Example of method in factory which reads data using query produced by its schema
42  *
43  * public DataObject get(
44  * final int iDomainId,
45  * final int iId
46  * ) throws OSSException
47  * {
48  * DatabaseReadOperation dbop = new DatabaseReadOperation(
49  * this, m_schema.getSelectMyDataById(MyDatabaseSchema.MYDATA_COLUMNS),
50  * m_schema, dataType)
51  * {
52  * protected Object performOperation(
53  * DatabaseFactoryImpl dbfactory,
54  * Connection cntConnection,
55  * PreparedStatement pstmQuery
56  * ) throws OSSException,
57  * SQLException
58  * {
59  * pstmQuery.setInt(1, iId);
60  * pstmQuery.setInt(2, iDomainId);
61  * return DatabaseUtils.loadAtMostOneData(dbfactory, pstmQuery,
62  * "Multiple records loaded from database for domain ID "
63  * + iDomainId + " and ID " + iId);
64  * }
65  * };
66  * return (DataObject)dbop.executeRead();
67  * }
68  *
69  * @version $Id: DatabaseReadOperation.java,v 1.11 2007/01/28 06:54:42 bastafidli Exp $
70  * @author Miro Halas
71  * @code.reviewer Miro Halas
72  * @code.reviewed 1.5 2006/07/25 23:57:55 jlegen
73  */

74 public abstract class DatabaseReadOperation extends DatabaseOperation
75                                             implements DatabaseOperations
76 {
77    // Constructors /////////////////////////////////////////////////////////////
78

79    /**
80     * Constructor to use when the database read doesn't require any
81     * prepared statement.
82     *
83     * @param factory - factory which is executing this operation
84     */

85    public DatabaseReadOperation(
86       DatabaseFactoryImpl factory
87    )
88    {
89       this(factory, null, null, factory.getDataType());
90    }
91
92    /**
93     * Constructor to use when database read doesn't require any prepared
94     * statement. There are contained attributes related to handling SQL errors.
95     *
96     * @param factory - factory which is executing this operation
97     * @param strQueryToPrepare - query which should be used to construct prepared
98     * statement which will be passed in to executeUpdate
99     * @param schema - database schema used with this operation
100     * @param dataType - data type used with operation
101     */

102    public DatabaseReadOperation(
103       DatabaseFactoryImpl factory,
104       String JavaDoc strQueryToPrepare,
105       DatabaseSchema schema,
106       int dataType
107    )
108    {
109       super(factory, strQueryToPrepare, schema, null, dataType);
110    }
111
112
113    /**
114     * Copy constructor to use when database read doesn't require any prepared
115     * statement. There are contained attributes related to handling SQL errors.
116     *
117     * @param factory - factory which is executing this operation
118     * @param strQueryToPrepare - query which should be used to construct prepared
119     * statement which will be passed in to executeUpdate
120     * @param schema - database schema used with this operation
121     */

122    public DatabaseReadOperation(
123       DatabaseFactoryImpl factory,
124       String JavaDoc strQueryToPrepare,
125       DatabaseSchema schema
126    )
127    {
128       this(factory, strQueryToPrepare, schema, factory.getDataType());
129    }
130
131    // Public methods ///////////////////////////////////////////////////////////
132

133    /**
134     * Method to execute database read invoking the user defined code
135     * in performOperation.
136     *
137     * @return Object - data read from the database
138     * @throws OSSException - an error has occured
139     */

140    public Object JavaDoc executeRead(
141    ) throws OSSException
142    {
143       Connection JavaDoc cntConnection = null;
144       PreparedStatement JavaDoc pstmQuery = null;
145       
146       try
147       {
148          // Request autocommit true since we are just reading data from the database
149
cntConnection = m_factory.m_connectionFactory.requestConnection(true);
150          // Prepare the query if any query was specified
151
pstmQuery = prepareQuery(m_factory, cntConnection, m_strQuery);
152          // Execute the read hopefully defined in the derived class
153
m_returnData = performOperation(m_factory, cntConnection, pstmQuery);
154       }
155       catch (SQLException JavaDoc sqleExc)
156       {
157          handleSQLException(sqleExc, cntConnection, DatabaseOperations.DBOP_SELECT,
158                             m_iDataType, m_data);
159       }
160       // We just want to propagate OSSException since we do not want
161
// to loose any error message produced by underlying layer and there
162
// is no need to add any more messaging.
163
catch (OSSException ossExc)
164       {
165          handleKnownError(ossExc, cntConnection, DatabaseOperations.DBOP_SELECT,
166                           m_iDataType, m_data);
167       }
168       // We must catch Throwable to rollback since assert throw Error and not Exception
169
catch (Throwable JavaDoc thr)
170       {
171          handleUnknownError(thr, cntConnection, DatabaseOperations.DBOP_SELECT,
172                             m_iDataType, m_data);
173       }
174       finally
175       {
176          DatabaseUtils.closeStatement(pstmQuery);
177          m_factory.m_connectionFactory.returnConnection(cntConnection);
178       }
179       
180       return m_returnData;
181    }
182
183    
184    // Helper methods ///////////////////////////////////////////////////////////
185

186    /**
187     * Prepare the query if it was specified using the provided connection.
188     *
189     * @param dbfactory - database factory executing this operation
190     * @param cntConnection - ready to use connection to perform the database
191     * operation. No need to return this connection.
192     * @param strQuery - query to prepare, might be null or empty if there is
193     * nothing to prepare
194     * @return PreparedStatement - prepared statement for query passed in as a
195     * parameter to the constructor. If no query was
196     * passed into constructor, this will be null.
197     * @throws OSSException - an error has occured
198     * @throws SQLException - an error has occured
199     */

200    protected PreparedStatement JavaDoc prepareQuery(
201       DatabaseFactoryImpl dbfactory,
202       Connection JavaDoc cntConnection,
203       String JavaDoc strQuery
204    ) throws OSSException,
205             SQLException JavaDoc
206    {
207       PreparedStatement JavaDoc pstmQuery = null;
208       
209       if ((strQuery != null) && (strQuery.length() > 0))
210       {
211          pstmQuery = cntConnection.prepareStatement(strQuery);
212       }
213       
214       return pstmQuery;
215    }
216    
217    /**
218     * Define content of this method to perform the database operation using the
219     * provided connection and optional prepared statement.
220     *
221     * @param dbfactory - database factory executing this operation
222     * @param cntConnection - ready to use connection to perform the database
223     * operation. No need to return this connection.
224     * @param pstmStatement - prepared statement for query passed in as a
225     * parameter to the constructor. No need to close
226     * this statement. If no query was passed into
227     * constructor, this will be null.
228     * @return Object - data read from the database accessible through getReturnData
229     * @throws OSSException - an error has occured
230     * @throws SQLException - an error has occured
231     */

232    protected Object JavaDoc performOperation(
233       DatabaseFactoryImpl dbfactory,
234       Connection JavaDoc cntConnection,
235       PreparedStatement JavaDoc pstmStatement
236    ) throws OSSException,
237             SQLException JavaDoc
238    {
239       // Override this method to provide actual commands to update the database
240
return null;
241    }
242    
243
244    /**
245     * Provide custom handling of SQL Exceptions to usually detect constraint
246     * violation. By default just handle it as unknown error.
247     *
248     * @param sqleExc - SQLException to handle
249     * @param cntConnection - ready to use connection to perform the database
250     * operation. No need to return this connection.
251     * @param iOperationType - type of the operation that caused the exception,
252     * see DatabaseOperations for possible values
253     * @param iDataType - data type the data object represents (e.g if this is
254     * type user and data is Integer, that means it is id
255     * of user object). This is one of the DataConstant
256     * constants.
257     * @param data - data object the exception is handled for
258     * @throws OSSException - properly handled exception
259     */

260    protected void handleSQLException(
261       SQLException JavaDoc sqleExc,
262       Connection JavaDoc cntConnection,
263       int iOperationType,
264       int iDataType,
265       Object JavaDoc data
266    ) throws OSSException
267    {
268       if (m_dbschema != null)
269       {
270          m_dbschema.handleSQLException(
271             sqleExc, cntConnection, iOperationType, iDataType, data);
272       }
273       else
274       {
275          // By default just handle it as unknown error
276
handleUnknownError(sqleExc, cntConnection, iOperationType, iDataType, data);
277       }
278    }
279    
280    /**
281     * Override this method to provide any custom error handling for expected
282     * error, which were most likely produced by lower layer. The default
283     * implementation just propagates this error.
284
285     * @param exc - known error which must be handled.
286     * @param cntConnection - ready to use connection to perform the database
287     * operation. No need to return this connection.
288     * @param iOperationType - type of the operation that caused the exception,
289     * see DatabaseOperations for possible values
290     * @param iDataType - data type the data object represents (e.g if this is
291     * type user and data is Integer, that means it is id
292     * of user object). This is one of the DataConstant
293     * constants.
294     * @param data - data object the exception is handled for
295     * @throws OSSException - properly handled exception
296     */

297    protected void handleKnownError(
298       OSSException exc,
299       Connection JavaDoc cntConnection,
300       int iOperationType,
301       int iDataType,
302       Object JavaDoc data
303    ) throws OSSException
304    {
305       throw exc;
306    }
307
308    /**
309     * Override this method to provide any custom error handling for unexpected
310     * error, which weren't handled by lower layer. The default implementation
311     * wraps it in proper error.
312     *
313     * @param thr - throwable causing this error. This is not OSSException
314     * or a derived class.
315     * @param cntConnection - ready to use connection to perform the database
316     * operation. No need to return this connection.
317     * @param iOperationType - type of the operation that caused the exception,
318     * see DatabaseOperations for possible values
319     * @param iDataType - data type the data object represents (e.g if this is
320     * type user and data is Integer, that means it is id
321     * of user object). This is one of the DataConstant
322     * constants.
323     * @param data - data object the exception is handled for
324     * @throws OSSException - properly handled exception
325     */

326    protected void handleUnknownError(
327       Throwable JavaDoc thr,
328       Connection JavaDoc cntConnection,
329       int iOperationType,
330       int iDataType,
331       Object JavaDoc data
332    ) throws OSSException
333    {
334       switch (iOperationType)
335       {
336          case (DBOP_SELECT) :
337          {
338
339             throw new OSSDatabaseAccessException("Failed to load data from the database.",
340                      thr);
341          }
342          default:
343          {
344             if (GlobalConstants.ERROR_CHECKING)
345             {
346                assert false : "Unknown database operation type " + iOperationType;
347             }
348          }
349       }
350    }
351 }
352
Popular Tags