|
From: Juergen H. <jho...@us...> - 2007-01-31 22:53:00
|
Update of /cvsroot/springframework/spring/src/org/springframework/orm/hibernate3 In directory sc8-pr-cvs8.sourceforge.net:/tmp/cvs-serv32055/src/org/springframework/orm/hibernate3 Modified Files: HibernateTransactionManager.java SessionFactoryUtils.java HibernateAccessor.java Log Message: SessionFactoryUtils translates SQLGrammar/DataException into InvalidDataAccessResourceUsageException; HibernateAccessor/HibernateTransactionManager translates GenericJDBCException using a default SQLExceptionTranslator Index: SessionFactoryUtils.java =================================================================== RCS file: /cvsroot/springframework/spring/src/org/springframework/orm/hibernate3/SessionFactoryUtils.java,v retrieving revision 1.35 retrieving revision 1.36 diff -C2 -d -r1.35 -r1.36 *** SessionFactoryUtils.java 3 Nov 2006 15:03:52 -0000 1.35 --- SessionFactoryUtils.java 31 Jan 2007 22:52:50 -0000 1.36 *************** *** 1,4 **** /* ! * Copyright 2002-2006 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); --- 1,4 ---- /* ! * Copyright 2002-2007 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); *************** *** 50,55 **** --- 50,57 ---- import org.hibernate.engine.SessionFactoryImplementor; import org.hibernate.exception.ConstraintViolationException; + import org.hibernate.exception.DataException; import org.hibernate.exception.JDBCConnectionException; import org.hibernate.exception.LockAcquisitionException; + import org.hibernate.exception.SQLGrammarException; import org.springframework.core.CollectionFactory; *************** *** 60,63 **** --- 62,66 ---- import org.springframework.dao.IncorrectResultSizeDataAccessException; import org.springframework.dao.InvalidDataAccessApiUsageException; + import org.springframework.dao.InvalidDataAccessResourceUsageException; import org.springframework.jdbc.datasource.DataSourceUtils; import org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator; *************** *** 627,636 **** return new DataAccessResourceFailureException(ex.getMessage(), ex); } ! if (ex instanceof ConstraintViolationException) { ! return new DataIntegrityViolationException(ex.getMessage(), ex); } if (ex instanceof LockAcquisitionException) { return new CannotAcquireLockException(ex.getMessage(), ex); } if (ex instanceof JDBCException) { return new HibernateJdbcException((JDBCException) ex); --- 630,645 ---- return new DataAccessResourceFailureException(ex.getMessage(), ex); } ! if (ex instanceof SQLGrammarException) { ! return new InvalidDataAccessResourceUsageException(ex.getMessage(), ex); ! } ! if (ex instanceof DataException) { ! return new InvalidDataAccessResourceUsageException(ex.getMessage(), ex); } if (ex instanceof LockAcquisitionException) { return new CannotAcquireLockException(ex.getMessage(), ex); } + if (ex instanceof ConstraintViolationException) { + return new DataIntegrityViolationException(ex.getMessage(), ex); + } if (ex instanceof JDBCException) { return new HibernateJdbcException((JDBCException) ex); Index: HibernateAccessor.java =================================================================== RCS file: /cvsroot/springframework/spring/src/org/springframework/orm/hibernate3/HibernateAccessor.java,v retrieving revision 1.13 retrieving revision 1.14 diff -C2 -d -r1.13 -r1.14 *** HibernateAccessor.java 1 Jan 2007 15:54:25 -0000 1.13 --- HibernateAccessor.java 31 Jan 2007 22:52:51 -0000 1.14 *************** *** 27,30 **** --- 27,31 ---- import org.hibernate.Session; import org.hibernate.SessionFactory; + import org.hibernate.exception.GenericJDBCException; import org.springframework.beans.BeansException; *************** *** 37,42 **** /** ! * Base class for HibernateTemplate and HibernateInterceptor, defining common ! * properties such as SessionFactory and flushing behavior. * * <p>Not intended to be used directly. --- 38,43 ---- /** ! * Base class for {@link HibernateTemplate} and {@link HibernateInterceptor}, ! * defining common properties such as SessionFactory and flushing behavior. * * <p>Not intended to be used directly. *************** *** 129,132 **** --- 130,135 ---- private SQLExceptionTranslator jdbcExceptionTranslator; + private SQLExceptionTranslator defaultJdbcExceptionTranslator; + private int flushMode = FLUSH_AUTO; *************** *** 309,313 **** public void afterPropertiesSet() { if (getSessionFactory() == null) { ! throw new IllegalArgumentException("sessionFactory is required"); } } --- 312,316 ---- public void afterPropertiesSet() { if (getSessionFactory() == null) { ! throw new IllegalArgumentException("Property 'sessionFactory' is required"); } } *************** *** 389,395 **** } /** ! * Convert the given HibernateException to an appropriate exception from the ! * <code>org.springframework.dao</code> hierarchy. * <p>Will automatically apply a specified SQLExceptionTranslator to a * Hibernate JDBCException, else rely on Hibernate's default translation. --- 392,399 ---- } + /** ! * Convert the given HibernateException to an appropriate exception ! * from the <code>org.springframework.dao</code> hierarchy. * <p>Will automatically apply a specified SQLExceptionTranslator to a * Hibernate JDBCException, else rely on Hibernate's default translation. *************** *** 401,407 **** public DataAccessException convertHibernateAccessException(HibernateException ex) { if (getJdbcExceptionTranslator() != null && ex instanceof JDBCException) { ! JDBCException jdbcEx = (JDBCException) ex; ! return getJdbcExceptionTranslator().translate( ! "Hibernate operation: " + jdbcEx.getMessage(), jdbcEx.getSQL(), jdbcEx.getSQLException()); } return SessionFactoryUtils.convertHibernateAccessException(ex); --- 405,412 ---- public DataAccessException convertHibernateAccessException(HibernateException ex) { if (getJdbcExceptionTranslator() != null && ex instanceof JDBCException) { ! return convertJdbcAccessException((JDBCException) ex, getJdbcExceptionTranslator()); ! } ! else if (GenericJDBCException.class.equals(ex.getClass())) { ! return convertJdbcAccessException((GenericJDBCException) ex, getDefaultJdbcExceptionTranslator()); } return SessionFactoryUtils.convertHibernateAccessException(ex); *************** *** 409,412 **** --- 414,429 ---- /** + * Convert the given Hibernate JDBCException to an appropriate exception + * from the <code>org.springframework.dao</code> hierarchy, using the + * given SQLExceptionTranslator. + * @param ex Hibernate JDBCException that occured + * @param translator the SQLExceptionTranslator to use + * @return a corresponding DataAccessException + */ + protected DataAccessException convertJdbcAccessException(JDBCException ex, SQLExceptionTranslator translator) { + return translator.translate("Hibernate operation: " + ex.getMessage(), ex.getSQL(), ex.getSQLException()); + } + + /** * Convert the given SQLException to an appropriate exception from the * <code>org.springframework.dao</code> hierarchy. Can be overridden in subclasses. *************** *** 421,425 **** SQLExceptionTranslator translator = getJdbcExceptionTranslator(); if (translator == null) { ! translator = SessionFactoryUtils.newJdbcExceptionTranslator(getSessionFactory()); } return translator.translate("Hibernate-related JDBC operation", null, ex); --- 438,442 ---- SQLExceptionTranslator translator = getJdbcExceptionTranslator(); if (translator == null) { ! translator = getDefaultJdbcExceptionTranslator(); } return translator.translate("Hibernate-related JDBC operation", null, ex); *************** *** 427,430 **** --- 444,461 ---- /** + * Obtain a default SQLExceptionTranslator, lazily creating it if necessary. + * <p>Creates a default + * {@link org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator} + * for the SessionFactory's underlying DataSource. + */ + protected synchronized SQLExceptionTranslator getDefaultJdbcExceptionTranslator() { + if (this.defaultJdbcExceptionTranslator == null) { + this.defaultJdbcExceptionTranslator = SessionFactoryUtils.newJdbcExceptionTranslator(getSessionFactory()); + } + return this.defaultJdbcExceptionTranslator; + } + + + /** * Enable the specified filters on the given Session. * @param session the current Hibernate Session Index: HibernateTransactionManager.java =================================================================== RCS file: /cvsroot/springframework/spring/src/org/springframework/orm/hibernate3/HibernateTransactionManager.java,v retrieving revision 1.28 retrieving revision 1.29 diff -C2 -d -r1.28 -r1.29 *** HibernateTransactionManager.java 22 Dec 2006 20:45:08 -0000 1.28 --- HibernateTransactionManager.java 31 Jan 2007 22:52:50 -0000 1.29 *************** *** 1,4 **** /* ! * Copyright 2002-2006 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); --- 1,4 ---- /* ! * Copyright 2002-2007 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); *************** *** 29,32 **** --- 29,33 ---- import org.hibernate.SessionFactory; import org.hibernate.Transaction; + import org.hibernate.exception.GenericJDBCException; import org.hibernate.impl.SessionImpl; *************** *** 40,43 **** --- 41,45 ---- import org.springframework.jdbc.datasource.JdbcTransactionObjectSupport; import org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy; + import org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator; import org.springframework.jdbc.support.SQLExceptionTranslator; import org.springframework.transaction.CannotCreateTransactionException; *************** *** 52,68 **** /** ! * PlatformTransactionManager implementation for a single Hibernate SessionFactory. * Binds a Hibernate Session from the specified factory to the thread, potentially ! * allowing for one thread Session per factory. SessionFactoryUtils and ! * HibernateTemplate are aware of thread-bound Sessions and participate in such ! * transactions automatically. Using either of those or going through * <code>SessionFactory.getCurrentSession()</code> is required for Hibernate * access code that needs to support this transaction handling mechanism. * ! * <p>Supports custom isolation levels, and timeouts that get applied as appropriate ! * Hibernate query timeouts. To support the latter, application code must either use ! * <code>HibernateTemplate</code> (which by default applies the timeouts) or call ! * <code>SessionFactoryUtils.applyTransactionTimeout</code> for each created ! * Hibernate Query object. * * <p>This implementation is appropriate for applications that solely use Hibernate --- 54,68 ---- /** ! * {@link org.springframework.transaction.PlatformTransactionManager} ! * implementation for a single Hibernate {@link org.hibernate.SessionFactory}. * Binds a Hibernate Session from the specified factory to the thread, potentially ! * allowing for one thread Session per factory. {@link SessionFactoryUtils} and ! * {@link HibernateTemplate} are aware of thread-bound Sessions and participate ! * in such transactions automatically. Using either of those or going through * <code>SessionFactory.getCurrentSession()</code> is required for Hibernate * access code that needs to support this transaction handling mechanism. * ! * <p>Supports custom isolation levels, and timeouts that get applied as ! * Hibernate transaction timeouts.. * * <p>This implementation is appropriate for applications that solely use Hibernate *************** *** 72,108 **** * caching) and services that use plain JDBC (without being aware of Hibernate)! * Application code needs to stick to the same simple Connection lookup pattern as ! * with DataSourceTransactionManager (i.e. <code>DataSourceUtils.getConnection</code> ! * or going through a TransactionAwareDataSourceProxy). * * <p>Note that to be able to register a DataSource's Connection for plain JDBC ! * code, this instance needs to be aware of the DataSource (see setDataSource). * The given DataSource should obviously match the one used by the given * SessionFactory. To achieve this, configure both to the same JNDI DataSource, ! * or preferably create the SessionFactory with LocalSessionFactoryBean and * a local DataSource (which will be autodetected by this transaction manager). * ! * <p>JTA (usually through JtaTransactionManager) is necessary for accessing multiple ! * transactional resources. The DataSource that Hibernate uses needs to be JTA-enabled ! * then (see container setup), alternatively the Hibernate JCA connector can be used ! * for direct container integration. Normally, JTA setup for Hibernate is somewhat ! * container-specific due to the JTA TransactionManager lookup, required for proper ! * transactional handling of the SessionFactory-level read-write cache. * ! * <p>Fortunately, there is an easier way with Spring: SessionFactoryUtils (and thus ! * HibernateTemplate) registers synchronizations with TransactionSynchronizationManager ! * (as used by JtaTransactionManager), for proper afterCompletion callbacks. Therefore, ! * as long as Spring's JtaTransactionManager drives the JTA transactions, Hibernate ! * does not require any special configuration for proper JTA participation. ! * Note that there are special cases with EJB CMT and restrictive JTA subsystems: ! * See JtaTransactionManager's javadoc for details. * ! * <p>On JDBC 3.0, this transaction manager supports nested transactions via JDBC ! * 3.0 Savepoints. The "nestedTransactionAllowed" flag defaults to "false", though, ! * as nested transactions will just apply to the JDBC Connection, not to the ! * Hibernate Session and its cached objects. You can manually set the flag to "true" ! * if you want to use nested transactions for JDBC access code that participates ! * in Hibernate transactions (provided that your JDBC driver supports Savepoints). ! * <i>Note that Hibernate itself does not support nested transactions! Hence, ! * do not expect Hibernate access code to participate in a nested transaction.</i> * * <p>Requires Hibernate 3.0.3 or later. As of Spring 2.0, this transaction manager --- 72,113 ---- * caching) and services that use plain JDBC (without being aware of Hibernate)! * Application code needs to stick to the same simple Connection lookup pattern as ! * with {@link org.springframework.jdbc.datasource.DataSourceTransactionManager} ! * (i.e. {@link org.springframework.jdbc.datasource.DataSourceUtils#getConnection} ! * or going through a ! * {@link org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy}). * * <p>Note that to be able to register a DataSource's Connection for plain JDBC ! * code, this instance needs to be aware of the DataSource ({@link #setDataSource}). * The given DataSource should obviously match the one used by the given * SessionFactory. To achieve this, configure both to the same JNDI DataSource, ! * or preferably create the SessionFactory with {@link LocalSessionFactoryBean} and * a local DataSource (which will be autodetected by this transaction manager). * ! * <p>JTA (usually through {@link org.springframework.transaction.jta.JtaTransactionManager}) ! * is necessary for accessing multiple transactional resources within the same ! * transaction. The DataSource that Hibernate uses needs to be JTA-enabled in ! * such a scenario (see container setup). Normally, JTA setup for Hibernate is ! * somewhat container-specific due to the JTA TransactionManager lookup, required ! * for proper transactional handling of the SessionFactory-level read-write cache. * ! * <p>Fortunately, there is an easier way with Spring: {@link SessionFactoryUtils} ! * (and thus {@link HibernateTemplate}) registers synchronizations with Spring's ! * {@link org.springframework.transaction.support.TransactionSynchronizationManager} ! * (as used by {@link org.springframework.transaction.jta.JtaTransactionManager}), ! * for proper after-completion callbacks. Therefore, as long as Spring's ! * JtaTransactionManager drives the JTA transactions, Hibernate does not require ! * any special configuration for proper JTA participation. Note that there are ! * special restrictions with EJB CMT and restrictive JTA subsystems: See ! * {@link org.springframework.transaction.jta.JtaTransactionManager}'s javadoc for details. * ! * <p>On JDBC 3.0, this transaction manager supports nested transactions via JDBC 3.0 ! * Savepoints. The {@link #setNestedTransactionAllowed} "nestedTransactionAllowed"} ! * flag defaults to "false", though, as nested transactions will just apply to the ! * JDBC Connection, not to the Hibernate Session and its cached objects. You can ! * manually set the flag to "true" if you want to use nested transactions for ! * JDBC access code which participates in Hibernate transactions (provided that ! * your JDBC driver supports Savepoints). <i>Note that Hibernate itself does not ! * support nested transactions! Hence, do not expect Hibernate access code to ! * semantically participate in a nested transaction.</i> * * <p>Requires Hibernate 3.0.3 or later. As of Spring 2.0, this transaction manager *************** *** 150,153 **** --- 155,160 ---- private SQLExceptionTranslator jdbcExceptionTranslator; + private SQLExceptionTranslator defaultJdbcExceptionTranslator; + /** * Just needed for entityInterceptorBeanName. *************** *** 359,366 **** public void afterPropertiesSet() { if (getSessionFactory() == null) { ! throw new IllegalArgumentException("sessionFactory is required"); } if (this.entityInterceptor instanceof String && this.beanFactory == null) { ! throw new IllegalArgumentException("beanFactory is required for entityInterceptorBeanName"); } --- 366,373 ---- public void afterPropertiesSet() { if (getSessionFactory() == null) { ! throw new IllegalArgumentException("Property 'sessionFactory' is required"); } if (this.entityInterceptor instanceof String && this.beanFactory == null) { ! throw new IllegalArgumentException("Property 'beanFactory' is required for 'entityInterceptorBeanName'"); } *************** *** 681,687 **** } /** ! * Convert the given HibernateException to an appropriate exception from the ! * <code>org.springframework.dao</code> hierarchy. * <p>Will automatically apply a specified SQLExceptionTranslator to a * Hibernate JDBCException, else rely on Hibernate's default translation. --- 688,695 ---- } + /** ! * Convert the given HibernateException to an appropriate exception ! * from the <code>org.springframework.dao</code> hierarchy. * <p>Will automatically apply a specified SQLExceptionTranslator to a * Hibernate JDBCException, else rely on Hibernate's default translation. *************** *** 693,703 **** protected DataAccessException convertHibernateAccessException(HibernateException ex) { if (getJdbcExceptionTranslator() != null && ex instanceof JDBCException) { ! JDBCException jdbcEx = (JDBCException) ex; ! return getJdbcExceptionTranslator().translate( ! "Hibernate flushing: " + jdbcEx.getMessage(), jdbcEx.getSQL(), jdbcEx.getSQLException()); } return SessionFactoryUtils.convertHibernateAccessException(ex); } /** --- 701,742 ---- protected DataAccessException convertHibernateAccessException(HibernateException ex) { if (getJdbcExceptionTranslator() != null && ex instanceof JDBCException) { ! return convertJdbcAccessException((JDBCException) ex, getJdbcExceptionTranslator()); ! } ! else if (GenericJDBCException.class.equals(ex.getClass())) { ! return convertJdbcAccessException((GenericJDBCException) ex, getDefaultJdbcExceptionTranslator()); } return SessionFactoryUtils.convertHibernateAccessException(ex); } + /** + * Convert the given Hibernate JDBCException to an appropriate exception + * from the <code>org.springframework.dao</code> hierarchy, using the + * given SQLExceptionTranslator. + * @param ex Hibernate JDBCException that occured + * @param translator the SQLExceptionTranslator to use + * @return a corresponding DataAccessException + */ + protected DataAccessException convertJdbcAccessException(JDBCException ex, SQLExceptionTranslator translator) { + return translator.translate("Hibernate flushing: " + ex.getMessage(), ex.getSQL(), ex.getSQLException()); + } + + /** + * Obtain a default SQLExceptionTranslator, lazily creating it if necessary. + * <p>Creates a default + * {@link org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator} + * for the SessionFactory's underlying DataSource. + */ + protected synchronized SQLExceptionTranslator getDefaultJdbcExceptionTranslator() { + if (this.defaultJdbcExceptionTranslator == null) { + if (getDataSource() != null) { + this.defaultJdbcExceptionTranslator = new SQLErrorCodeSQLExceptionTranslator(getDataSource()); + } + else { + this.defaultJdbcExceptionTranslator = SessionFactoryUtils.newJdbcExceptionTranslator(getSessionFactory()); + } + } + return this.defaultJdbcExceptionTranslator; + } + /** *************** *** 705,710 **** * Used as transaction object by HibernateTransactionManager. * ! * <p>Derives from JdbcTransactionObjectSupport to inherit the capability ! * to manage JDBC 3.0 Savepoints for underlying JDBC Connections. * * @see SessionHolder --- 744,749 ---- * Used as transaction object by HibernateTransactionManager. * ! * <p>Derives from JdbcTransactionObjectSupport in order to inherit the ! * capability to manage JDBC 3.0 Savepoints for underlying JDBC Connections. * * @see SessionHolder *************** *** 722,730 **** public SessionHolder getSessionHolder() { ! return sessionHolder; } public boolean isNewSessionHolder() { ! return newSessionHolder; } --- 761,769 ---- public SessionHolder getSessionHolder() { ! return this.sessionHolder; } public boolean isNewSessionHolder() { ! return this.newSessionHolder; } *************** *** 749,753 **** /** * Holder for suspended resources. ! * Used internally by doSuspend and doResume. */ private static class SuspendedResourcesHolder { --- 788,792 ---- /** * Holder for suspended resources. ! * Used internally by <code>doSuspend</code> and <code>doResume</code>. */ private static class SuspendedResourcesHolder { *************** *** 763,771 **** private SessionHolder getSessionHolder() { ! return sessionHolder; } private ConnectionHolder getConnectionHolder() { ! return connectionHolder; } } --- 802,810 ---- private SessionHolder getSessionHolder() { ! return this.sessionHolder; } private ConnectionHolder getConnectionHolder() { ! return this.connectionHolder; } } |