001    /**
002     * Copyright (c) 2000-present 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 org.aopalliance.intercept.MethodInvocation;
018    
019    import org.springframework.transaction.PlatformTransactionManager;
020    import org.springframework.transaction.TransactionStatus;
021    import org.springframework.transaction.interceptor.TransactionAttribute;
022    import org.springframework.transaction.support.CallbackPreferringPlatformTransactionManager;
023    import org.springframework.transaction.support.TransactionCallback;
024    
025    /**
026     * @author Michael C. Han
027     * @author Shuyang Zhou
028     */
029    public class CallbackPreferringTransactionExecutor
030            extends BaseTransactionExecutor {
031    
032            @Override
033            public Object execute(
034                            PlatformTransactionManager platformTransactionManager,
035                            TransactionAttribute transactionAttribute,
036                            MethodInvocation methodInvocation)
037                    throws Throwable {
038    
039                    CallbackPreferringPlatformTransactionManager
040                            callbackPreferringPlatformTransactionManager =
041                                    (CallbackPreferringPlatformTransactionManager)
042                                            platformTransactionManager;
043    
044                    try {
045                            Object result =
046                                    callbackPreferringPlatformTransactionManager.execute(
047                                            transactionAttribute,
048                                            createTransactionCallback(
049                                                    transactionAttribute, methodInvocation));
050    
051                            if (result instanceof ThrowableHolder) {
052                                    ThrowableHolder throwableHolder = (ThrowableHolder)result;
053    
054                                    throw throwableHolder.getThrowable();
055                            }
056    
057                            return result;
058                    }
059                    catch (ThrowableHolderException the) {
060                            throw the.getCause();
061                    }
062            }
063    
064            protected TransactionCallback<Object> createTransactionCallback(
065                    TransactionAttribute transactionAttribute,
066                    MethodInvocation methodInvocation) {
067    
068                    return new CallbackPreferringTransactionCallback(
069                            transactionAttribute, methodInvocation);
070            }
071    
072            protected static class ThrowableHolder {
073    
074                    public ThrowableHolder(Throwable throwable) {
075                            _throwable = throwable;
076                    }
077    
078                    public Throwable getThrowable() {
079                            return _throwable;
080                    }
081    
082                    private final Throwable _throwable;
083    
084            }
085    
086            protected static class ThrowableHolderException extends RuntimeException {
087    
088                    public ThrowableHolderException(Throwable cause) {
089                            super(cause);
090                    }
091    
092            }
093    
094            private class CallbackPreferringTransactionCallback
095                    implements TransactionCallback<Object> {
096    
097                    @Override
098                    public Object doInTransaction(TransactionStatus transactionStatus) {
099                            fireTransactionCreatedEvent(
100                                    _transactionAttribute, transactionStatus);
101    
102                            boolean rollback = false;
103    
104                            try {
105                                    return _methodInvocation.proceed();
106                            }
107                            catch (Throwable throwable) {
108                                    if (_transactionAttribute.rollbackOn(throwable)) {
109                                            fireTransactionRollbackedEvent(
110                                                    _transactionAttribute, transactionStatus, throwable);
111    
112                                            if (transactionStatus.isNewTransaction()) {
113                                                    rollback = true;
114                                            }
115    
116                                            if (throwable instanceof RuntimeException) {
117                                                    throw (RuntimeException)throwable;
118                                            }
119                                            else {
120                                                    throw new ThrowableHolderException(throwable);
121                                            }
122                                    }
123                                    else {
124                                            return new ThrowableHolder(throwable);
125                                    }
126                            }
127                            finally {
128                                    if (!rollback) {
129                                            fireTransactionCommittedEvent(
130                                                    _transactionAttribute, transactionStatus);
131                                    }
132                            }
133                    }
134    
135                    private CallbackPreferringTransactionCallback(
136                            TransactionAttribute transactionAttribute,
137                            MethodInvocation methodInvocation) {
138    
139                            _transactionAttribute = transactionAttribute;
140                            _methodInvocation = methodInvocation;
141                    }
142    
143                    private final MethodInvocation _methodInvocation;
144                    private final TransactionAttribute _transactionAttribute;
145    
146            }
147    
148    }