001/**
002 * Copyright (c) 2015-2022, Michael Yang 杨福海 (fuhai999@gmail.com).
003 * <p>
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 * <p>
008 * http://www.apache.org/licenses/LICENSE-2.0
009 * <p>
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package io.jboot.support.seata.interceptor;
017
018import com.jfinal.aop.Invocation;
019import io.jboot.support.seata.JbootSeataManager;
020import io.jboot.support.seata.annotation.SeataGlobalTransactional;
021import io.seata.common.exception.ShouldNeverHappenException;
022import io.seata.common.util.StringUtils;
023import io.seata.tm.api.FailureHandler;
024import io.seata.tm.api.TransactionalExecutor;
025import io.seata.tm.api.transaction.NoRollbackRule;
026import io.seata.tm.api.transaction.RollbackRule;
027import io.seata.tm.api.transaction.TransactionInfo;
028
029import java.lang.reflect.Method;
030import java.util.Arrays;
031import java.util.LinkedHashSet;
032import java.util.Set;
033import java.util.stream.Collectors;
034
035public class SeataGlobalTransactionHandler {
036
037        public static Object handleGlobalTransaction(final Invocation invocation,
038                        final SeataGlobalTransactional globalTrxAnno) throws Throwable {
039                try {
040                        return JbootSeataManager.me().getTransactionalTemplate().execute(new TransactionalExecutor() {
041
042                                @Override
043                                public Object execute() throws Throwable {
044                                        invocation.invoke();
045                                        return invocation.getReturnValue();
046                                }
047
048                                public String name() {
049                                        String name = globalTrxAnno.name();
050                                        if (!StringUtils.isNullOrEmpty(name)) {
051                                                return name;
052                                        }
053                                        return formatMethod(invocation.getMethod());
054                                }
055
056                                @Override
057                                public TransactionInfo getTransactionInfo() {
058                                        TransactionInfo transactionInfo = new TransactionInfo();
059                                        transactionInfo.setTimeOut(globalTrxAnno.timeoutMills());
060                                        transactionInfo.setName(name());
061                                        Set<RollbackRule> rollbackRules = new LinkedHashSet<>();
062                                        for (Class<?> rbRule : globalTrxAnno.rollbackFor()) {
063                                                rollbackRules.add(new RollbackRule(rbRule));
064                                        }
065                                        for (String rbRule : globalTrxAnno.rollbackForClassName()) {
066                                                rollbackRules.add(new RollbackRule(rbRule));
067                                        }
068                                        for (Class<?> rbRule : globalTrxAnno.noRollbackFor()) {
069                                                rollbackRules.add(new NoRollbackRule(rbRule));
070                                        }
071                                        for (String rbRule : globalTrxAnno.noRollbackForClassName()) {
072                                                rollbackRules.add(new NoRollbackRule(rbRule));
073                                        }
074                                        transactionInfo.setRollbackRules(rollbackRules);
075                                        return transactionInfo;
076                                }
077
078                        });
079
080                } catch (TransactionalExecutor.ExecutionException e) {
081                        FailureHandler failureHandler = JbootSeataManager.me().getFailureHandler();
082                        TransactionalExecutor.Code code = e.getCode();
083                        switch (code) {
084                        case RollbackDone:
085                                throw e.getOriginalException();
086                        case BeginFailure:
087                                failureHandler.onBeginFailure(e.getTransaction(), e.getCause());
088                                throw e.getCause();
089                        case CommitFailure:
090                                failureHandler.onCommitFailure(e.getTransaction(), e.getCause());
091                                throw e.getCause();
092                        case RollbackFailure:
093                                failureHandler.onRollbackFailure(e.getTransaction(), e.getCause());
094                                throw e.getCause(); 
095                        case RollbackRetrying:
096                                failureHandler.onRollbackRetrying(e.getTransaction(), e.getOriginalException());
097                                throw e.getCause();
098                        default:
099                                throw new ShouldNeverHappenException("Unknown TransactionalExecutor.Code: " + code);
100
101                        }
102                }
103        }
104
105        private static String formatMethod(Method method) {
106                String paramTypes = Arrays.stream(method.getParameterTypes())
107                                .map(Class::getName)
108                                .collect(Collectors.joining(", ", "(", ")"));
109                return method.getName() + paramTypes;
110        }
111}