KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > springframework > orm > jdo > DefaultJdoDialect


1 /*
2  * Copyright 2002-2006 the original author or authors.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16
17 package org.springframework.orm.jdo;
18
19 import java.sql.Connection JavaDoc;
20 import java.sql.SQLException JavaDoc;
21 import java.util.Collection JavaDoc;
22
23 import javax.jdo.JDOException;
24 import javax.jdo.PersistenceManager;
25 import javax.jdo.Query;
26 import javax.jdo.Transaction;
27
28 import org.apache.commons.logging.Log;
29 import org.apache.commons.logging.LogFactory;
30
31 import org.springframework.dao.DataAccessException;
32 import org.springframework.dao.support.PersistenceExceptionTranslator;
33 import org.springframework.jdbc.datasource.ConnectionHandle;
34 import org.springframework.jdbc.support.JdbcUtils;
35 import org.springframework.jdbc.support.SQLExceptionTranslator;
36 import org.springframework.transaction.InvalidIsolationLevelException;
37 import org.springframework.transaction.TransactionDefinition;
38 import org.springframework.transaction.TransactionException;
39
40 /**
41  * Default implementation of the JdoDialect interface.
42  * Updated to leverage the JDO 2.0 API when available, as of Spring 1.2.
43  * Used as default dialect by JdoAccessor and JdoTransactionManager.
44  *
45  * <p>Simply begins a standard JDO transaction in <code>beginTransaction</code>.
46  * Returns a handle for a JDO2 DataStoreConnection on <code>getJdbcConnection</code>.
47  * Calls the corresponding JDO2 operations on <code>detachCopy(All)</code>,
48  * <code>attachCopy(All)</code>, <code>flush</code> and <code>newNamedQuery</code>.
49  * Ignores a given query timeout in <code>applyQueryTimeout</code>.
50  * Uses a Spring SQLExceptionTranslator for exception translation, if applicable.
51  *
52  * <p>Note that, even with JDO2, vendor-specific subclasses are still necessary
53  * for special transaction semantics and more sophisticated exception translation.
54  * Furthermore, vendor-specific subclasses are encouraged to expose the native JDBC
55  * Connection on <code>getJdbcConnection</code>, rather than JDO2's wrapper handle.
56  *
57  * <p>This class also implements the PersistenceExceptionTranslator interface,
58  * as autodetected by Spring's PersistenceExceptionTranslationPostProcessor,
59  * for AOP-based translation of native exceptions to Spring DataAccessExceptions.
60  * Hence, the presence of a standard DefaultJdoDialect bean automatically enables
61  * a PersistenceExceptionTranslationPostProcessor to translate JDO exceptions.
62  *
63  * @author Juergen Hoeller
64  * @since 1.1
65  * @see #setJdbcExceptionTranslator
66  * @see JdoAccessor#setJdoDialect
67  * @see JdoTransactionManager#setJdoDialect
68  * @see org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor
69  */

