KickJava   Java API By Example, From Geeks To Geeks.

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


1 /*
2  * Copyright (c) 2003 - 2007 OpenSubsystems s.r.o. Slovak Republic. All rights reserved.
3  *
4  * Project: OpenSubsystems
5  *
6  * $Id: DatabaseUpdateOperation.java,v 1.19 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.data.DataObject;
29 import org.opensubsystems.core.error.OSSDataCreateException;
30 import org.opensubsystems.core.error.OSSDataDeleteException;
31 import org.opensubsystems.core.error.OSSDataSaveException;
32 import org.opensubsystems.core.error.OSSException;
33 import org.opensubsystems.core.util.DatabaseUtils;
34 import org.opensubsystems.core.util.GlobalConstants;
35
36 /**
37  * Adapter to simplify writing of database updates, which takes care of
38  * requesting and returning connections, transaction management and
39  * exception handling. To use this adapter you just need to define anonymous
40  * class and override method performOperation to provide the actual database
41  * update. Optionally you may want to override one of the handleXXX methods
42  * to provide custom error handling.
43  *
44  * Example how to perform the update using query retrieved from schema
45  *
46  * public ModifiableDataObject save(
47  * final ModifiableDataObject data
48  * ) throws OSSException
49  * {
50  * DatabaseUpdateOperation dbop = new DatabaseUpdateOperation(
51  * this, m_schema.getQueryToUpdateMyData(data),
52  * DatabaseUpdateOperation.DBOP_UPDATE, m_schema,
53  * DataConstants.MY_DATA, data
54  * )
55  * {
56  * protected void updateDatabase(
57  * DatabaseFactoryImpl dbfactory,
58  * Connection cntConnection,
59  * PreparedStatement pstmQuery
60  * ) throws OSSException,
61  * SQLException
62  * {
63  * ModifiableDataObject objData = data;
64  * int iIndex = ((ModifiableDatabaseFactory)dbfactory).setValuesForUpdate(
65  * pstmQuery, objData);
66  *
67  * DatabaseImpl.getInstance().updatedAndFetchGeneratedValues(
68  * m_strDataObjectName,
69  * cntConnection, pstmQuery,
70  * m_dbschema.isInDomain(),
71  * m_dbschema.getTableNames().get(
72  * new Integer(m_iDataType)).toString(),
73  * iIndex, objData);
74  * setReturnData(objData);
75  * }
76  * };
77  * dbop.executeUpdate();
78  *
79  * return (ModifiableDataObject)dbop.getReturnData();
80  * }
81  *
82  *
83  * Example of method in factory which saves data using its schema
84  *
85  * public ModifiableDataObject save(
86  * final ModifiableDataObject data
87  * ) throws OSSException
88  * {
89  * DatabaseUpdateOperation dbop = new DatabaseUpdateOperation(
90  * this, DatabaseUpdateOperation.DBOP_UPDATE)
91  * {
92  * protected void updateDatabase(
93  * DatabaseFactoryImpl dbfactory,
94  * Connection cntConnection,
95  * PreparedStatement pstmQuery
96  * ) throws OSSException,
97  * SQLException
98  * {
99  * setReturnData(m_schema.updateData(cntConnection, (MyData)data));
100  * }
101  * };
102  * dbop.executeUpdate();
103  *
104  * return (ModifiableDataObject)dbop.getReturnData();
105  * }
106  *
107  * @version $Id: DatabaseUpdateOperation.java,v 1.19 2007/01/28 06:54:42 bastafidli Exp $
108  * @author Miro Halas
109  * @code.reviewer Miro Halas
110  * @code.reviewed 1.10 2006/07/26 23:45:36 jlegeny
111  */

