001    /**
002     * Copyright (c) 2000-2013 Liferay, Inc. All rights reserved.
003     *
004     * The contents of this file are subject to the terms of the Liferay Enterprise
005     * Subscription License ("License"). You may not use this file except in
006     * compliance with the License. You can obtain a copy of the License by
007     * contacting Liferay, Inc. See the License for the specific language governing
008     * permissions and limitations under the License, including but not limited to
009     * distribution rights of the Software.
010     *
011     *
012     *
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.search.buffer.IndexerRequestBufferTransactionLifecycleListener;
021    import com.liferay.portal.spring.hibernate.LastSessionRecorderUtil;
022    
023    import org.aopalliance.intercept.MethodInvocation;
024    
025    import org.springframework.transaction.PlatformTransactionManager;
026    import org.springframework.transaction.TransactionStatus;
027    import org.springframework.transaction.interceptor.TransactionAttribute;
028    import org.springframework.transaction.support.CallbackPreferringPlatformTransactionManager;
029    import org.springframework.transaction.support.TransactionCallback;
030    
031    /**
032     * @author Michael C. Han
033     * @author Shuyang Zhou
034     */
035    public class CallbackPreferringTransactionExecutor
036            extends BaseTransactionExecutor {
037    
038            @Override
039            public Object execute(
040                            PlatformTransactionManager platformTransactionManager,
041                            TransactionAttribute transactionAttribute,
042                            MethodInvocation methodInvocation)
043                    throws Throwable {
044    
045                    CallbackPreferringPlatformTransactionManager
046                            callbackPreferringPlatformTransactionManager =
047                                    (CallbackPreferringPlatformTransactionManager)
048                                            platformTransactionManager;
049    
050                    try {
051                            Object result =
052                                    callbackPreferringPlatformTransactionManager.execute(
053                                            transactionAttribute,
054                                            createTransactionCallback(
055                                                    transactionAttribute, methodInvocation));
056    
057                            if (result instanceof ThrowableHolder) {
058                                    ThrowableHolder throwableHolder = (ThrowableHolder)result;
059    
060                                    throw throwableHolder.getThrowable();
061                            }
062    
063                            return result;
064                    }
065                    catch (ThrowableHolderException the) {
066                            throw the.getCause();
067                    }
068            }
069    
070            protected TransactionCallback<Object> createTransactionCallback(
071                    TransactionAttribute transactionAttribute,
072                    MethodInvocation methodInvocation) {
073    
074                    return new CallbackPreferringTransactionCallback(
075                            transactionAttribute, methodInvocation);
076            }
077    
078            protected static class ThrowableHolder {
079    
080                    public ThrowableHolder(Throwable throwable) {
081                            _throwable = throwable;
082                    }
083    
084                    public Throwable getThrowable() {
085                            return _throwable;
086                    }
087    
088                    private Throwable _throwable;
089    
090            }
091    
092            protected static class ThrowableHolderException extends RuntimeException {
093    
094                    public ThrowableHolderException(Throwable cause) {
095                            super(cause);
096                    }
097    
098            }
099    
100            private class CallbackPreferringTransactionCallback
101                    implements TransactionCallback<Object> {
102    
103                    private CallbackPreferringTransactionCallback(
104                            TransactionAttribute transactionAttribute,
105                            MethodInvocation methodInvocation) {
106    
107                            _transactionAttribute = transactionAttribute;
108                            _methodInvocation = methodInvocation;
109                    }
110    
111                    @Override
112                    public Object doInTransaction(TransactionStatus transactionStatus) {
113                            boolean newTransaction = transactionStatus.isNewTransaction();
114    
115                            if (newTransaction) {
116                                    TransactionalPortalCacheHelper.begin();
117    
118                                    TransactionCommitCallbackUtil.pushCallbackList();
119    
120                                    IndexerRequestBufferTransactionLifecycleListener.created();
121                            }
122    
123                            boolean rollback = false;
124    
125                            try {
126                                    if (newTransaction) {
127                                            LastSessionRecorderUtil.syncLastSessionState();
128                                    }
129    
130                                    return _methodInvocation.proceed();
131                            }
132                            catch (Throwable throwable) {
133                                    if (_transactionAttribute.rollbackOn(throwable)) {
134                                            if (newTransaction) {
135                                                    TransactionalPortalCacheHelper.rollback();
136    
137                                                    TransactionCommitCallbackUtil.popCallbackList();
138    
139                                                    IndexerRequestBufferTransactionLifecycleListener.
140                                                            rollbacked();
141    
142                                                    EntityCacheUtil.clearLocalCache();
143                                                    FinderCacheUtil.clearLocalCache();
144    
145                                                    rollback = true;
146                                            }
147    
148                                            if (throwable instanceof RuntimeException) {
149                                                    throw (RuntimeException)throwable;
150                                            }
151                                            else {
152                                                    throw new ThrowableHolderException(throwable);
153                                            }
154                                    }
155                                    else {
156                                            return new ThrowableHolder(throwable);
157                                    }
158                            }
159                            finally {
160                                    if (newTransaction && !rollback) {
161                                            TransactionalPortalCacheHelper.commit();
162    
163                                            invokeCallbacks();
164                                    }
165                            }
166                    }
167    
168                    private MethodInvocation _methodInvocation;
169                    private TransactionAttribute _transactionAttribute;
170    
171            }
172    
173    }