001/* 002 * Copyright 2002-2014 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.orm.hibernate4; 018 019import java.lang.reflect.Method; 020import javax.sql.DataSource; 021 022import org.apache.commons.logging.Log; 023import org.apache.commons.logging.LogFactory; 024import org.hibernate.HibernateException; 025import org.hibernate.JDBCException; 026import org.hibernate.NonUniqueObjectException; 027import org.hibernate.NonUniqueResultException; 028import org.hibernate.ObjectDeletedException; 029import org.hibernate.PersistentObjectException; 030import org.hibernate.PessimisticLockException; 031import org.hibernate.PropertyValueException; 032import org.hibernate.QueryException; 033import org.hibernate.QueryTimeoutException; 034import org.hibernate.Session; 035import org.hibernate.SessionFactory; 036import org.hibernate.StaleObjectStateException; 037import org.hibernate.StaleStateException; 038import org.hibernate.TransientObjectException; 039import org.hibernate.UnresolvableObjectException; 040import org.hibernate.WrongClassException; 041import org.hibernate.dialect.lock.OptimisticEntityLockException; 042import org.hibernate.dialect.lock.PessimisticEntityLockException; 043import org.hibernate.engine.spi.SessionFactoryImplementor; 044import org.hibernate.exception.ConstraintViolationException; 045import org.hibernate.exception.DataException; 046import org.hibernate.exception.JDBCConnectionException; 047import org.hibernate.exception.LockAcquisitionException; 048import org.hibernate.exception.SQLGrammarException; 049import org.hibernate.service.spi.Wrapped; 050 051import org.springframework.dao.CannotAcquireLockException; 052import org.springframework.dao.DataAccessException; 053import org.springframework.dao.DataAccessResourceFailureException; 054import org.springframework.dao.DataIntegrityViolationException; 055import org.springframework.dao.DuplicateKeyException; 056import org.springframework.dao.IncorrectResultSizeDataAccessException; 057import org.springframework.dao.InvalidDataAccessApiUsageException; 058import org.springframework.dao.InvalidDataAccessResourceUsageException; 059import org.springframework.dao.PessimisticLockingFailureException; 060import org.springframework.jdbc.datasource.DataSourceUtils; 061import org.springframework.util.ClassUtils; 062import org.springframework.util.ReflectionUtils; 063 064/** 065 * Helper class featuring methods for Hibernate Session handling. 066 * Also provides support for exception translation. 067 * 068 * <p>Used internally by {@link HibernateTransactionManager}. 069 * Can also be used directly in application code. 070 * 071 * @author Juergen Hoeller 072 * @since 3.1 073 * @see HibernateExceptionTranslator 074 * @see HibernateTransactionManager 075 */ 076public abstract class SessionFactoryUtils { 077 078 /** 079 * Order value for TransactionSynchronization objects that clean up Hibernate Sessions. 080 * Returns {@code DataSourceUtils.CONNECTION_SYNCHRONIZATION_ORDER - 100} 081 * to execute Session cleanup before JDBC Connection cleanup, if any. 082 * @see org.springframework.jdbc.datasource.DataSourceUtils#CONNECTION_SYNCHRONIZATION_ORDER 083 */ 084 public static final int SESSION_SYNCHRONIZATION_ORDER = 085 DataSourceUtils.CONNECTION_SYNCHRONIZATION_ORDER - 100; 086 087 static final Log logger = LogFactory.getLog(SessionFactoryUtils.class); 088 089 /** 090 * Bridging between the different ConnectionProvider package location in 4.0-4.2 vs 4.3. 091 */ 092 private static final Method getConnectionProviderMethod = 093 ClassUtils.getMethodIfAvailable(SessionFactoryImplementor.class, "getConnectionProvider"); 094 095 096 /** 097 * Determine the DataSource of the given SessionFactory. 098 * @param sessionFactory the SessionFactory to check 099 * @return the DataSource, or {@code null} if none found 100 * @see org.hibernate.engine.spi.SessionFactoryImplementor#getConnectionProvider 101 */ 102 public static DataSource getDataSource(SessionFactory sessionFactory) { 103 if (getConnectionProviderMethod != null && sessionFactory instanceof SessionFactoryImplementor) { 104 Wrapped cp = (Wrapped) ReflectionUtils.invokeMethod(getConnectionProviderMethod, sessionFactory); 105 if (cp != null) { 106 return cp.unwrap(DataSource.class); 107 } 108 } 109 return null; 110 } 111 112 /** 113 * Perform actual closing of the Hibernate Session, 114 * catching and logging any cleanup exceptions thrown. 115 * @param session the Hibernate Session to close (may be {@code null}) 116 * @see org.hibernate.Session#close() 117 */ 118 public static void closeSession(Session session) { 119 if (session != null) { 120 try { 121 session.close(); 122 } 123 catch (HibernateException ex) { 124 logger.debug("Could not close Hibernate Session", ex); 125 } 126 catch (Throwable ex) { 127 logger.debug("Unexpected exception on closing Hibernate Session", ex); 128 } 129 } 130 } 131 132 /** 133 * Convert the given HibernateException to an appropriate exception 134 * from the {@code org.springframework.dao} hierarchy. 135 * @param ex HibernateException that occurred 136 * @return the corresponding DataAccessException instance 137 * @see HibernateExceptionTranslator#convertHibernateAccessException 138 * @see HibernateTransactionManager#convertHibernateAccessException 139 */ 140 public static DataAccessException convertHibernateAccessException(HibernateException ex) { 141 if (ex instanceof JDBCConnectionException) { 142 return new DataAccessResourceFailureException(ex.getMessage(), ex); 143 } 144 if (ex instanceof SQLGrammarException) { 145 SQLGrammarException jdbcEx = (SQLGrammarException) ex; 146 return new InvalidDataAccessResourceUsageException(ex.getMessage() + "; SQL [" + jdbcEx.getSQL() + "]", ex); 147 } 148 if (ex instanceof QueryTimeoutException) { 149 QueryTimeoutException jdbcEx = (QueryTimeoutException) ex; 150 return new org.springframework.dao.QueryTimeoutException(ex.getMessage() + "; SQL [" + jdbcEx.getSQL() + "]", ex); 151 } 152 if (ex instanceof LockAcquisitionException) { 153 LockAcquisitionException jdbcEx = (LockAcquisitionException) ex; 154 return new CannotAcquireLockException(ex.getMessage() + "; SQL [" + jdbcEx.getSQL() + "]", ex); 155 } 156 if (ex instanceof PessimisticLockException) { 157 PessimisticLockException jdbcEx = (PessimisticLockException) ex; 158 return new PessimisticLockingFailureException(ex.getMessage() + "; SQL [" + jdbcEx.getSQL() + "]", ex); 159 } 160 if (ex instanceof ConstraintViolationException) { 161 ConstraintViolationException jdbcEx = (ConstraintViolationException) ex; 162 return new DataIntegrityViolationException(ex.getMessage() + "; SQL [" + jdbcEx.getSQL() + 163 "]; constraint [" + jdbcEx.getConstraintName() + "]", ex); 164 } 165 if (ex instanceof DataException) { 166 DataException jdbcEx = (DataException) ex; 167 return new DataIntegrityViolationException(ex.getMessage() + "; SQL [" + jdbcEx.getSQL() + "]", ex); 168 } 169 if (ex instanceof JDBCException) { 170 return new HibernateJdbcException((JDBCException) ex); 171 } 172 // end of JDBCException (subclass) handling 173 174 if (ex instanceof QueryException) { 175 return new HibernateQueryException((QueryException) ex); 176 } 177 if (ex instanceof NonUniqueResultException) { 178 return new IncorrectResultSizeDataAccessException(ex.getMessage(), 1, ex); 179 } 180 if (ex instanceof NonUniqueObjectException) { 181 return new DuplicateKeyException(ex.getMessage(), ex); 182 } 183 if (ex instanceof PropertyValueException) { 184 return new DataIntegrityViolationException(ex.getMessage(), ex); 185 } 186 if (ex instanceof PersistentObjectException) { 187 return new InvalidDataAccessApiUsageException(ex.getMessage(), ex); 188 } 189 if (ex instanceof TransientObjectException) { 190 return new InvalidDataAccessApiUsageException(ex.getMessage(), ex); 191 } 192 if (ex instanceof ObjectDeletedException) { 193 return new InvalidDataAccessApiUsageException(ex.getMessage(), ex); 194 } 195 if (ex instanceof UnresolvableObjectException) { 196 return new HibernateObjectRetrievalFailureException((UnresolvableObjectException) ex); 197 } 198 if (ex instanceof WrongClassException) { 199 return new HibernateObjectRetrievalFailureException((WrongClassException) ex); 200 } 201 if (ex instanceof StaleObjectStateException) { 202 return new HibernateOptimisticLockingFailureException((StaleObjectStateException) ex); 203 } 204 if (ex instanceof StaleStateException) { 205 return new HibernateOptimisticLockingFailureException((StaleStateException) ex); 206 } 207 if (ex instanceof OptimisticEntityLockException) { 208 return new HibernateOptimisticLockingFailureException((OptimisticEntityLockException) ex); 209 } 210 if (ex instanceof PessimisticEntityLockException) { 211 if (ex.getCause() instanceof LockAcquisitionException) { 212 return new CannotAcquireLockException(ex.getMessage(), ex.getCause()); 213 } 214 return new PessimisticLockingFailureException(ex.getMessage(), ex); 215 } 216 217 // fallback 218 return new HibernateSystemException(ex); 219 } 220 221}