112 public abstract class DatabaseUpdateOperation extends DatabaseOperation
113                                               implements DatabaseOperations
114 {
115    // Attributes ///////////////////////////////////////////////////////////////
116

117    /**
118     * Type of update performed by this class.
119     */

120    private int m_iUpdateType;
121    
122    // Constructors /////////////////////////////////////////////////////////////
123

124    /**
125     * Constructor to use when database update doesn't require any prepared
126     * statement.
127     *
128     * @param factory - factory which is executing this operation
129     * @param iUpdateType - type of update, one of the constants defined above
130     */

131    public DatabaseUpdateOperation(
132       DatabaseFactoryImpl factory,
133       int iUpdateType
134    )
135    {
136       this(factory, null, null, iUpdateType, null);
137    }
138
139
140    /**
141     * Constructor to use when database update requires prepared statement.
142     *
143     * @param factory - factory which is executing this operation
144     * @param strQueryToPrepare - query which should be used to construct prepared
145     * statement which will be passed in to executeUpdate
146     * @param schema - database schema used with this operation
147     * @param iUpdateType - type of update, one of the constants defined above
148     * @param data - data used for operation
149     */

150    public DatabaseUpdateOperation(
151       DatabaseFactoryImpl factory,
152       String JavaDoc strQueryToPrepare,
153       ModifiableDatabaseSchema schema,
154       int iUpdateType,
155       Object JavaDoc data
156    )
157    {
158       super(factory, strQueryToPrepare, schema, data, factory.getDataType());
159       
160       m_iUpdateType = iUpdateType;
161    }
162
163    // Public methods ///////////////////////////////////////////////////////////
164

165    /**
166     * Method to execute database update invoking the user defined code
167     * in performOperation.
168     *
169     * @throws OSSException - an error has occured
170     */

171    public void executeUpdate(
172    ) throws OSSException
173    {
174       Connection JavaDoc cntConnection = null;
175       PreparedStatement JavaDoc pstmQuery = null;
176       
177       try
178       {
179          // Request autocommit false since we are modifying database
180
cntConnection = m_factory.m_connectionFactory.requestConnection(false);
181          if ((m_strQuery != null) && (m_strQuery.length() > 0))
182          {
183             // Based on type of query we either execute just a normal query
184
// or invoke a stored procedure
185
if (DatabaseImpl.getInstance().isCallableStatement(m_strQuery))
186             {
187                pstmQuery = cntConnection.prepareCall(m_strQuery);
188             }
189             else
190             {
191                pstmQuery = cntConnection.prepareStatement(m_strQuery);
192             }
193          }
194
195          // Execute the update hopefully defined in the derived class
196
performOperation(m_factory, cntConnection, pstmQuery);
197
198          // At this point we don't know if this is just a single operation
199
// and we need to commit or if it is a part of bigger transaction
200
// and the commit is not desired until all operations proceed.
201
// Therefore let the DatabaseTransactionFactory resolve it
202
m_factory.m_transactionFactory.commitTransaction(cntConnection);
203       }
204       // We want to handle SQLException separately since it often means constraint
205
// violation which can be detected and we can provide more meaningful message
206
catch (SQLException JavaDoc sqleExc)
207       {
208          // At this point we don't know if this is just a single operation
209
// and we need to commit or if it is a part of bigger transaction
210
// and the commit is not desired until all operations proceed.
211
// Therefore let the DatabaseTransactionFactory resolve it
212
DatabaseUtils.rollbackAndIgnoreException(cntConnection);
213          handleSQLException(sqleExc, cntConnection, m_iUpdateType, m_iDataType, m_data);
214       }
215       // We just want to propagate OSSException since we do not want
216
// to loose any error message produced by underlying layer and there
217
// is no need to add any more messaging.
218
catch (OSSException ossExc)
219       {
220          // At this point we don't know if this is just a single operation
221
// and we need to commit or if it is a part of bigger transaction
222
// and the commit is not desired until all operations proceed.
223
// Therefore let the DatabaseTransactionFactory resolve it
224
DatabaseUtils.rollbackAndIgnoreException(cntConnection);
225          handleKnownError(ossExc, cntConnection, m_iUpdateType, m_iDataType, m_data);
226       }
227       // We must catch Throwable to rollback since assert throw Error and not Exception
228
catch (Throwable JavaDoc thr)
229       {
230          // At this point we don't know if this is just a single operation
231
// and we need to commit or if it is a part of bigger transaction
232
// and the commit is not desired until all operations proceed.
233
// Therefore let the DatabaseTransactionFactory resolve it
234
DatabaseUtils.rollbackAndIgnoreException(cntConnection);
235          handleUnknownError(thr, cntConnection, m_iUpdateType, m_iDataType, m_data);
236       }
237       finally
238       {
239          DatabaseUtils.closeStatement(pstmQuery);
240          m_factory.m_connectionFactory.returnConnection(cntConnection);
241       }
242    }
243
244    // Helper methods ///////////////////////////////////////////////////////////
245

246    /**
247     * Define content of this method to perform the database operation using the
248     * provided connection and optional prepared statement.
249     *
250     * @param dbfactory - database factory used for this operation
251     * @param cntConnection - ready to use connection to perform the database
252     * operation. No need to return this connection.
253     * @param pstmStatement - prepared statement for query passed in as a
254     * parameter to the constructor. No need to close
255     * this statement. If no query was passed into
256     * constructor, this will be null.
257     *
258     * @throws OSSException - an error has occured
259     * @throws SQLException - an error has occured
260     */

261    protected void performOperation(
262       DatabaseFactoryImpl dbfactory,
263       Connection JavaDoc cntConnection,
264       PreparedStatement JavaDoc pstmStatement
265    ) throws OSSException,
266             SQLException JavaDoc
267    {
268       // Override this method to provide actual commands to update the database
269
}
270
271    /**
272     * Define content of this method to perform the prepare data (update dataobject attribute).
273     *
274     * @param data - data object the attributes will be updated for
275     */

276    protected void prepareData(
277       DataObject data
278    )
279    {
280       // Override this method to provide actual commands to update the data object
281
}
282
283    /**
284     * Method sets values to the prepared statement for insert of data object.
285     *
286     * @param insertStatement - prepared statement the values will be set up for
287     * @param data - data object to insert, based on the type of the data object
288     * it can be determined what data are we inserting
289     * @param initialIndex - initial index for values to be set up into statement
290     * @return int - index of the last parameter in prepared statement (can be used
291     * for later processing outside of this method)
292     * @throws OSSException - exception during setting values
293     * @throws SQLException - exception during setting values
294     */

295    protected int setValuesForInsert(
296       PreparedStatement JavaDoc insertStatement,
297       DataObject data,
298       int initialIndex
299    ) throws OSSException,
300             SQLException JavaDoc
301    {
302       // Override this method to provide changes in set up values for insert
303
return ((BasicDatabaseFactory)m_factory).setValuesForInsert(
304                   insertStatement, data, initialIndex);
305    }
306
307    /**
308     * Method sets values to the prepared statement for update of data object.
309     *
310     * @param updateStatement - prepared statement the values will be set up for
311     * @param data - data object to update, based on the type of the data object
312     * it can be determined what data are we updating
313     * @param initialIndex - initial index for values to be set up into statement
314     * @return int - index of the last parameter in prepared statement (can be used
315     * for later processing outside of this method)
316     * @throws OSSException - exception during setting values
317     * @throws SQLException - exception during setting values
318     */

319    protected int setValuesForUpdate(
320       PreparedStatement JavaDoc updateStatement,
321       DataObject data,
322       int initialIndex
323    ) throws OSSException,
324             SQLException JavaDoc
325    {
326       // Override this method to provide changes in set up values for update
327
return ((ModifiableDatabaseFactory)m_factory).setValuesForUpdate(
328                   updateStatement, data, initialIndex);
329    }
330
331    /**
332     * Provide custom handling of SQL Exceptions to usually detect constraint
333     * violation. By default just handle it as unknown error.
334     *
335     * @param sqleExc - SQLException to handle
336     * @param cntConnection - ready to use connection to perform the database
337     * operation. No need to return this connection.
338     * @param iOperationType - type of the operation that caused the exception,
339     * see DatabaseOperations for possible values
340     * @param iDataType - data type the data object represents (e.g if this is
341     * type user and data is Integer, that means it is id
342     * of user object). This is one of the DataConstant
343     * constants.
344     * @param data - data object the exception is handled for
345     * @throws OSSException - properly handled exception
346     */

347    protected void handleSQLException(
348       SQLException JavaDoc sqleExc,
349       Connection JavaDoc cntConnection,
350       int iOperationType,
351       int iDataType,
352       Object JavaDoc data
353    ) throws OSSException
354    {
355       if (m_dbschema != null)
356       {
357          m_dbschema.handleSQLException(
358             sqleExc, cntConnection, iOperationType, iDataType, data);
359       }
360       else
361       {
362          // By default just handle it as unknown error
363
handleUnknownError(sqleExc, cntConnection, iOperationType, iDataType, data);
364       }
365    }
366    
367    /**
368     * Override this method to provide any custom error handling for expected
369     * error, which were most likely produced by lower layer. The default
370     * implementation just propagates this error.
371
372     * @param exc - known error which must be handled.
373     * @param cntConnection - ready to use connection to perform the database
374     * operation. No need to return this connection.
375     * @param iOperationType - type of the operation that caused the exception,
376     * see DatabaseOperations for possible values
377     * @param iDataType - data type the data object represents (e.g if this is
378     * type user and data is Integer, that means it is id
379     * of user object). This is one of the DataConstant
380     * constants.
381     * @param data - data object the exception is handled for
382     * @throws OSSException - properly handled exception
383     */

384    protected void handleKnownError(
385       OSSException exc,
386       Connection JavaDoc cntConnection,
387       int iOperationType,
388       int iDataType,
389       Object JavaDoc data
390    ) throws OSSException
391    {
392       throw exc;
393    }
394    
395    /**
396     * Override this method to provide any custom error handling for unexpected
397     * error, which weren't handled by lower layer. The default implementation
398     * wraps it in proper error based on the type of operation.
399     *
400     * @param thr - throwable causing this error. This is not OSSException
401     * or a derived class.
402     * @param cntConnection - ready to use connection to perform the database
403     * operation. No need to return this connection.
404     * @param iOperationType - type of the operation that caused the exception,
405     * see DatabaseOperations for possible values
406     * @param iDataType - data type the data object represents (e.g if this is
407     * type user and data is Integer, that means it is id
408     * of user object). This is one of the DataConstant
409     * constants.
410     * @param data - data object the exception is handled for
411     * @throws OSSException - properly handled exception
412     */

413    protected void handleUnknownError(
414       Throwable JavaDoc thr,
415       Connection JavaDoc cntConnection,
416       int iOperationType,
417       int iDataType,
418       Object JavaDoc data
419    ) throws OSSException
420    {
421       switch (iOperationType)
422       {
423          case (DBOP_INSERT) :
424          {
425             throw new OSSDataCreateException(
426                           "Failed to create data in the database.", thr);
427          }
428          case (DBOP_UPDATE) :
429          {
430             throw new OSSDataSaveException(
431                          "Failed to update data in the database.", thr);
432          }
433          case (DBOP_DELETE) :
434          {
435             throw new OSSDataDeleteException(
436                          "Failed to delete data from the database.", thr);
437          }
438          default:
439          {
440             if (GlobalConstants.ERROR_CHECKING)
441             {
442                assert false : "Unknown database update type " + iOperationType;
443             }
444          }
445       }
446    }
447 }
448
Popular Tags