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}