/**
* Copyright (c) 2000-present Liferay, Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; either version 2.1 of the License, or (at your option)
* any later version.
*
* This library is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
* details.
*/
package com.liferay.portal.spring.hibernate;
import java.sql.Connection;
import java.util.Date;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.jdbc.Work;
import org.springframework.orm.hibernate3.HibernateTransactionManager;
import org.springframework.orm.hibernate3.SessionHolder;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionException;
import org.springframework.transaction.TransactionStatus;
/**
* @author Shuyang Zhou
*/
public class PortletTransactionManager implements PlatformTransactionManager {
public PortletTransactionManager(
HibernateTransactionManager portalHibernateTransactionManager,
SessionFactory portletSessionFactory) {
_portalHibernateTransactionManager = portalHibernateTransactionManager;
_portletSessionFactory = portletSessionFactory;
}
@Override
public void commit(TransactionStatus transactionStatus)
throws TransactionException {
if (!(transactionStatus instanceof TransactionStatusWrapper)) {
_portalHibernateTransactionManager.commit(transactionStatus);
return;
}
Throwable throwable = null;
try {
TransactionStatusWrapper transactionStatusWrapper =
(TransactionStatusWrapper)transactionStatus;
transactionStatus = transactionStatusWrapper._transactionStatus;
transactionStatusWrapper.reset();
}
catch (Throwable t) {
throwable = t;
throw t;
}
finally {
if (throwable == null) {
_portalHibernateTransactionManager.commit(transactionStatus);
}
else {
_portalHibernateTransactionManager.rollback(transactionStatus);
}
}
}
public SessionFactory getPortletSessionFactory() {
return _portletSessionFactory;
}
@Override
public TransactionStatus getTransaction(
TransactionDefinition transactionDefinition)
throws TransactionException {
TransactionStatus portalTransactionStatus =
_portalHibernateTransactionManager.getTransaction(
transactionDefinition);
SessionHolder portalSessionHolder =
(SessionHolder)SpringHibernateThreadLocalUtil.getResource(
_portalHibernateTransactionManager.getSessionFactory());
if (portalSessionHolder == null) {
return portalTransactionStatus;
}
Connection portalConnection = _getConnection(portalSessionHolder);
SessionHolder portletSessionHolder =
(SessionHolder)SpringHibernateThreadLocalUtil.getResource(
_portletSessionFactory);
if (portletSessionHolder != null) {
if (portalConnection == _getConnection(portletSessionHolder)) {
return portalTransactionStatus;
}
Session portalSession = portalSessionHolder.getSession();
portalSession.flush();
}
Session portletSession = _portletSessionFactory.openSession(
portalConnection);
SpringHibernateThreadLocalUtil.setResource(
_portletSessionFactory,
_createSessionHolder(portletSession, portalSessionHolder));
return new TransactionStatusWrapper(
portalTransactionStatus, _portletSessionFactory,
portletSessionHolder, portletSession);
}
@Override
public void rollback(TransactionStatus transactionStatus)
throws TransactionException {
if (!(transactionStatus instanceof TransactionStatusWrapper)) {
_portalHibernateTransactionManager.rollback(transactionStatus);
return;
}
try {
TransactionStatusWrapper transactionStatusWrapper =
(TransactionStatusWrapper)transactionStatus;
transactionStatus = transactionStatusWrapper._transactionStatus;
transactionStatusWrapper.reset();
}
finally {
_portalHibernateTransactionManager.rollback(transactionStatus);
}
}
private SessionHolder _createSessionHolder(
Session session, SessionHolder templateSessionHolder) {
SessionHolder sessionHolder = new SessionHolder(session);
sessionHolder.setPreviousFlushMode(
templateSessionHolder.getPreviousFlushMode());
if (templateSessionHolder.isRollbackOnly()) {
sessionHolder.setRollbackOnly();
}
sessionHolder.setSynchronizedWithTransaction(
templateSessionHolder.isSynchronizedWithTransaction());
if (templateSessionHolder.hasTimeout()) {
Date deadline = templateSessionHolder.getDeadline();
sessionHolder.setTimeoutInMillis(
deadline.getTime() - System.currentTimeMillis());
}
sessionHolder.setTransaction(templateSessionHolder.getTransaction());
if (templateSessionHolder.isVoid()) {
sessionHolder.unbound();
}
return sessionHolder;
}
private Connection _getConnection(SessionHolder sessionHolder) {
Session session = sessionHolder.getSession();
ConnectionReference connectionHolder = new ConnectionReference();
session.doWork(
new Work() {
@Override
public void execute(Connection connection) {
connectionHolder.setConnection(connection);
}
});
return connectionHolder.getConnection();
}
private final HibernateTransactionManager
_portalHibernateTransactionManager;
private final SessionFactory _portletSessionFactory;
private static class ConnectionReference {
public Connection getConnection() {
return _connection;
}
public void setConnection(Connection connection) {
_connection = connection;
}
private Connection _connection;
}
private static class TransactionStatusWrapper implements TransactionStatus {
@Override
public Object createSavepoint() throws TransactionException {
return _transactionStatus.createSavepoint();
}
@Override
public void flush() {
_transactionStatus.flush();
}
@Override
public boolean hasSavepoint() {
return _transactionStatus.hasSavepoint();
}
@Override
public boolean isCompleted() {
return _transactionStatus.isCompleted();
}
@Override
public boolean isNewTransaction() {
return _transactionStatus.isNewTransaction();
}
@Override
public boolean isRollbackOnly() {
return _transactionStatus.isRollbackOnly();
}
@Override
public void releaseSavepoint(Object savepoint)
throws TransactionException {
_transactionStatus.releaseSavepoint(savepoint);
}
public void reset() {
try {
_portletSession.flush();
}
finally {
SpringHibernateThreadLocalUtil.setResource(
_portletSessionFactory, _previousPortletSessionHolder);
}
}
@Override
public void rollbackToSavepoint(Object savepoint)
throws TransactionException {
_transactionStatus.rollbackToSavepoint(savepoint);
}
@Override
public void setRollbackOnly() {
_transactionStatus.setRollbackOnly();
}
private TransactionStatusWrapper(
TransactionStatus transactionStatus,
SessionFactory targetSessionFactory,
SessionHolder previousPortletSessionHolder,
Session portletSession) {
_transactionStatus = transactionStatus;
_portletSessionFactory = targetSessionFactory;
_previousPortletSessionHolder = previousPortletSessionHolder;
_portletSession = portletSession;
}
private final Session _portletSession;
private final SessionFactory _portletSessionFactory;
private final SessionHolder _previousPortletSessionHolder;
private final TransactionStatus _transactionStatus;
}
}