1 16 17 package org.springframework.orm.toplink; 18 19 import java.sql.Connection ; 20 import java.sql.SQLException ; 21 22 import javax.sql.DataSource ; 23 24 import oracle.toplink.exceptions.DatabaseException; 25 import oracle.toplink.exceptions.TopLinkException; 26 import oracle.toplink.internal.databaseaccess.Accessor; 27 import oracle.toplink.internal.databaseaccess.DatabaseAccessor; 28 import oracle.toplink.sessions.Session; 29 30 import org.springframework.beans.factory.InitializingBean; 31 import org.springframework.dao.DataAccessException; 32 import org.springframework.jdbc.datasource.ConnectionHolder; 33 import org.springframework.jdbc.datasource.JdbcTransactionObjectSupport; 34 import org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy; 35 import org.springframework.jdbc.support.SQLExceptionTranslator; 36 import org.springframework.transaction.CannotCreateTransactionException; 37 import org.springframework.transaction.TransactionDefinition; 38 import org.springframework.transaction.support.AbstractPlatformTransactionManager; 39 import org.springframework.transaction.support.DefaultTransactionStatus; 40 import org.springframework.transaction.support.ResourceTransactionManager; 41 import org.springframework.transaction.support.TransactionSynchronizationManager; 42 43 103 public class TopLinkTransactionManager extends AbstractPlatformTransactionManager 104 implements ResourceTransactionManager, InitializingBean { 105 106 private SessionFactory sessionFactory; 107 108 private DataSource dataSource; 109 110 private boolean lazyDatabaseTransaction = false; 111 112 private SQLExceptionTranslator jdbcExceptionTranslator; 113 114 115 120 public TopLinkTransactionManager() { 121 } 122 123 127 public TopLinkTransactionManager(SessionFactory sessionFactory) { 128 this.sessionFactory = sessionFactory; 129 afterPropertiesSet(); 130 } 131 132 143 public void setSessionFactory(SessionFactory sessionFactory) { 144 this.sessionFactory = sessionFactory; 145 } 146 147 150 public SessionFactory getSessionFactory() { 151 return this.sessionFactory; 152 } 153 154 177 public void setDataSource(DataSource dataSource) { 178 if (dataSource instanceof TransactionAwareDataSourceProxy) { 179 this.dataSource = ((TransactionAwareDataSourceProxy) dataSource).getTargetDataSource(); 183 } 184 else { 185 this.dataSource = dataSource; 186 } 187 } 188 189 192 public DataSource getDataSource() { 193 return this.dataSource; 194 } 195 196 209 public void setLazyDatabaseTransaction(boolean lazyDatabaseTransaction) { 210 this.lazyDatabaseTransaction = lazyDatabaseTransaction; 211 } 212 213 217 public boolean isLazyDatabaseTransaction() { 218 return this.lazyDatabaseTransaction; 219 } 220 221 232 public void setJdbcExceptionTranslator(SQLExceptionTranslator jdbcExceptionTranslator) { 233 this.jdbcExceptionTranslator = jdbcExceptionTranslator; 234 } 235 236 239 public SQLExceptionTranslator getJdbcExceptionTranslator() { 240 return this.jdbcExceptionTranslator; 241 } 242 243 public void afterPropertiesSet() { 244 if (getSessionFactory() == null) { 245 throw new IllegalArgumentException ("Property 'sessionFactory' is required"); 246 } 247 } 248 249 250 public Object getResourceFactory() { 251 return getSessionFactory(); 252 } 253 254 protected Object doGetTransaction() { 255 TopLinkTransactionObject txObject = new TopLinkTransactionObject(); 256 SessionHolder sessionHolder = (SessionHolder) 257 TransactionSynchronizationManager.getResource(this.sessionFactory); 258 txObject.setSessionHolder(sessionHolder); 259 return txObject; 260 } 261 262 protected boolean isExistingTransaction(Object transaction) { 263 TopLinkTransactionObject txObject = (TopLinkTransactionObject) transaction; 264 return (txObject.getSessionHolder() != null); 265 } 266 267 protected void doBegin(Object transaction, TransactionDefinition definition) { 268 Session session = null; 269 270 try { 271 if (!definition.isReadOnly()) { 272 logger.debug("Creating managed TopLink Session with active UnitOfWork for read-write transaction"); 273 session = getSessionFactory().createManagedClientSession(); 274 } 275 else { 276 logger.debug("Creating plain TopLink Session without active UnitOfWork for read-only transaction"); 277 session = getSessionFactory().createSession(); 278 } 279 280 if (logger.isDebugEnabled()) { 281 logger.debug("Opened new session [" + session + "] for TopLink transaction"); 282 } 283 284 TopLinkTransactionObject txObject = (TopLinkTransactionObject) transaction; 285 txObject.setSessionHolder(new SessionHolder(session)); 286 txObject.getSessionHolder().setSynchronizedWithTransaction(true); 287 288 switch (definition.getIsolationLevel()) { 290 case TransactionDefinition.ISOLATION_READ_UNCOMMITTED: 291 break; 293 case TransactionDefinition.ISOLATION_REPEATABLE_READ: 294 break; 296 case TransactionDefinition.ISOLATION_SERIALIZABLE: 297 break; 299 } 300 301 int timeout = determineTimeout(definition); 303 if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) { 304 txObject.getSessionHolder().setTimeoutInSeconds(timeout); 305 } 306 307 if (!definition.isReadOnly() && !isLazyDatabaseTransaction()) { 310 session.getActiveUnitOfWork().beginEarlyTransaction(); 311 } 312 313 if (getDataSource() != null) { 315 Connection con = getJdbcConnection(session); 316 if (con != null) { 317 ConnectionHolder conHolder = new ConnectionHolder(con); 318 if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) { 319 conHolder.setTimeoutInSeconds(timeout); 320 } 321 if (logger.isDebugEnabled()) { 322 logger.debug("Exposing TopLink transaction as JDBC transaction [" + con + "]"); 323 } 324 TransactionSynchronizationManager.bindResource(getDataSource(), conHolder); 325 txObject.setConnectionHolder(conHolder); 326 } 327 else { 328 if (logger.isDebugEnabled()) { 329 logger.debug("Not exposing TopLink transaction [" + session + 330 "] as JDBC transaction because no JDBC Connection could be retrieved from it"); 331 } 332 } 333 } 334 335 TransactionSynchronizationManager.bindResource(getSessionFactory(), txObject.getSessionHolder()); 337 } 338 339 catch (Exception ex) { 340 SessionFactoryUtils.releaseSession(session, getSessionFactory()); 341 throw new CannotCreateTransactionException("Could not open TopLink Session for transaction", ex); 342 } 343 } 344 345 354 protected Connection getJdbcConnection(Session session) { 355 if (!(session instanceof oracle.toplink.publicinterface.Session)) { 356 if (logger.isDebugEnabled()) { 357 logger.debug("TopLink Session [" + session + 358 "] does not derive from [oracle.toplink.publicinterface.Session]"); 359 } 360 return null; 361 } 362 Accessor accessor = ((oracle.toplink.publicinterface.Session) session).getAccessor(); 363 if (!(accessor instanceof DatabaseAccessor)) { 364 if (logger.isDebugEnabled()) { 365 logger.debug("TopLink Accessor [" + accessor + 366 "] does not derive from [oracle.toplink.internal.databaseaccess.DatabaseAccessor]"); 367 } 368 return null; 369 } 370 return ((DatabaseAccessor) accessor).getConnection(); 371 } 372 373 protected Object doSuspend(Object transaction) { 374 TopLinkTransactionObject txObject = (TopLinkTransactionObject) transaction; 375 txObject.setSessionHolder(null); 376 return TransactionSynchronizationManager.unbindResource(getSessionFactory()); 377 } 378 379 protected void doResume(Object transaction, Object suspendedResources) { 380 SessionHolder sessionHolder = (SessionHolder) suspendedResources; 381 if (TransactionSynchronizationManager.hasResource(getSessionFactory())) { 382 TransactionSynchronizationManager.unbindResource(getSessionFactory()); 385 } 386 TransactionSynchronizationManager.bindResource(getSessionFactory(), sessionHolder); 387 } 388 389 protected void doCommit(DefaultTransactionStatus status) { 390 TopLinkTransactionObject txObject = (TopLinkTransactionObject) status.getTransaction(); 391 if (status.isDebug()) { 392 logger.debug("Committing TopLink transaction on session [" + 393 txObject.getSessionHolder().getSession() + "]"); 394 } 395 try { 396 if (!status.isReadOnly()) { 397 txObject.getSessionHolder().getSession().getActiveUnitOfWork().commit(); 398 } 399 txObject.getSessionHolder().clear(); 400 } 401 catch (TopLinkException ex) { 402 throw convertTopLinkAccessException(ex); 403 } 404 } 405 406 protected void doRollback(DefaultTransactionStatus status) { 407 TopLinkTransactionObject txObject = (TopLinkTransactionObject) status.getTransaction(); 408 if (status.isDebug()) { 409 logger.debug("Not committing TopLink transaction on session [" + 410 txObject.getSessionHolder().getSession() + "]"); 411 } 412 txObject.getSessionHolder().clear(); 413 } 414 415 protected void doSetRollbackOnly(DefaultTransactionStatus status) { 416 TopLinkTransactionObject txObject = (TopLinkTransactionObject) status.getTransaction(); 417 if (status.isDebug()) { 418 logger.debug("Setting TopLink transaction on session [" + 419 txObject.getSessionHolder().getSession() + "] rollback-only"); 420 } 421 txObject.getSessionHolder().setRollbackOnly(); 422 } 423 424 protected void doCleanupAfterCompletion(Object transaction) { 425 TopLinkTransactionObject txObject = (TopLinkTransactionObject) transaction; 426 427 TransactionSynchronizationManager.unbindResource(getSessionFactory()); 429 430 if (txObject.hasConnectionHolder()) { 432 TransactionSynchronizationManager.unbindResource(getDataSource()); 433 } 434 435 Session session = txObject.getSessionHolder().getSession(); 436 if (logger.isDebugEnabled()) { 437 logger.debug("Releasing TopLink Session [" + session + "] after transaction"); 438 } 439 try { 440 session.release(); 441 } 442 catch (Throwable ex) { 443 logger.debug("Could not release TopLink Session after transaction", ex); 445 } 446 } 447 448 458 protected DataAccessException convertTopLinkAccessException(TopLinkException ex) { 459 if (getJdbcExceptionTranslator() != null && ex instanceof DatabaseException) { 460 Throwable internalEx = ex.getInternalException(); 461 if (internalEx instanceof SQLException ) { 463 return getJdbcExceptionTranslator().translate( 464 "TopLink commit: " + ex.getMessage(), null, (SQLException ) internalEx); 465 } 466 } 467 return SessionFactoryUtils.convertTopLinkAccessException(ex); 468 } 469 470 471 478 private static class TopLinkTransactionObject extends JdbcTransactionObjectSupport { 479 480 private SessionHolder sessionHolder; 481 482 public void setSessionHolder(SessionHolder sessionHolder) { 483 this.sessionHolder = sessionHolder; 484 } 485 486 public SessionHolder getSessionHolder() { 487 return this.sessionHolder; 488 } 489 490 public boolean isRollbackOnly() { 491 return getSessionHolder().isRollbackOnly(); 492 } 493 } 494 495 } 496 | Popular Tags |