70 public class DefaultJdoDialect implements JdoDialect, PersistenceExceptionTranslator {
71
72     protected final Log logger = LogFactory.getLog(getClass());
73
74     private SQLExceptionTranslator jdbcExceptionTranslator;
75
76
77     /**
78      * Create a new DefaultJdoDialect.
79      */

80     public DefaultJdoDialect() {
81     }
82
83     /**
84      * Create a new DefaultJdoDialect.
85      * @param connectionFactory the connection factory of the JDO PersistenceManagerFactory,
86      * which is used to initialize the default JDBC exception translator
87      * @see javax.jdo.PersistenceManagerFactory#getConnectionFactory()
88      * @see PersistenceManagerFactoryUtils#newJdbcExceptionTranslator(Object)
89      */

90     DefaultJdoDialect(Object JavaDoc connectionFactory) {
91         this.jdbcExceptionTranslator = PersistenceManagerFactoryUtils.newJdbcExceptionTranslator(connectionFactory);
92     }
93
94     /**
95      * Set the JDBC exception translator for this dialect.
96      * <p>Applied to any SQLException root cause of a JDOException, if specified.
97      * The default is to rely on the JDO provider's native exception translation.
98      * @param jdbcExceptionTranslator exception translator
99      * @see java.sql.SQLException
100      * @see javax.jdo.JDOException#getCause()
101      * @see org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator
102      * @see org.springframework.jdbc.support.SQLStateSQLExceptionTranslator
103      */

104     public void setJdbcExceptionTranslator(SQLExceptionTranslator jdbcExceptionTranslator) {
105         this.jdbcExceptionTranslator = jdbcExceptionTranslator;
106     }
107
108     /**
109      * Return the JDBC exception translator for this dialect, if any.
110      */

111     public SQLExceptionTranslator getJdbcExceptionTranslator() {
112         return this.jdbcExceptionTranslator;
113     }
114
115
116     //-------------------------------------------------------------------------
117
// Hooks for transaction management (used by JdoTransactionManager)
118
//-------------------------------------------------------------------------
119

120     /**
121      * This implementation invokes the standard JDO <code>Transaction.begin</code>
122      * method. Throws an InvalidIsolationLevelException if a non-default isolation
123      * level is set.
124      * @see javax.jdo.Transaction#begin
125      * @see org.springframework.transaction.InvalidIsolationLevelException
126      */

127     public Object JavaDoc beginTransaction(Transaction transaction, TransactionDefinition definition)
128             throws JDOException, SQLException JavaDoc, TransactionException {
129
130         if (definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT) {
131             throw new InvalidIsolationLevelException(
132                     "Standard JDO does not support custom isolation levels: " +
133                     "use a special JdoDialect implementation for your JDO provider");
134         }
135         transaction.begin();
136         return null;
137     }
138
139     /**
140      * This implementation does nothing, as the default beginTransaction implementation
141      * does not require any cleanup.
142      * @see #beginTransaction
143      */

144     public void cleanupTransaction(Object JavaDoc transactionData) {
145     }
146
147     /**
148      * This implementation returns a DataStoreConnectionHandle for JDO2,
149      * which will also work on JDO1 until actually accessing the JDBC Connection.
150      * <p>For pre-JDO2 implementations, override this method to return the
151      * Connection through the corresponding vendor-specific mechanism, or <code>null</code>
152      * if the Connection is not retrievable.
153      * <p><b>NOTE:</b> A JDO2 DataStoreConnection is always a wrapper,
154      * never the native JDBC Connection. If you need access to the native JDBC
155      * Connection (or the connection pool handle, to be unwrapped via a Spring
156      * NativeJdbcExtractor), override this method to return the native
157      * Connection through the corresponding vendor-specific mechanism.
158      * <p>A JDO2 DataStoreConnection is only "borrowed" from the PersistenceManager:
159      * it needs to be returned as early as possible. Effectively, JDO2 requires the
160      * fetched Connection to be closed before continuing PersistenceManager work.
161      * For this reason, the exposed ConnectionHandle eagerly releases its JDBC
162      * Connection at the end of each JDBC data access operation (that is, on
163      * <code>DataSourceUtils.releaseConnection</code>).
164      * @see javax.jdo.PersistenceManager#getDataStoreConnection()
165      * @see org.springframework.jdbc.support.nativejdbc.NativeJdbcExtractor
166      * @see org.springframework.jdbc.datasource.DataSourceUtils#releaseConnection
167      */

168     public ConnectionHandle getJdbcConnection(PersistenceManager pm, boolean readOnly)
169             throws JDOException, SQLException JavaDoc {
170
171         return new DataStoreConnectionHandle(pm);
172     }
173
174     /**
175      * This implementation does nothing, assuming that the Connection
176      * will implicitly be closed with the PersistenceManager.
177      * <p>If the JDO provider returns a Connection handle that it
178      * expects the application to close, the dialect needs to invoke
179      * <code>Connection.close</code> here.
180      * @see java.sql.Connection#close()
181      */

182     public void releaseJdbcConnection(ConnectionHandle conHandle, PersistenceManager pm)
183             throws JDOException, SQLException JavaDoc {
184     }
185
186
187     //-------------------------------------------------------------------------
188
// Hooks for special data access operations (used by JdoTemplate)
189
//-------------------------------------------------------------------------
190

191     /**
192      * This implementation delegates to JDO 2.0's <code>detachCopy</code> method.
193      * <p>To be overridden for pre-JDO2 implementations, using the corresponding
194      * vendor-specific mechanism there.
195      * @see javax.jdo.PersistenceManager#detachCopy(Object)
196      */

197     public Object JavaDoc detachCopy(PersistenceManager pm, Object JavaDoc entity) throws JDOException {
198         return pm.detachCopy(entity);
199     }
200
201     /**
202      * This implementation delegates to JDO 2.0's <code>detachCopyAll</code> method.
203      * <p>To be overridden for pre-JDO2 implementations, using the corresponding
204      * vendor-specific mechanism there.
205      * @see javax.jdo.PersistenceManager#detachCopyAll(java.util.Collection)
206      */

207     public Collection JavaDoc detachCopyAll(PersistenceManager pm, Collection JavaDoc entities) throws JDOException {
208         return pm.detachCopyAll(entities);
209     }
210
211     /**
212      * This implementation delegates to JDO 2.0's <code>makePersistent</code> method,
213      * which also serves as facility for reattaching objects as of JDO 2.0 final draft.
214      * <p>To be overridden for pre-JDO2 implementations, using the corresponding
215      * vendor-specific mechanism there.
216      * <p>Note that previous JDO 2.0 drafts specified a dedicated <code>attachCopy</code>
217      * method for this purpose, which Spring's DefaultJdoDialect used to delegate to.
218      * As of Spring 2.0, this has been adapted to the final JDO 2.0 API. You can still
219      * create a custom JdoDialect that uses the pre-final API methods, of course.
220      * @see javax.jdo.PersistenceManager#makePersistent(Object)
221      */

222     public Object JavaDoc attachCopy(PersistenceManager pm, Object JavaDoc detachedEntity) throws JDOException {
223         return pm.makePersistent(detachedEntity);
224     }
225
226     /**
227      * This implementation delegates to JDO 2.0's <code>makePersistentAll</code> method,
228      * which also serves as facility for reattaching objects as of JDO 2.0 final draft.
229      * <p>To be overridden for pre-JDO2 implementations, using the corresponding
230      * vendor-specific mechanism there.
231      * <p>Note that previous JDO 2.0 drafts specified a dedicated <code>attachCopy</code>
232      * method for this purpose, which Spring's DefaultJdoDialect used to delegate to.
233      * As of Spring 2.0, this has been adapted to the final JDO 2.0 API. You can still
234      * create a custom JdoDialect that uses the pre-final API methods, of course.
235      * @see javax.jdo.PersistenceManager#makePersistentAll(java.util.Collection)
236      */

237     public Collection JavaDoc attachCopyAll(PersistenceManager pm, Collection JavaDoc detachedEntities) throws JDOException {
238         return pm.makePersistentAll(detachedEntities);
239     }
240
241     /**
242      * This implementation delegates to JDO 2.0's <code>flush</code> method.
243      * <p>To be overridden for pre-JDO2 implementations, using the corresponding
244      * vendor-specific mechanism there.
245      * @see javax.jdo.PersistenceManager#flush()
246      */

247     public void flush(PersistenceManager pm) throws JDOException {
248         pm.flush();
249     }
250
251     /**
252      * This implementation delegates to JDO 2.0's <code>newNamedQuery</code> method.
253      * <p>To be overridden for pre-JDO2 implementations, using the corresponding
254      * vendor-specific mechanism there.
255      * @see javax.jdo.PersistenceManager#newNamedQuery(Class, String)
256      */

257     public Query newNamedQuery(PersistenceManager pm, Class JavaDoc entityClass, String JavaDoc queryName) throws JDOException {
258         return pm.newNamedQuery(entityClass, queryName);
259     }
260
261     /**
262      * This implementation logs a warning that it cannot apply a query timeout.
263      */

264     public void applyQueryTimeout(Query query, int remainingTimeInSeconds) throws JDOException {
265         logger.info("DefaultJdoDialect does not support query timeouts: ignoring remaining transaction time");
266     }
267
268
269     //-----------------------------------------------------------------------------------
270
// Hook for exception translation (used by JdoTransactionManager and JdoTemplate)
271
//-----------------------------------------------------------------------------------
272

273     /**
274      * Implementation of the PersistenceExceptionTranslator interface,
275      * as autodetected by Spring's PersistenceExceptionTranslationPostProcessor.
276      * <p>Converts the exception if it is a JDOException, using this JdoDialect.
277      * Else returns <code>null</code> to indicate an unknown exception.
278      * @see org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor
279      * @see #translateException
280      */

281     public DataAccessException translateExceptionIfPossible(RuntimeException JavaDoc ex) {
282         if (ex instanceof JDOException) {
283             return translateException((JDOException) ex);
284         }
285         return null;
286     }
287
288     /**
289      * This implementation delegates to PersistenceManagerFactoryUtils.
290      * @see PersistenceManagerFactoryUtils#convertJdoAccessException
291      */

292     public DataAccessException translateException(JDOException ex) {
293         if (getJdbcExceptionTranslator() != null && ex.getCause() instanceof SQLException JavaDoc) {
294             return getJdbcExceptionTranslator().translate("JDO operation: " + ex.getMessage(),
295                     extractSqlStringFromException(ex), (SQLException JavaDoc) ex.getCause());
296         }
297         return PersistenceManagerFactoryUtils.convertJdoAccessException(ex);
298     }
299
300     /**
301      * Template method for extracting a SQL String from the given exception.
302      * <p>Default implementation always returns <code>null</code>. Can be overridden in
303      * subclasses to extract SQL Strings for vendor-specific exception classes.
304      * @param ex the JDOException, containing a SQLException
305      * @return the SQL String, or <code>null</code> if none found
306      */

307     protected String JavaDoc extractSqlStringFromException(JDOException ex) {
308         return null;
309     }
310
311
312     /**
313      * ConnectionHandle implementation that fetches a new JDO2 DataStoreConnection
314      * for every <code>getConnection</code> call and closes the Connection on
315      * <code>releaseConnection</code>. This is necessary because JDO2 requires the
316      * fetched Connection to be closed before continuing PersistenceManager work.
317      * @see javax.jdo.PersistenceManager#getDataStoreConnection()
318      */

319     private static class DataStoreConnectionHandle implements ConnectionHandle {
320
321         private final PersistenceManager persistenceManager;
322
323         public DataStoreConnectionHandle(PersistenceManager persistenceManager) {
324             this.persistenceManager = persistenceManager;
325         }
326
327         public Connection JavaDoc getConnection() {
328             return (Connection JavaDoc) this.persistenceManager.getDataStoreConnection();
329         }
330
331         public void releaseConnection(Connection JavaDoc con) {
332             JdbcUtils.closeConnection(con);
333         }
334     }
335
336 }
337
Popular Tags