1 16 17 package org.springframework.orm.hibernate; 18 19 import java.util.HashMap ; 20 import java.util.Iterator ; 21 import java.util.Map ; 22 import java.util.Set ; 23 24 import javax.sql.DataSource ; 25 import javax.transaction.Status ; 26 import javax.transaction.Transaction ; 27 import javax.transaction.TransactionManager ; 28 29 import net.sf.hibernate.Criteria; 30 import net.sf.hibernate.FlushMode; 31 import net.sf.hibernate.HibernateException; 32 import net.sf.hibernate.Interceptor; 33 import net.sf.hibernate.JDBCException; 34 import net.sf.hibernate.NonUniqueResultException; 35 import net.sf.hibernate.ObjectDeletedException; 36 import net.sf.hibernate.PersistentObjectException; 37 import net.sf.hibernate.Query; 38 import net.sf.hibernate.QueryException; 39 import net.sf.hibernate.Session; 40 import net.sf.hibernate.SessionFactory; 41 import net.sf.hibernate.StaleObjectStateException; 42 import net.sf.hibernate.TransientObjectException; 43 import net.sf.hibernate.UnresolvableObjectException; 44 import net.sf.hibernate.WrongClassException; 45 import net.sf.hibernate.connection.ConnectionProvider; 46 import net.sf.hibernate.engine.SessionFactoryImplementor; 47 import org.apache.commons.logging.Log; 48 import org.apache.commons.logging.LogFactory; 49 50 import org.springframework.core.CollectionFactory; 51 import org.springframework.dao.DataAccessException; 52 import org.springframework.dao.DataAccessResourceFailureException; 53 import org.springframework.dao.IncorrectResultSizeDataAccessException; 54 import org.springframework.dao.InvalidDataAccessApiUsageException; 55 import org.springframework.jdbc.datasource.DataSourceUtils; 56 import org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator; 57 import org.springframework.jdbc.support.SQLExceptionTranslator; 58 import org.springframework.jdbc.support.SQLStateSQLExceptionTranslator; 59 import org.springframework.transaction.jta.SpringJtaSynchronizationAdapter; 60 import org.springframework.transaction.support.TransactionSynchronizationManager; 61 import org.springframework.util.Assert; 62 63 91 public abstract class SessionFactoryUtils { 92 93 99 public static final int SESSION_SYNCHRONIZATION_ORDER = 100 DataSourceUtils.CONNECTION_SYNCHRONIZATION_ORDER - 100; 101 102 static final Log logger = LogFactory.getLog(SessionFactoryUtils.class); 103 104 private static final ThreadLocal deferredCloseHolder = new ThreadLocal (); 105 106 107 114 public static DataSource getDataSource(SessionFactory sessionFactory) { 115 if (sessionFactory instanceof SessionFactoryImplementor) { 116 ConnectionProvider cp = ((SessionFactoryImplementor) sessionFactory).getConnectionProvider(); 117 if (cp instanceof LocalDataSourceConnectionProvider) { 118 return ((LocalDataSourceConnectionProvider) cp).getDataSource(); 119 } 120 } 121 return null; 122 } 123 124 134 public static SQLExceptionTranslator newJdbcExceptionTranslator(SessionFactory sessionFactory) { 135 DataSource ds = getDataSource(sessionFactory); 136 if (ds != null) { 137 return new SQLErrorCodeSQLExceptionTranslator(ds); 138 } 139 return new SQLStateSQLExceptionTranslator(); 140 } 141 142 157 public static TransactionManager getJtaTransactionManager(SessionFactory sessionFactory, Session session) { 158 SessionFactoryImplementor sessionFactoryImpl = null; 159 if (sessionFactory instanceof SessionFactoryImplementor) { 160 sessionFactoryImpl = ((SessionFactoryImplementor) sessionFactory); 161 } 162 else if (session != null) { 163 SessionFactory internalFactory = session.getSessionFactory(); 164 if (internalFactory instanceof SessionFactoryImplementor) { 165 sessionFactoryImpl = (SessionFactoryImplementor) internalFactory; 166 } 167 } 168 return (sessionFactoryImpl != null ? sessionFactoryImpl.getTransactionManager() : null); 169 } 170 171 172 191 public static Session getSession(SessionFactory sessionFactory, boolean allowCreate) 192 throws DataAccessResourceFailureException, IllegalStateException { 193 194 return getSession(sessionFactory, null, null, allowCreate); 195 } 196 197 218 public static Session getSession( 219 SessionFactory sessionFactory, Interceptor entityInterceptor, 220 SQLExceptionTranslator jdbcExceptionTranslator) throws DataAccessResourceFailureException { 221 222 return getSession(sessionFactory, entityInterceptor, jdbcExceptionTranslator, true); 223 } 224 225 241 private static Session getSession( 242 SessionFactory sessionFactory, Interceptor entityInterceptor, 243 SQLExceptionTranslator jdbcExceptionTranslator, boolean allowCreate) 244 throws DataAccessResourceFailureException, IllegalStateException { 245 246 Assert.notNull(sessionFactory, "No SessionFactory specified"); 247 248 SessionHolder sessionHolder = (SessionHolder) TransactionSynchronizationManager.getResource(sessionFactory); 249 if (sessionHolder != null && !sessionHolder.isEmpty()) { 250 Session session = null; 252 if (TransactionSynchronizationManager.isSynchronizationActive() && 253 sessionHolder.doesNotHoldNonDefaultSession()) { 254 session = sessionHolder.getValidatedSession(); 257 if (!sessionHolder.isSynchronizedWithTransaction()) { 258 logger.debug("Registering Spring transaction synchronization for existing Hibernate Session"); 259 TransactionSynchronizationManager.registerSynchronization( 260 new SpringSessionSynchronization(sessionHolder, sessionFactory, jdbcExceptionTranslator, false)); 261 sessionHolder.setSynchronizedWithTransaction(true); 262 FlushMode flushMode = session.getFlushMode(); 264 if (FlushMode.NEVER.equals(flushMode) && 265 !TransactionSynchronizationManager.isCurrentTransactionReadOnly()) { 266 session.setFlushMode(FlushMode.AUTO); 267 sessionHolder.setPreviousFlushMode(flushMode); 268 } 269 } 270 } 271 else { 272 session = getJtaSynchronizedSession(sessionHolder, sessionFactory, jdbcExceptionTranslator); 274 } 275 if (session != null) { 276 return session; 277 } 278 } 279 280 try { 281 logger.debug("Opening Hibernate Session"); 282 Session session = (entityInterceptor != null ? 283 sessionFactory.openSession(entityInterceptor) : sessionFactory.openSession()); 284 285 if (TransactionSynchronizationManager.isSynchronizationActive()) { 289 logger.debug("Registering Spring transaction synchronization for new Hibernate Session"); 291 SessionHolder holderToUse = sessionHolder; 292 if (holderToUse == null) { 293 holderToUse = new SessionHolder(session); 294 } 295 else { 296 holderToUse.addSession(session); 297 } 298 if (TransactionSynchronizationManager.isCurrentTransactionReadOnly()) { 299 session.setFlushMode(FlushMode.NEVER); 300 } 301 TransactionSynchronizationManager.registerSynchronization( 302 new SpringSessionSynchronization(holderToUse, sessionFactory, jdbcExceptionTranslator, true)); 303 holderToUse.setSynchronizedWithTransaction(true); 304 if (holderToUse != sessionHolder) { 305 TransactionSynchronizationManager.bindResource(sessionFactory, holderToUse); 306 } 307 } 308 else { 309 registerJtaSynchronization(session, sessionFactory, jdbcExceptionTranslator, sessionHolder); 311 } 312 313 if (!allowCreate && !isSessionTransactional(session, sessionFactory)) { 315 closeSession(session); 316 throw new IllegalStateException ("No Hibernate Session bound to thread, " + 317 "and configuration does not allow creation of non-transactional one here"); 318 } 319 320 return session; 321 } 322 catch (HibernateException ex) { 323 throw new DataAccessResourceFailureException("Could not open Hibernate Session", ex); 324 } 325 } 326 327 337 private static Session getJtaSynchronizedSession( 338 SessionHolder sessionHolder, SessionFactory sessionFactory, 339 SQLExceptionTranslator jdbcExceptionTranslator) throws DataAccessResourceFailureException { 340 341 TransactionManager jtaTm = getJtaTransactionManager(sessionFactory, sessionHolder.getAnySession()); 345 if (jtaTm != null) { 346 try { 351 Transaction jtaTx = jtaTm.getTransaction(); 353 if (jtaTx != null) { 354 int jtaStatus = jtaTx.getStatus(); 355 if (jtaStatus == Status.STATUS_ACTIVE || jtaStatus == Status.STATUS_MARKED_ROLLBACK) { 356 Session session = sessionHolder.getValidatedSession(jtaTx); 357 if (session == null && !sessionHolder.isSynchronizedWithTransaction()) { 358 session = sessionHolder.getValidatedSession(); 364 if (session != null) { 365 logger.debug("Registering JTA transaction synchronization for existing Hibernate Session"); 366 sessionHolder.addSession(jtaTx, session); 367 jtaTx.registerSynchronization( 368 new SpringJtaSynchronizationAdapter( 369 new SpringSessionSynchronization(sessionHolder, sessionFactory, jdbcExceptionTranslator, false), 370 jtaTm)); 371 sessionHolder.setSynchronizedWithTransaction(true); 372 FlushMode flushMode = session.getFlushMode(); 374 if (FlushMode.NEVER.equals(flushMode)) { 375 session.setFlushMode(FlushMode.AUTO); 376 sessionHolder.setPreviousFlushMode(flushMode); 377 } 378 } 379 } 380 return session; 381 } 382 } 383 return sessionHolder.getValidatedSession(); 386 } 387 catch (Throwable ex) { 388 throw new DataAccessResourceFailureException("Could not check JTA transaction", ex); 389 } 390 } 391 else { 392 return sessionHolder.getValidatedSession(); 395 } 396 } 397 398 406 private static void registerJtaSynchronization(Session session, SessionFactory sessionFactory, 407 SQLExceptionTranslator jdbcExceptionTranslator, SessionHolder sessionHolder) { 408 409 TransactionManager jtaTm = getJtaTransactionManager(sessionFactory, session); 413 if (jtaTm != null) { 414 try { 415 Transaction jtaTx = jtaTm.getTransaction(); 416 if (jtaTx != null) { 417 int jtaStatus = jtaTx.getStatus(); 418 if (jtaStatus == Status.STATUS_ACTIVE || jtaStatus == Status.STATUS_MARKED_ROLLBACK) { 419 logger.debug("Registering JTA transaction synchronization for new Hibernate Session"); 420 SessionHolder holderToUse = sessionHolder; 421 if (holderToUse == null) { 424 holderToUse = new SessionHolder(jtaTx, session); 425 } 426 else { 427 holderToUse.addSession(jtaTx, session); 428 } 429 jtaTx.registerSynchronization( 430 new SpringJtaSynchronizationAdapter( 431 new SpringSessionSynchronization(holderToUse, sessionFactory, jdbcExceptionTranslator, true), 432 jtaTm)); 433 holderToUse.setSynchronizedWithTransaction(true); 434 if (holderToUse != sessionHolder) { 435 TransactionSynchronizationManager.bindResource(sessionFactory, holderToUse); 436 } 437 } 438 } 439 } 440 catch (Throwable ex) { 441 throw new DataAccessResourceFailureException( 442 "Could not register synchronization with JTA TransactionManager", ex); 443 } 444 } 445 } 446 447 448 458 public static Session getNewSession(SessionFactory sessionFactory) { 459 return getNewSession(sessionFactory, null); 460 } 461 462 473 public static Session getNewSession(SessionFactory sessionFactory, Interceptor entityInterceptor) { 474 Assert.notNull(sessionFactory, "No SessionFactory specified"); 475 476 try { 477 SessionHolder sessionHolder = (SessionHolder) TransactionSynchronizationManager.getResource(sessionFactory); 478 if (sessionHolder != null && !sessionHolder.isEmpty()) { 479 if (entityInterceptor != null) { 480 return sessionFactory.openSession(sessionHolder.getAnySession().connection(), entityInterceptor); 481 } 482 else { 483 return sessionFactory.openSession(sessionHolder.getAnySession().connection()); 484 } 485 } 486 else { 487 if (entityInterceptor != null) { 488 return sessionFactory.openSession(entityInterceptor); 489 } 490 else { 491 return sessionFactory.openSession(); 492 } 493 } 494 } 495 catch (HibernateException ex) { 496 throw new DataAccessResourceFailureException("Could not open Hibernate Session", ex); 497 } 498 } 499 500 501 509 public static boolean isSessionTransactional(Session session, SessionFactory sessionFactory) { 510 if (sessionFactory == null) { 511 return false; 512 } 513 SessionHolder sessionHolder = 514 (SessionHolder) TransactionSynchronizationManager.getResource(sessionFactory); 515 return (sessionHolder != null && sessionHolder.containsSession(session)); 516 } 517 518 526 public static void applyTransactionTimeout(Query query, SessionFactory sessionFactory) { 527 Assert.notNull(query, "No Query object specified"); 528 if (sessionFactory != null) { 529 SessionHolder sessionHolder = 530 (SessionHolder) TransactionSynchronizationManager.getResource(sessionFactory); 531 if (sessionHolder != null && sessionHolder.hasTimeout()) { 532 query.setTimeout(sessionHolder.getTimeToLiveInSeconds()); 533 } 534 } 535 } 536 537 544 public static void applyTransactionTimeout(Criteria criteria, SessionFactory sessionFactory) { 545 Assert.notNull(criteria, "No Criteria object specified"); 546 SessionHolder sessionHolder = 547 (SessionHolder) TransactionSynchronizationManager.getResource(sessionFactory); 548 if (sessionHolder != null && sessionHolder.hasTimeout()) { 549 criteria.setTimeout(sessionHolder.getTimeToLiveInSeconds()); 550 } 551 } 552 553 564 public static DataAccessException convertHibernateAccessException(HibernateException ex) { 565 if (ex instanceof JDBCException) { 566 return new HibernateJdbcException((JDBCException) ex); 569 } 570 571 if (ex instanceof PersistentObjectException) { 572 return new InvalidDataAccessApiUsageException(ex.getMessage(), ex); 573 } 574 if (ex instanceof TransientObjectException) { 575 return new InvalidDataAccessApiUsageException(ex.getMessage(), ex); 576 } 577 if (ex instanceof ObjectDeletedException) { 578 return new InvalidDataAccessApiUsageException(ex.getMessage(), ex); 579 } 580 if (ex instanceof QueryException) { 581 return new HibernateQueryException((QueryException) ex); 582 } 583 if (ex instanceof UnresolvableObjectException) { 584 return new HibernateObjectRetrievalFailureException((UnresolvableObjectException) ex); 585 } 586 if (ex instanceof WrongClassException) { 587 return new HibernateObjectRetrievalFailureException((WrongClassException) ex); 588 } 589 if (ex instanceof NonUniqueResultException) { 590 return new IncorrectResultSizeDataAccessException(ex.getMessage(), 1); 591 } 592 if (ex instanceof StaleObjectStateException) { 593 return new HibernateOptimisticLockingFailureException((StaleObjectStateException) ex); 594 } 595 596 return new HibernateSystemException(ex); 598 } 599 600 601 607 public static boolean isDeferredCloseActive(SessionFactory sessionFactory) { 608 Assert.notNull(sessionFactory, "No SessionFactory specified"); 609 Map holderMap = (Map ) deferredCloseHolder.get(); 610 return (holderMap != null && holderMap.containsKey(sessionFactory)); 611 } 612 613 625 public static void initDeferredClose(SessionFactory sessionFactory) { 626 Assert.notNull(sessionFactory, "No SessionFactory specified"); 627 logger.debug("Initializing deferred close of Hibernate Sessions"); 628 Map holderMap = (Map ) deferredCloseHolder.get(); 629 if (holderMap == null) { 630 holderMap = new HashMap (); 631 deferredCloseHolder.set(holderMap); 632 } 633 holderMap.put(sessionFactory, CollectionFactory.createLinkedSetIfPossible(4)); 634 } 635 636 643 public static void processDeferredClose(SessionFactory sessionFactory) { 644 Assert.notNull(sessionFactory, "No SessionFactory specified"); 645 646 Map holderMap = (Map ) deferredCloseHolder.get(); 647 if (holderMap == null || !holderMap.containsKey(sessionFactory)) { 648 throw new IllegalStateException ("Deferred close not active for SessionFactory [" + sessionFactory + "]"); 649 } 650 651 logger.debug("Processing deferred close of Hibernate Sessions"); 652 Set sessions = (Set ) holderMap.remove(sessionFactory); 653 for (Iterator it = sessions.iterator(); it.hasNext();) { 654 closeSession((Session) it.next()); 655 } 656 657 if (holderMap.isEmpty()) { 658 deferredCloseHolder.set(null); 659 } 660 } 661 662 669 public static void releaseSession(Session session, SessionFactory sessionFactory) { 670 if (session == null) { 671 return; 672 } 673 if (!isSessionTransactional(session, sessionFactory)) { 675 closeSessionOrRegisterDeferredClose(session, sessionFactory); 676 } 677 } 678 679 687 static void closeSessionOrRegisterDeferredClose(Session session, SessionFactory sessionFactory) { 688 Map holderMap = (Map ) deferredCloseHolder.get(); 689 if (holderMap != null && sessionFactory != null && holderMap.containsKey(sessionFactory)) { 690 logger.debug("Registering Hibernate Session for deferred close"); 691 session.setFlushMode(FlushMode.NEVER); 693 Set sessions = (Set ) holderMap.get(sessionFactory); 694 sessions.add(session); 695 } 696 else { 697 closeSession(session); 698 } 699 } 700 701 707 public static void closeSession(Session session) { 708 if (session != null) { 709 logger.debug("Closing Hibernate Session"); 710 try { 711 session.close(); 712 } 713 catch (HibernateException ex) { 714 logger.debug("Could not close Hibernate Session", ex); 715 } 716 catch (Throwable ex) { 717 logger.debug("Unexpected exception on closing Hibernate Session", ex); 718 } 719 } 720 } 721 722 } 723 | Popular Tags |