001    /**
002     * Copyright (c) 2000-2013 Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portal.spring.transaction;
016    
017    import com.liferay.portal.cache.transactional.TransactionalPortalCacheHelper;
018    import com.liferay.portal.kernel.dao.orm.EntityCacheUtil;
019    import com.liferay.portal.kernel.dao.orm.FinderCacheUtil;
020    import com.liferay.portal.spring.hibernate.LastSessionRecorderUtil;
021    
022    import org.aopalliance.intercept.MethodInvocation;
023    
024    import org.springframework.transaction.PlatformTransactionManager;
025    import org.springframework.transaction.TransactionStatus;
026    import org.springframework.transaction.interceptor.TransactionAttribute;
027    import org.springframework.transaction.support.CallbackPreferringPlatformTransactionManager;
028    import org.springframework.transaction.support.TransactionCallback;
029    
030    /**
031     * @author Michael C. Han
032     * @author Shuyang Zhou
033     */
034    public class CallbackPreferringTransactionExecutor
035            extends BaseTransactionExecutor {
036    
037            @Override
038            public Object execute(
039                            PlatformTransactionManager platformTransactionManager,
040                            TransactionAttribute transactionAttribute,
041                            MethodInvocation methodInvocation)
042                    throws Throwable {
043    
044                    CallbackPreferringPlatformTransactionManager
045                            callbackPreferringPlatformTransactionManager =
046                                    (CallbackPreferringPlatformTransactionManager)
047                                            platformTransactionManager;
048    
049                    try {
050                            Object result =
051                                    callbackPreferringPlatformTransactionManager.execute(
052                                            transactionAttribute,
053                                            createTransactionCallback(
054                                                    transactionAttribute, methodInvocation));
055    
056                            if (result instanceof ThrowableHolder) {
057                                    ThrowableHolder throwableHolder = (ThrowableHolder)result;
058    
059                                    throw throwableHolder.getThrowable();
060                            }
061    
062                            return result;
063                    }
064                    catch (ThrowableHolderException the) {
065                            throw the.getCause();
066                    }
067            }
068    
069            protected TransactionCallback<Object> createTransactionCallback(
070                    TransactionAttribute transactionAttribute,
071                    MethodInvocation methodInvocation) {
072    
073                    return new CallbackPreferringTransactionCallback(
074                            transactionAttribute, methodInvocation);
075            }
076    
077            protected static class ThrowableHolder {
078    
079                    public ThrowableHolder(Throwable throwable) {
080                            _throwable = throwable;
081                    }
082    
083                    public Throwable getThrowable() {
084                            return _throwable;
085                    }
086    
087                    private Throwable _throwable;
088    
089            }
090    
091            protected static class ThrowableHolderException extends RuntimeException {
092    
093                    public ThrowableHolderException(Throwable cause) {
094                            super(cause);
095                    }
096    
097            }
098    
099            private class CallbackPreferringTransactionCallback
100                    implements TransactionCallback<Object> {
101    
102                    private CallbackPreferringTransactionCallback(
103                            TransactionAttribute transactionAttribute,
104                            MethodInvocation methodInvocation) {
105    
106                            _transactionAttribute = transactionAttribute;
107                            _methodInvocation = methodInvocation;
108                    }
109    
110                    @Override
111                    public Object doInTransaction(TransactionStatus transactionStatus) {
112                            boolean newTransaction = transactionStatus.isNewTransaction();
113    
114                            if (newTransaction) {
115                                    TransactionalPortalCacheHelper.begin();
116    
117                                    TransactionCommitCallbackUtil.pushCallbackList();
118                            }
119    
120                            boolean rollback = false;
121    
122                            try {
123                                    if (newTransaction) {
124                                            LastSessionRecorderUtil.syncLastSessionState();
125                                    }
126    
127                                    return _methodInvocation.proceed();
128                            }
129                            catch (Throwable throwable) {
130                                    if (_transactionAttribute.rollbackOn(throwable)) {
131                                            if (newTransaction) {
132                                                    TransactionalPortalCacheHelper.rollback();
133    
134                                                    TransactionCommitCallbackUtil.popCallbackList();
135    
136                                                    EntityCacheUtil.clearLocalCache();
137                                                    FinderCacheUtil.clearLocalCache();
138    
139                                                    rollback = true;
140                                            }
141    
142                                            if (throwable instanceof RuntimeException) {
143                                                    throw (RuntimeException)throwable;
144                                            }
145                                            else {
146                                                    throw new ThrowableHolderException(throwable);
147                                            }
148                                    }
149                                    else {
150                                            return new ThrowableHolder(throwable);
151                                    }
152                            }
153                            finally {
154                                    if (newTransaction && !rollback) {
155                                            TransactionalPortalCacheHelper.commit();
156    
157                                            invokeCallbacks();
158                                    }
159                            }
160                    }
161    
162                    private MethodInvocation _methodInvocation;
163                    private TransactionAttribute _transactionAttribute;
164    
165            }
166    
167    }