From 3b76acd797a0efa0db453e70353e4a68d3ee623b Mon Sep 17 00:00:00 2001 From: leezongjie Date: Mon, 5 Feb 2024 13:55:22 +0800 Subject: [PATCH 1/7] =?UTF-8?q?=E6=94=AF=E6=8C=81tcc=E5=B5=8C=E5=A5=97?= =?UTF-8?q?=E4=BA=8B=E5=8A=A1=E6=B3=A8=E8=A7=A3=E5=88=87=E9=9D=A2=E8=A7=A3?= =?UTF-8?q?=E6=9E=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../NestInterceptorHandlerWrapper.java | 58 ++++ .../AbstractProxyInvocationHandler.java | 10 + ...GlobalTransactionalInterceptorHandler.java | 9 + .../handler/ProxyInvocationHandler.java | 7 + .../parser/DefaultInterfaceParser.java | 44 ++- .../GlobalTransactionalInterceptorParser.java | 2 - .../TccActionInterceptorHandler.java | 7 +- .../parser/TccActionInterceptorParser.java | 2 - .../seata/rm/tcc/BranchSessionMock.java | 69 ++++ .../apache/seata/rm/tcc/NestTccAction.java | 56 +++ .../seata/rm/tcc/NestTccActionImpl.java | 62 ++++ .../org/apache/seata/rm/tcc/TccAction.java | 19 +- .../apache/seata/rm/tcc/TccActionImpl.java | 22 +- .../TccActionInterceptorParserTest.java | 322 ++++++++++++++++++ 14 files changed, 651 insertions(+), 38 deletions(-) create mode 100644 integration-tx-api/src/main/java/org/apache/seata/integration/tx/api/interceptor/NestInterceptorHandlerWrapper.java create mode 100644 tcc/src/test/java/org/apache/seata/rm/tcc/BranchSessionMock.java create mode 100644 tcc/src/test/java/org/apache/seata/rm/tcc/NestTccAction.java create mode 100644 tcc/src/test/java/org/apache/seata/rm/tcc/NestTccActionImpl.java diff --git a/integration-tx-api/src/main/java/org/apache/seata/integration/tx/api/interceptor/NestInterceptorHandlerWrapper.java b/integration-tx-api/src/main/java/org/apache/seata/integration/tx/api/interceptor/NestInterceptorHandlerWrapper.java new file mode 100644 index 00000000000..0abb2fc4bd2 --- /dev/null +++ b/integration-tx-api/src/main/java/org/apache/seata/integration/tx/api/interceptor/NestInterceptorHandlerWrapper.java @@ -0,0 +1,58 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.seata.integration.tx.api.interceptor; + +import java.lang.reflect.Method; +import org.apache.seata.integration.tx.api.interceptor.handler.ProxyInvocationHandler; + + +public class NestInterceptorHandlerWrapper implements InvocationWrapper { + + private ProxyInvocationHandler proxyInvocationHandler; + + private InvocationWrapper invocation; + + public NestInterceptorHandlerWrapper(ProxyInvocationHandler proxyInvocationHandler, InvocationWrapper invocation) { + this.proxyInvocationHandler = proxyInvocationHandler; + this.invocation = invocation; + } + + @Override + public Method getMethod() { + return invocation.getMethod(); + } + + @Override + public Object getProxy() { + return invocation.getProxy(); + } + + @Override + public Object getTarget() { + return invocation.getTarget(); + } + + @Override + public Object[] getArguments() { + return invocation.getArguments(); + } + + @Override + public Object proceed() throws Throwable { + return proxyInvocationHandler.invoke(invocation); + } +} diff --git a/integration-tx-api/src/main/java/org/apache/seata/integration/tx/api/interceptor/handler/AbstractProxyInvocationHandler.java b/integration-tx-api/src/main/java/org/apache/seata/integration/tx/api/interceptor/handler/AbstractProxyInvocationHandler.java index f6c3a533859..76429b7a505 100644 --- a/integration-tx-api/src/main/java/org/apache/seata/integration/tx/api/interceptor/handler/AbstractProxyInvocationHandler.java +++ b/integration-tx-api/src/main/java/org/apache/seata/integration/tx/api/interceptor/handler/AbstractProxyInvocationHandler.java @@ -18,6 +18,7 @@ import org.apache.seata.common.util.CollectionUtils; import org.apache.seata.integration.tx.api.interceptor.InvocationWrapper; +import org.apache.seata.integration.tx.api.interceptor.NestInterceptorHandlerWrapper; public abstract class AbstractProxyInvocationHandler implements ProxyInvocationHandler { @@ -26,11 +27,16 @@ public abstract class AbstractProxyInvocationHandler implements ProxyInvocationH protected int order = Integer.MAX_VALUE; + protected ProxyInvocationHandler nextInvocationHandlerChain; + @Override public Object invoke(InvocationWrapper invocation) throws Throwable { if (CollectionUtils.isNotEmpty(getMethodsToProxy()) && !getMethodsToProxy().contains(invocation.getMethod().getName())) { return invocation.proceed(); } + if (nextInvocationHandlerChain != null) { + invocation = new NestInterceptorHandlerWrapper(nextInvocationHandlerChain, invocation); + } return doInvoke(invocation); } @@ -44,4 +50,8 @@ public int getOrder() { return this.order; } + @Override + public void setNextProxyInvocationHandler(ProxyInvocationHandler next) { + this.nextInvocationHandlerChain = next; + } } diff --git a/integration-tx-api/src/main/java/org/apache/seata/integration/tx/api/interceptor/handler/GlobalTransactionalInterceptorHandler.java b/integration-tx-api/src/main/java/org/apache/seata/integration/tx/api/interceptor/handler/GlobalTransactionalInterceptorHandler.java index 7f9750a6466..367790f28c3 100644 --- a/integration-tx-api/src/main/java/org/apache/seata/integration/tx/api/interceptor/handler/GlobalTransactionalInterceptorHandler.java +++ b/integration-tx-api/src/main/java/org/apache/seata/integration/tx/api/interceptor/handler/GlobalTransactionalInterceptorHandler.java @@ -381,4 +381,13 @@ public SeataInterceptorPosition getPosition() { return SeataInterceptorPosition.BeforeTransaction; } + @Override + public int order() { + return 1; + } + + @Override + public String type() { + return "GlobalTransactional"; + } } diff --git a/integration-tx-api/src/main/java/org/apache/seata/integration/tx/api/interceptor/handler/ProxyInvocationHandler.java b/integration-tx-api/src/main/java/org/apache/seata/integration/tx/api/interceptor/handler/ProxyInvocationHandler.java index 8238d8526ba..1dbe24a61da 100644 --- a/integration-tx-api/src/main/java/org/apache/seata/integration/tx/api/interceptor/handler/ProxyInvocationHandler.java +++ b/integration-tx-api/src/main/java/org/apache/seata/integration/tx/api/interceptor/handler/ProxyInvocationHandler.java @@ -31,4 +31,11 @@ public interface ProxyInvocationHandler extends SeataInterceptor { SeataInterceptorPosition getPosition(); + String type(); + + default int order() { + return 0; + } + + void setNextProxyInvocationHandler(ProxyInvocationHandler next); } diff --git a/integration-tx-api/src/main/java/org/apache/seata/integration/tx/api/interceptor/parser/DefaultInterfaceParser.java b/integration-tx-api/src/main/java/org/apache/seata/integration/tx/api/interceptor/parser/DefaultInterfaceParser.java index 2827f9dc7dc..c3ba7b8b178 100644 --- a/integration-tx-api/src/main/java/org/apache/seata/integration/tx/api/interceptor/parser/DefaultInterfaceParser.java +++ b/integration-tx-api/src/main/java/org/apache/seata/integration/tx/api/interceptor/parser/DefaultInterfaceParser.java @@ -16,13 +16,16 @@ */ package org.apache.seata.integration.tx.api.interceptor.parser; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashSet; +import java.util.List; +import java.util.Set; import org.apache.seata.common.loader.EnhancedServiceLoader; import org.apache.seata.common.util.CollectionUtils; import org.apache.seata.integration.tx.api.interceptor.handler.ProxyInvocationHandler; -import java.util.ArrayList; -import java.util.List; - /** * @author leezongjie */ @@ -53,15 +56,46 @@ protected void initInterfaceParser() { } } + /** + * 创建拦截器链,支持天添加多个拦截器,按顺序组织,拦截顺序同解析顺序,{@link InterfaceParser}的加载解析顺序可以通过@LoadLevel控制。 + * 不允许加载多个同类型的拦截器,如tcc和saga的二阶段注解不能同时存在,通过{@link ProxyInvocationHandler#type()}指定类型。 + * + * @param target + * @param objectName + * @return + * @throws Exception + */ @Override public ProxyInvocationHandler parserInterfaceToProxy(Object target, String objectName) throws Exception { + + List invocationHandlerList = new ArrayList<>(); + Set invocationHandlerRepeatCheck = new HashSet<>(); + for (InterfaceParser interfaceParser : ALL_INTERFACE_PARSERS) { ProxyInvocationHandler proxyInvocationHandler = interfaceParser.parserInterfaceToProxy(target, objectName); if (proxyInvocationHandler != null) { - return proxyInvocationHandler; + if (!invocationHandlerRepeatCheck.add(proxyInvocationHandler.type())) { + throw new RuntimeException("there is already an annotation of type " + proxyInvocationHandler.type() + " for class: " + target.getClass().getName()); + } + invocationHandlerList.add(proxyInvocationHandler); } } - return null; + + Collections.sort(invocationHandlerList, Comparator.comparingInt(ProxyInvocationHandler::order)); + + ProxyInvocationHandler result = null; + ProxyInvocationHandler last = null; + for (ProxyInvocationHandler proxyInvocationHandler : invocationHandlerList) { + if (result == null) { + result = proxyInvocationHandler; + } + if (last != null) { + last.setNextProxyInvocationHandler(proxyInvocationHandler); + } + last = proxyInvocationHandler; + } + + return result; } @Override diff --git a/integration-tx-api/src/main/java/org/apache/seata/integration/tx/api/interceptor/parser/GlobalTransactionalInterceptorParser.java b/integration-tx-api/src/main/java/org/apache/seata/integration/tx/api/interceptor/parser/GlobalTransactionalInterceptorParser.java index 3026615db9e..ca9e3a6f408 100644 --- a/integration-tx-api/src/main/java/org/apache/seata/integration/tx/api/interceptor/parser/GlobalTransactionalInterceptorParser.java +++ b/integration-tx-api/src/main/java/org/apache/seata/integration/tx/api/interceptor/parser/GlobalTransactionalInterceptorParser.java @@ -19,7 +19,6 @@ import java.lang.reflect.Method; import java.util.HashSet; import java.util.Set; - import org.apache.seata.common.ConfigurationKeys; import org.apache.seata.common.util.CollectionUtils; import org.apache.seata.common.util.ReflectionUtil; @@ -31,7 +30,6 @@ import org.apache.seata.spring.annotation.GlobalTransactional; import org.apache.seata.tm.api.FailureHandlerHolder; - public class GlobalTransactionalInterceptorParser implements InterfaceParser { private final Set methodsToProxy = new HashSet<>(); diff --git a/tcc/src/main/java/org/apache/seata/rm/tcc/interceptor/TccActionInterceptorHandler.java b/tcc/src/main/java/org/apache/seata/rm/tcc/interceptor/TccActionInterceptorHandler.java index ffee8848e4f..a321bf1226b 100644 --- a/tcc/src/main/java/org/apache/seata/rm/tcc/interceptor/TccActionInterceptorHandler.java +++ b/tcc/src/main/java/org/apache/seata/rm/tcc/interceptor/TccActionInterceptorHandler.java @@ -21,7 +21,6 @@ import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; - import org.apache.seata.common.Constants; import org.apache.seata.common.DefaultValues; import org.apache.seata.common.holder.ObjectHolder; @@ -37,11 +36,9 @@ import org.apache.seata.integration.tx.api.interceptor.handler.AbstractProxyInvocationHandler; import org.apache.seata.rm.tcc.api.TwoPhaseBusinessAction; import org.slf4j.MDC; - import static org.apache.seata.common.ConfigurationKeys.TCC_ACTION_INTERCEPTOR_ORDER; import static org.apache.seata.common.Constants.BEAN_NAME_SPRING_FENCE_CONFIG; - public class TccActionInterceptorHandler extends AbstractProxyInvocationHandler { private static final int ORDER_NUM = ConfigurationFactory.getInstance().getInt(TCC_ACTION_INTERCEPTOR_ORDER, @@ -167,4 +164,8 @@ public SeataInterceptorPosition getPosition() { return SeataInterceptorPosition.Any; } + @Override + public String type() { + return "twoPhaseAnnotation"; + } } diff --git a/tcc/src/main/java/org/apache/seata/rm/tcc/interceptor/parser/TccActionInterceptorParser.java b/tcc/src/main/java/org/apache/seata/rm/tcc/interceptor/parser/TccActionInterceptorParser.java index ffe88d6ad19..740690b19db 100644 --- a/tcc/src/main/java/org/apache/seata/rm/tcc/interceptor/parser/TccActionInterceptorParser.java +++ b/tcc/src/main/java/org/apache/seata/rm/tcc/interceptor/parser/TccActionInterceptorParser.java @@ -21,7 +21,6 @@ import java.util.Collections; import java.util.HashSet; import java.util.Set; - import org.apache.seata.common.util.ReflectionUtil; import org.apache.seata.integration.tx.api.interceptor.handler.ProxyInvocationHandler; import org.apache.seata.integration.tx.api.interceptor.parser.DefaultResourceRegisterParser; @@ -34,7 +33,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; - public class TccActionInterceptorParser implements InterfaceParser { private static final Logger LOGGER = LoggerFactory.getLogger(TccActionInterceptorParser.class); diff --git a/tcc/src/test/java/org/apache/seata/rm/tcc/BranchSessionMock.java b/tcc/src/test/java/org/apache/seata/rm/tcc/BranchSessionMock.java new file mode 100644 index 00000000000..a8c0261fbe8 --- /dev/null +++ b/tcc/src/test/java/org/apache/seata/rm/tcc/BranchSessionMock.java @@ -0,0 +1,69 @@ +package org.apache.seata.rm.tcc; + +import org.apache.seata.core.model.BranchType; + +public class BranchSessionMock { + + private String xid; + + private long branchId; + + private String resourceGroupId; + + private String resourceId; + + + private BranchType branchType; + + + private String applicationData; + + + public String getXid() { + return xid; + } + + public void setXid(String xid) { + this.xid = xid; + } + + public long getBranchId() { + return branchId; + } + + public void setBranchId(long branchId) { + this.branchId = branchId; + } + + public String getResourceGroupId() { + return resourceGroupId; + } + + public void setResourceGroupId(String resourceGroupId) { + this.resourceGroupId = resourceGroupId; + } + + public String getResourceId() { + return resourceId; + } + + public void setResourceId(String resourceId) { + this.resourceId = resourceId; + } + + public BranchType getBranchType() { + return branchType; + } + + public void setBranchType(BranchType branchType) { + this.branchType = branchType; + } + + public String getApplicationData() { + return applicationData; + } + + public void setApplicationData(String applicationData) { + this.applicationData = applicationData; + } +} diff --git a/tcc/src/test/java/org/apache/seata/rm/tcc/NestTccAction.java b/tcc/src/test/java/org/apache/seata/rm/tcc/NestTccAction.java new file mode 100644 index 00000000000..19fe35a8f86 --- /dev/null +++ b/tcc/src/test/java/org/apache/seata/rm/tcc/NestTccAction.java @@ -0,0 +1,56 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.seata.rm.tcc; + +import org.apache.seata.rm.tcc.api.BusinessActionContext; +import org.apache.seata.rm.tcc.api.LocalTCC; +import org.apache.seata.rm.tcc.api.TwoPhaseBusinessAction; + +/** + * The interface Tcc action. + */ +@LocalTCC +public interface NestTccAction { + + /** + * Prepare boolean. + * + * @param actionContext the action context + * @return the boolean + */ + @TwoPhaseBusinessAction(name = "tccNestActionForTest") + boolean prepare(BusinessActionContext actionContext, int count); + + @TwoPhaseBusinessAction(name = "tccNestActionForTest") + boolean prepareNestRequiredNew(BusinessActionContext actionContext, int count); + + /** + * Commit boolean. + * + * @param actionContext the action context + * @return the boolean + */ + boolean commit(BusinessActionContext actionContext); + + /** + * Rollback boolean. + * + * @param actionContext the action context + * @return the boolean + */ + boolean rollback(BusinessActionContext actionContext); +} diff --git a/tcc/src/test/java/org/apache/seata/rm/tcc/NestTccActionImpl.java b/tcc/src/test/java/org/apache/seata/rm/tcc/NestTccActionImpl.java new file mode 100644 index 00000000000..4b34d7534e7 --- /dev/null +++ b/tcc/src/test/java/org/apache/seata/rm/tcc/NestTccActionImpl.java @@ -0,0 +1,62 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.seata.rm.tcc; + + +import org.apache.seata.rm.tcc.api.BusinessActionContext; +import org.apache.seata.spring.annotation.GlobalTransactional; +import org.apache.seata.tm.api.transaction.Propagation; + + +public class NestTccActionImpl implements NestTccAction { + + private TccAction tccAction; + private boolean isCommit; + + @Override + @GlobalTransactional() + public boolean prepare(BusinessActionContext actionContext, int count) { + tccAction.prepare(actionContext); + return count > 1; + } + + @GlobalTransactional(propagation = Propagation.REQUIRES_NEW) + @Override + public boolean prepareNestRequiredNew(BusinessActionContext actionContext, int count) { + tccAction.prepare(actionContext); + return count > 1; + } + + @Override + public boolean commit(BusinessActionContext actionContext) { + isCommit = true; + return true; + } + + @Override + public boolean rollback(BusinessActionContext actionContext) { + return true; + } + + public void setTccAction(TccAction tccAction) { + this.tccAction = tccAction; + } + + public boolean isCommit() { + return isCommit; + } +} diff --git a/tcc/src/test/java/org/apache/seata/rm/tcc/TccAction.java b/tcc/src/test/java/org/apache/seata/rm/tcc/TccAction.java index 8f3c29011f5..9f0e6f53322 100644 --- a/tcc/src/test/java/org/apache/seata/rm/tcc/TccAction.java +++ b/tcc/src/test/java/org/apache/seata/rm/tcc/TccAction.java @@ -17,15 +17,11 @@ package org.apache.seata.rm.tcc; import org.apache.seata.rm.tcc.api.BusinessActionContext; -import org.apache.seata.rm.tcc.api.BusinessActionContextParameter; import org.apache.seata.rm.tcc.api.LocalTCC; import org.apache.seata.rm.tcc.api.TwoPhaseBusinessAction; -import java.util.List; - /** * The interface Tcc action. - * */ @LocalTCC public interface TccAction { @@ -34,16 +30,10 @@ public interface TccAction { * Prepare boolean. * * @param actionContext the action context - * @param a the a - * @param b the b - * @param tccParam the tcc param * @return the boolean */ - @TwoPhaseBusinessAction(name = "tccActionForTest", commitMethod = "commit", rollbackMethod = "rollback", commitArgsClasses = {BusinessActionContext.class, TccParam.class, Integer.class}, rollbackArgsClasses = {BusinessActionContext.class, TccParam.class}) - boolean prepare(BusinessActionContext actionContext, - @BusinessActionContextParameter("a") int a, - @BusinessActionContextParameter(paramName = "b", index = 0) List b, - @BusinessActionContextParameter(isParamInProperty = true) TccParam tccParam); + @TwoPhaseBusinessAction(name = "tccActionForTest") + boolean prepare(BusinessActionContext actionContext); /** * Commit boolean. @@ -51,8 +41,7 @@ boolean prepare(BusinessActionContext actionContext, * @param actionContext the action context * @return the boolean */ - boolean commit(BusinessActionContext actionContext, - @BusinessActionContextParameter("tccParam") TccParam param, @Param("a") Integer a); + boolean commit(BusinessActionContext actionContext); /** * Rollback boolean. @@ -60,5 +49,5 @@ boolean commit(BusinessActionContext actionContext, * @param actionContext the action context * @return the boolean */ - boolean rollback(BusinessActionContext actionContext, @BusinessActionContextParameter("tccParam") TccParam param); + boolean rollback(BusinessActionContext actionContext); } diff --git a/tcc/src/test/java/org/apache/seata/rm/tcc/TccActionImpl.java b/tcc/src/test/java/org/apache/seata/rm/tcc/TccActionImpl.java index d49ad3f6d70..c0012a86354 100644 --- a/tcc/src/test/java/org/apache/seata/rm/tcc/TccActionImpl.java +++ b/tcc/src/test/java/org/apache/seata/rm/tcc/TccActionImpl.java @@ -17,9 +17,6 @@ package org.apache.seata.rm.tcc; import org.apache.seata.rm.tcc.api.BusinessActionContext; -import org.apache.seata.rm.tcc.api.BusinessActionContextParameter; - -import java.util.List; /** * The type Tcc action. @@ -27,23 +24,26 @@ */ public class TccActionImpl implements TccAction { + private boolean isCommit; + + @Override - public boolean prepare(BusinessActionContext actionContext, - int a, - List b, - TccParam TccParam ) { + public boolean prepare(BusinessActionContext actionContext) { return true; } @Override - public boolean commit(BusinessActionContext actionContext, - @BusinessActionContextParameter("tccParam") TccParam param, @Param("a") Integer a) { + public boolean commit(BusinessActionContext actionContext) { + isCommit = true; return true; } @Override - public boolean rollback(BusinessActionContext actionContext, - @BusinessActionContextParameter("tccParam") TccParam param) { + public boolean rollback(BusinessActionContext actionContext) { return true; } + + public boolean isCommit() { + return isCommit; + } } diff --git a/tcc/src/test/java/org/apache/seata/rm/tcc/interceptor/parser/TccActionInterceptorParserTest.java b/tcc/src/test/java/org/apache/seata/rm/tcc/interceptor/parser/TccActionInterceptorParserTest.java index 79fda999831..cf712e8d963 100644 --- a/tcc/src/test/java/org/apache/seata/rm/tcc/interceptor/parser/TccActionInterceptorParserTest.java +++ b/tcc/src/test/java/org/apache/seata/rm/tcc/interceptor/parser/TccActionInterceptorParserTest.java @@ -16,14 +16,46 @@ */ package org.apache.seata.rm.tcc.interceptor.parser; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; +import org.apache.seata.core.exception.TransactionException; +import org.apache.seata.core.model.BranchType; +import org.apache.seata.core.model.GlobalStatus; +import org.apache.seata.core.model.ResourceManager; +import org.apache.seata.core.model.TransactionManager; import org.apache.seata.integration.tx.api.interceptor.handler.ProxyInvocationHandler; +import org.apache.seata.integration.tx.api.interceptor.parser.DefaultInterfaceParser; +import org.apache.seata.integration.tx.api.util.ProxyUtil; +import org.apache.seata.rm.DefaultResourceManager; +import org.apache.seata.rm.tcc.BranchSessionMock; +import org.apache.seata.rm.tcc.NestTccAction; +import org.apache.seata.rm.tcc.NestTccActionImpl; import org.apache.seata.rm.tcc.NormalTccActionImpl; +import org.apache.seata.rm.tcc.TCCResourceManager; +import org.apache.seata.rm.tcc.TccAction; +import org.apache.seata.rm.tcc.TccActionImpl; +import org.apache.seata.tm.TransactionManagerHolder; +import org.apache.seata.tm.api.GlobalTransaction; +import org.apache.seata.tm.api.GlobalTransactionContext; import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; class TccActionInterceptorParserTest { + @BeforeAll + public static void init() throws IOException { + System.setProperty("config.type", "file"); + System.setProperty("config.file.name", "file.conf"); + System.setProperty("txServiceGroup", "default_tx_group"); + System.setProperty("service.vgroupMapping.default_tx_group", "default"); + } + @Test void parserInterfaceToProxy() { @@ -38,4 +70,294 @@ void parserInterfaceToProxy() { Assertions.assertNotNull(proxyInvocationHandler); } + + + @Test + public void testNestTcc_should_commit() throws Exception { + //given + DefaultResourceManager.get(); + DefaultResourceManager.mockResourceManager(BranchType.TCC, resourceManager); + + TransactionManagerHolder.set(transactionManager); + + TccActionImpl tccAction = new TccActionImpl(); + TccAction tccActionProxy = ProxyUtil.createProxy(tccAction); + Assertions.assertNotNull(tccActionProxy); + + NestTccActionImpl nestTccAction = new NestTccActionImpl(); + nestTccAction.setTccAction(tccActionProxy); + + //when + ProxyInvocationHandler proxyInvocationHandler = DefaultInterfaceParser.get().parserInterfaceToProxy(nestTccAction, nestTccAction.getClass().getName()); + + //then + Assertions.assertNotNull(proxyInvocationHandler); + + + //when + NestTccAction nestTccActionProxy = ProxyUtil.createProxy(nestTccAction); + //then + Assertions.assertNotNull(nestTccActionProxy); + + + // transaction commit test + GlobalTransaction tx = GlobalTransactionContext.getCurrentOrCreate(); + + try { + tx.begin(60000, "testBiz"); + + boolean result = nestTccActionProxy.prepare(null, 2); + + Assertions.assertTrue(result); + + if (result) { + tx.commit(); + } else { + tx.rollback(); + } + } catch (Exception exx) { + tx.rollback(); + throw exx; + } + + Assertions.assertTrue(nestTccAction.isCommit()); + Assertions.assertTrue(tccAction.isCommit()); + + } + + + @Test + public void testNestTcc_should_rollback() throws Exception { + //given + DefaultResourceManager.get(); + DefaultResourceManager.mockResourceManager(BranchType.TCC, resourceManager); + + TransactionManagerHolder.set(transactionManager); + + TccActionImpl tccAction = new TccActionImpl(); + TccAction tccActionProxy = ProxyUtil.createProxy(tccAction); + Assertions.assertNotNull(tccActionProxy); + + NestTccActionImpl nestTccAction = new NestTccActionImpl(); + nestTccAction.setTccAction(tccActionProxy); + + //when + ProxyInvocationHandler proxyInvocationHandler = DefaultInterfaceParser.get().parserInterfaceToProxy(nestTccAction, nestTccAction.getClass().getName()); + + //then + Assertions.assertNotNull(proxyInvocationHandler); + + + //when + NestTccAction nestTccActionProxy = ProxyUtil.createProxy(nestTccAction); + //then + Assertions.assertNotNull(nestTccActionProxy); + + + // transaction commit test + GlobalTransaction tx = GlobalTransactionContext.getCurrentOrCreate(); + + try { + tx.begin(60000, "testBiz"); + + boolean result = nestTccActionProxy.prepare(null, 1); + + Assertions.assertFalse(result); + + if (result) { + tx.commit(); + } else { + tx.rollback(); + } + } catch (Exception exx) { + tx.rollback(); + throw exx; + } + + Assertions.assertFalse(nestTccAction.isCommit()); + Assertions.assertFalse(tccAction.isCommit()); + + } + + + @Test + public void testNestTcc_required_new_should_rollback_commit() throws Exception { + //given + DefaultResourceManager.get(); + DefaultResourceManager.mockResourceManager(BranchType.TCC, resourceManager); + + TransactionManagerHolder.set(transactionManager); + + TccActionImpl tccAction = new TccActionImpl(); + TccAction tccActionProxy = ProxyUtil.createProxy(tccAction); + Assertions.assertNotNull(tccActionProxy); + + NestTccActionImpl nestTccAction = new NestTccActionImpl(); + nestTccAction.setTccAction(tccActionProxy); + + //when + ProxyInvocationHandler proxyInvocationHandler = DefaultInterfaceParser.get().parserInterfaceToProxy(nestTccAction, nestTccAction.getClass().getName()); + + //then + Assertions.assertNotNull(proxyInvocationHandler); + + //when + NestTccAction nestTccActionProxy = ProxyUtil.createProxy(nestTccAction); + //then + Assertions.assertNotNull(nestTccActionProxy); + + + // transaction commit test + GlobalTransaction tx = GlobalTransactionContext.getCurrentOrCreate(); + + try { + tx.begin(60000, "testBiz"); + + boolean result = nestTccActionProxy.prepareNestRequiredNew(null, 1); + + Assertions.assertFalse(result); + + if (result) { + tx.commit(); + } else { + tx.rollback(); + } + } catch (Exception exx) { + tx.rollback(); + throw exx; + } + + Assertions.assertFalse(nestTccAction.isCommit()); + Assertions.assertTrue(tccAction.isCommit()); + + } + + + + @Test + public void testNestTcc_required_new_should_both_commit() throws Exception { + //given + DefaultResourceManager.get(); + DefaultResourceManager.mockResourceManager(BranchType.TCC, resourceManager); + + TransactionManagerHolder.set(transactionManager); + + TccActionImpl tccAction = new TccActionImpl(); + TccAction tccActionProxy = ProxyUtil.createProxy(tccAction); + Assertions.assertNotNull(tccActionProxy); + + NestTccActionImpl nestTccAction = new NestTccActionImpl(); + nestTccAction.setTccAction(tccActionProxy); + + //when + ProxyInvocationHandler proxyInvocationHandler = DefaultInterfaceParser.get().parserInterfaceToProxy(nestTccAction, nestTccAction.getClass().getName()); + + //then + Assertions.assertNotNull(proxyInvocationHandler); + + //when + NestTccAction nestTccActionProxy = ProxyUtil.createProxy(nestTccAction); + //then + Assertions.assertNotNull(nestTccActionProxy); + + + // transaction commit test + GlobalTransaction tx = GlobalTransactionContext.getCurrentOrCreate(); + + try { + tx.begin(60000, "testBiz"); + + boolean result = nestTccActionProxy.prepareNestRequiredNew(null, 2); + + Assertions.assertTrue(result); + + if (result) { + tx.commit(); + } else { + tx.rollback(); + } + } catch (Exception exx) { + tx.rollback(); + throw exx; + } + + Assertions.assertTrue(nestTccAction.isCommit()); + Assertions.assertTrue(tccAction.isCommit()); + + } + + + + private static Map> applicationDataMap = new ConcurrentHashMap<>(); + + + private static TransactionManager transactionManager = new TransactionManager() { + @Override + public String begin(String applicationId, String transactionServiceGroup, String name, int timeout) throws TransactionException { + return UUID.randomUUID().toString(); + } + + @Override + public GlobalStatus commit(String xid) throws TransactionException { + commitAll(xid); + return GlobalStatus.Committed; + } + + @Override + public GlobalStatus rollback(String xid) throws TransactionException { + + rollbackAll(xid); + + return GlobalStatus.Rollbacked; + } + + @Override + public GlobalStatus getStatus(String xid) throws TransactionException { + return GlobalStatus.Begin; + } + + @Override + public GlobalStatus globalReport(String xid, GlobalStatus globalStatus) throws TransactionException { + return globalStatus; + } + }; + + + private static ResourceManager resourceManager = new TCCResourceManager() { + + @Override + public Long branchRegister(BranchType branchType, String resourceId, String clientId, String xid, String applicationData, String lockKeys) throws TransactionException { + + long branchId = System.currentTimeMillis(); + + List branches = applicationDataMap.computeIfAbsent(xid, s -> new ArrayList<>()); + BranchSessionMock branchSessionMock = new BranchSessionMock(); + branchSessionMock.setXid(xid); + branchSessionMock.setBranchType(branchType); + branchSessionMock.setResourceId(resourceId); + branchSessionMock.setApplicationData(applicationData); + branchSessionMock.setBranchId(branchId); + + branches.add(branchSessionMock); + + return branchId; + } + }; + + public static void commitAll(String xid) throws TransactionException { + + List branches = applicationDataMap.computeIfAbsent(xid, s -> new ArrayList<>()); + for (BranchSessionMock branch : branches) { + resourceManager.branchCommit(branch.getBranchType(), branch.getXid(), branch.getBranchId(), branch.getResourceId(), branch.getApplicationData()); + } + } + + public static void rollbackAll(String xid) throws TransactionException { + + List branches = applicationDataMap.computeIfAbsent(xid, s -> new ArrayList<>()); + for (BranchSessionMock branch : branches) { + resourceManager.branchRollback(branch.getBranchType(), branch.getXid(), branch.getBranchId(), branch.getResourceId(), branch.getApplicationData()); + } + } + } From db0004c6599ee3fe0e5eaf011cd08098bc163d12 Mon Sep 17 00:00:00 2001 From: leezongjie Date: Mon, 5 Feb 2024 14:08:39 +0800 Subject: [PATCH 2/7] add License --- .../apache/seata/rm/tcc/BranchSessionMock.java | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/tcc/src/test/java/org/apache/seata/rm/tcc/BranchSessionMock.java b/tcc/src/test/java/org/apache/seata/rm/tcc/BranchSessionMock.java index a8c0261fbe8..7f60557c73b 100644 --- a/tcc/src/test/java/org/apache/seata/rm/tcc/BranchSessionMock.java +++ b/tcc/src/test/java/org/apache/seata/rm/tcc/BranchSessionMock.java @@ -1,3 +1,19 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.apache.seata.rm.tcc; import org.apache.seata.core.model.BranchType; From e5aaf91f952b9b60e50c8eda03712c8dca07ac07 Mon Sep 17 00:00:00 2001 From: leezongjie Date: Mon, 5 Feb 2024 14:10:37 +0800 Subject: [PATCH 3/7] add changelog --- changes/en-us/2.x.md | 2 +- changes/zh-cn/2.x.md | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/changes/en-us/2.x.md b/changes/en-us/2.x.md index 5c741aaae51..3279438d21a 100644 --- a/changes/en-us/2.x.md +++ b/changes/en-us/2.x.md @@ -23,7 +23,7 @@ Add changes here for all PR submitted to the 2.x branch. - [[#6256](https://github.com/apache/incubator-seata/pull/6256)] fix raft-discovery cannot read registry configuration for seata-all sdk - [[#6232](https://github.com/apache/incubator-seata/pull/6232)] convert to utf8mb4 if mysql column is json type - [[#6278](https://github.com/apache/incubator-seata/pull/6278)] fix ProtocolV1SerializerTest failed - +- [[#6331](https://github.com/apache/incubator-seata/pull/6331)] fixed the problem that TCC nested transactions cannot add TwoPhaseBusinessAction and GlobalTransactional annotations at the same time ### optimize: - [[#6031](https://github.com/apache/incubator-seata/pull/6031)] add a check for the existence of the undolog table diff --git a/changes/zh-cn/2.x.md b/changes/zh-cn/2.x.md index d915a242547..9671ea79126 100644 --- a/changes/zh-cn/2.x.md +++ b/changes/zh-cn/2.x.md @@ -23,6 +23,8 @@ - [[#6256](https://github.com/apache/incubator-seata/pull/6256)] 修复在seata-all sdk下,raft-discovery模块不能读取registry.conf的配置的问题 - [[#6232](https://github.com/apache/incubator-seata/pull/6232)] 修复在mysql的json类型下出现Cannot create a JSON value from a string with CHARACTER SET 'binary'问题 - [[#6278](https://github.com/apache/incubator-seata/pull/6278)] 修复 ProtocolV1SerializerTest 失败问题 +- [[#6331](https://github.com/apache/incubator-seata/pull/6331)] 修复TCC嵌套事务不能同时添加TwoPhaseBusinessAction和GlobalTransactional两个注解的问题 + ### optimize: - [[#6031](https://github.com/apache/incubator-seata/pull/6031)] 添加undo_log表的存在性校验 From 17b6acbceef821ae1c4f0874e0bb6b6c43e25b13 Mon Sep 17 00:00:00 2001 From: leezongjie Date: Thu, 22 Feb 2024 20:12:42 +0800 Subject: [PATCH 4/7] fix, support nest tcc --- .../handler/GlobalTransactionalInterceptorHandler.java | 6 +----- .../tx/api/interceptor/parser/DefaultInterfaceParser.java | 5 +++-- .../rm/tcc/interceptor/TccActionInterceptorHandler.java | 5 +++++ 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/integration-tx-api/src/main/java/org/apache/seata/integration/tx/api/interceptor/handler/GlobalTransactionalInterceptorHandler.java b/integration-tx-api/src/main/java/org/apache/seata/integration/tx/api/interceptor/handler/GlobalTransactionalInterceptorHandler.java index 367790f28c3..74fcae6b683 100644 --- a/integration-tx-api/src/main/java/org/apache/seata/integration/tx/api/interceptor/handler/GlobalTransactionalInterceptorHandler.java +++ b/integration-tx-api/src/main/java/org/apache/seata/integration/tx/api/interceptor/handler/GlobalTransactionalInterceptorHandler.java @@ -16,7 +16,6 @@ */ package org.apache.seata.integration.tx.api.interceptor.handler; -import org.apache.seata.tm.api.GlobalTransaction; import java.lang.annotation.Annotation; import java.lang.reflect.Method; import java.util.LinkedHashSet; @@ -51,6 +50,7 @@ import org.apache.seata.tm.TransactionManagerHolder; import org.apache.seata.tm.api.FailureHandler; import org.apache.seata.tm.api.FailureHandlerHolder; +import org.apache.seata.tm.api.GlobalTransaction; import org.apache.seata.tm.api.TransactionalExecutor; import org.apache.seata.tm.api.TransactionalTemplate; import org.apache.seata.tm.api.transaction.NoRollbackRule; @@ -381,10 +381,6 @@ public SeataInterceptorPosition getPosition() { return SeataInterceptorPosition.BeforeTransaction; } - @Override - public int order() { - return 1; - } @Override public String type() { diff --git a/integration-tx-api/src/main/java/org/apache/seata/integration/tx/api/interceptor/parser/DefaultInterfaceParser.java b/integration-tx-api/src/main/java/org/apache/seata/integration/tx/api/interceptor/parser/DefaultInterfaceParser.java index c3ba7b8b178..f4cdefbb68e 100644 --- a/integration-tx-api/src/main/java/org/apache/seata/integration/tx/api/interceptor/parser/DefaultInterfaceParser.java +++ b/integration-tx-api/src/main/java/org/apache/seata/integration/tx/api/interceptor/parser/DefaultInterfaceParser.java @@ -22,6 +22,7 @@ import java.util.HashSet; import java.util.List; import java.util.Set; + import org.apache.seata.common.loader.EnhancedServiceLoader; import org.apache.seata.common.util.CollectionUtils; import org.apache.seata.integration.tx.api.interceptor.handler.ProxyInvocationHandler; @@ -57,7 +58,8 @@ protected void initInterfaceParser() { } /** - * 创建拦截器链,支持天添加多个拦截器,按顺序组织,拦截顺序同解析顺序,{@link InterfaceParser}的加载解析顺序可以通过@LoadLevel控制。 + * 创建拦截器链,支持添加多个拦截器。 + * 可以通过{@link ProxyInvocationHandler#order()}指定切面的进入顺序。 * 不允许加载多个同类型的拦截器,如tcc和saga的二阶段注解不能同时存在,通过{@link ProxyInvocationHandler#type()}指定类型。 * * @param target @@ -67,7 +69,6 @@ protected void initInterfaceParser() { */ @Override public ProxyInvocationHandler parserInterfaceToProxy(Object target, String objectName) throws Exception { - List invocationHandlerList = new ArrayList<>(); Set invocationHandlerRepeatCheck = new HashSet<>(); diff --git a/tcc/src/main/java/org/apache/seata/rm/tcc/interceptor/TccActionInterceptorHandler.java b/tcc/src/main/java/org/apache/seata/rm/tcc/interceptor/TccActionInterceptorHandler.java index a321bf1226b..506f137d4d2 100644 --- a/tcc/src/main/java/org/apache/seata/rm/tcc/interceptor/TccActionInterceptorHandler.java +++ b/tcc/src/main/java/org/apache/seata/rm/tcc/interceptor/TccActionInterceptorHandler.java @@ -164,6 +164,11 @@ public SeataInterceptorPosition getPosition() { return SeataInterceptorPosition.Any; } + @Override + public int order() { + return 1; + } + @Override public String type() { return "twoPhaseAnnotation"; From 4f2612b1e475db5d460cd9114c13d954035e328c Mon Sep 17 00:00:00 2001 From: leezongjie Date: Wed, 28 Feb 2024 11:27:56 +0800 Subject: [PATCH 5/7] fix chinese comment annotation --- .../tx/api/interceptor/parser/DefaultInterfaceParser.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/integration-tx-api/src/main/java/org/apache/seata/integration/tx/api/interceptor/parser/DefaultInterfaceParser.java b/integration-tx-api/src/main/java/org/apache/seata/integration/tx/api/interceptor/parser/DefaultInterfaceParser.java index f4cdefbb68e..5e09e322cf6 100644 --- a/integration-tx-api/src/main/java/org/apache/seata/integration/tx/api/interceptor/parser/DefaultInterfaceParser.java +++ b/integration-tx-api/src/main/java/org/apache/seata/integration/tx/api/interceptor/parser/DefaultInterfaceParser.java @@ -58,9 +58,9 @@ protected void initInterfaceParser() { } /** - * 创建拦截器链,支持添加多个拦截器。 - * 可以通过{@link ProxyInvocationHandler#order()}指定切面的进入顺序。 - * 不允许加载多个同类型的拦截器,如tcc和saga的二阶段注解不能同时存在,通过{@link ProxyInvocationHandler#type()}指定类型。 + * Create an interceptor chain that supports adding multiple interceptors.Create an interceptor chain that supports adding multiple interceptors. + * The entry order of the facets can be specified through {@link ProxyInvocationHandler # order()}. + * It is not allowed to load multiple interceptors of the same type, such as two-stage annotations for TCC and Saga that cannot exist simultaneously. The type can be specified through {@link ProxyInvocationHandler # type()}.It is not allowed to load multiple interceptors of the same type, such as two-stage annotations for TCC and Saga that cannot exist simultaneously. The type can be specified through {@link ProxyInvocationHandler # type()}. * * @param target * @param objectName From ea2b18a6217e9ef7290baa4f7fe4c714a9fcb595 Mon Sep 17 00:00:00 2001 From: leezongjie Date: Wed, 28 Feb 2024 14:54:19 +0800 Subject: [PATCH 6/7] fix test --- .../test/java/org/apache/seata/rm/tcc/TccAction.java | 12 ++++++++++++ .../java/org/apache/seata/rm/tcc/TccActionImpl.java | 12 ++++++++++++ .../parser/TccActionInterceptorParserTest.java | 8 +++++++- .../parser/TccRegisterResourceParserTest.java | 10 +++++----- 4 files changed, 36 insertions(+), 6 deletions(-) diff --git a/tcc/src/test/java/org/apache/seata/rm/tcc/TccAction.java b/tcc/src/test/java/org/apache/seata/rm/tcc/TccAction.java index 9f0e6f53322..ec9ea949cf9 100644 --- a/tcc/src/test/java/org/apache/seata/rm/tcc/TccAction.java +++ b/tcc/src/test/java/org/apache/seata/rm/tcc/TccAction.java @@ -17,6 +17,7 @@ package org.apache.seata.rm.tcc; import org.apache.seata.rm.tcc.api.BusinessActionContext; +import org.apache.seata.rm.tcc.api.BusinessActionContextParameter; import org.apache.seata.rm.tcc.api.LocalTCC; import org.apache.seata.rm.tcc.api.TwoPhaseBusinessAction; @@ -43,6 +44,14 @@ public interface TccAction { */ boolean commit(BusinessActionContext actionContext); + /** + * Commit boolean. + * + * @param actionContext the action context + * @return the boolean + */ + boolean commitWithArg(BusinessActionContext actionContext, @BusinessActionContextParameter("tccParam") TccParam param, @Param("a") Integer a); + /** * Rollback boolean. * @@ -50,4 +59,7 @@ public interface TccAction { * @return the boolean */ boolean rollback(BusinessActionContext actionContext); + + boolean rollbackWithArg(BusinessActionContext actionContext, @BusinessActionContextParameter("tccParam") TccParam param); + } diff --git a/tcc/src/test/java/org/apache/seata/rm/tcc/TccActionImpl.java b/tcc/src/test/java/org/apache/seata/rm/tcc/TccActionImpl.java index c0012a86354..d63e67a5561 100644 --- a/tcc/src/test/java/org/apache/seata/rm/tcc/TccActionImpl.java +++ b/tcc/src/test/java/org/apache/seata/rm/tcc/TccActionImpl.java @@ -38,11 +38,23 @@ public boolean commit(BusinessActionContext actionContext) { return true; } + @Override + public boolean commitWithArg(BusinessActionContext actionContext, TccParam param, Integer a) { + return false; + } + + @Override public boolean rollback(BusinessActionContext actionContext) { return true; } + @Override + public boolean rollbackWithArg(BusinessActionContext actionContext, TccParam param) { + return false; + } + + public boolean isCommit() { return isCommit; } diff --git a/tcc/src/test/java/org/apache/seata/rm/tcc/interceptor/parser/TccActionInterceptorParserTest.java b/tcc/src/test/java/org/apache/seata/rm/tcc/interceptor/parser/TccActionInterceptorParserTest.java index cf712e8d963..0f193535537 100644 --- a/tcc/src/test/java/org/apache/seata/rm/tcc/interceptor/parser/TccActionInterceptorParserTest.java +++ b/tcc/src/test/java/org/apache/seata/rm/tcc/interceptor/parser/TccActionInterceptorParserTest.java @@ -22,6 +22,8 @@ import java.util.Map; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; + +import org.apache.seata.core.context.RootContext; import org.apache.seata.core.exception.TransactionException; import org.apache.seata.core.model.BranchType; import org.apache.seata.core.model.GlobalStatus; @@ -75,6 +77,7 @@ void parserInterfaceToProxy() { @Test public void testNestTcc_should_commit() throws Exception { //given + RootContext.unbind(); DefaultResourceManager.get(); DefaultResourceManager.mockResourceManager(BranchType.TCC, resourceManager); @@ -129,6 +132,7 @@ public void testNestTcc_should_commit() throws Exception { @Test public void testNestTcc_should_rollback() throws Exception { //given + RootContext.unbind(); DefaultResourceManager.get(); DefaultResourceManager.mockResourceManager(BranchType.TCC, resourceManager); @@ -183,6 +187,7 @@ public void testNestTcc_should_rollback() throws Exception { @Test public void testNestTcc_required_new_should_rollback_commit() throws Exception { //given + RootContext.unbind(); DefaultResourceManager.get(); DefaultResourceManager.mockResourceManager(BranchType.TCC, resourceManager); @@ -227,7 +232,7 @@ public void testNestTcc_required_new_should_rollback_commit() throws Exception { throw exx; } - Assertions.assertFalse(nestTccAction.isCommit()); + Assertions.assertTrue(nestTccAction.isCommit()); Assertions.assertTrue(tccAction.isCommit()); } @@ -237,6 +242,7 @@ public void testNestTcc_required_new_should_rollback_commit() throws Exception { @Test public void testNestTcc_required_new_should_both_commit() throws Exception { //given + RootContext.unbind(); DefaultResourceManager.get(); DefaultResourceManager.mockResourceManager(BranchType.TCC, resourceManager); diff --git a/tcc/src/test/java/org/apache/seata/rm/tcc/resource/parser/TccRegisterResourceParserTest.java b/tcc/src/test/java/org/apache/seata/rm/tcc/resource/parser/TccRegisterResourceParserTest.java index a11e12f8b1f..b7f651afae9 100644 --- a/tcc/src/test/java/org/apache/seata/rm/tcc/resource/parser/TccRegisterResourceParserTest.java +++ b/tcc/src/test/java/org/apache/seata/rm/tcc/resource/parser/TccRegisterResourceParserTest.java @@ -16,13 +16,14 @@ */ package org.apache.seata.rm.tcc.resource.parser; +import java.lang.reflect.Method; + +import org.apache.seata.rm.tcc.TccAction; import org.apache.seata.rm.tcc.TccParam; import org.apache.seata.rm.tcc.api.BusinessActionContext; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; -import java.lang.reflect.Method; - class TccRegisterResourceParserTest { @@ -30,14 +31,13 @@ class TccRegisterResourceParserTest { @Test public void testGetTwoPhaseArgs() throws Exception { - Class tccActionImpl = Class.forName("org.apache.seata.rm.tcc.TccActionImpl"); Class[] argsCommitClasses = new Class[]{BusinessActionContext.class, TccParam.class, Integer.class}; - Method commitMethod = tccActionImpl.getMethod("commit", argsCommitClasses); + Method commitMethod = TccAction.class.getMethod("commitWithArg", argsCommitClasses); Assertions.assertThrows(IllegalArgumentException.class, () -> { tccRegisterResourceParser.getTwoPhaseArgs(commitMethod, argsCommitClasses); }); Class[] argsRollbackClasses = new Class[]{BusinessActionContext.class, TccParam.class}; - Method rollbackMethod = tccActionImpl.getMethod("rollback", argsRollbackClasses); + Method rollbackMethod = TccAction.class.getMethod("rollbackWithArg", argsRollbackClasses); String[] keys = tccRegisterResourceParser.getTwoPhaseArgs(rollbackMethod, argsRollbackClasses); Assertions.assertNull(keys[0]); Assertions.assertEquals("tccParam", keys[1]); From eefd4bba2d8c5ab7300ddf111eb46876240e5d77 Mon Sep 17 00:00:00 2001 From: leezongjie Date: Wed, 28 Feb 2024 15:59:58 +0800 Subject: [PATCH 7/7] Resolve review comments --- .../interceptor/InvocationHandlerType.java | 26 +++++++++++++++++++ ...GlobalTransactionalInterceptorHandler.java | 3 ++- .../parser/DefaultInterfaceParser.java | 8 +++--- .../TccActionInterceptorHandler.java | 3 ++- 4 files changed, 34 insertions(+), 6 deletions(-) create mode 100644 integration-tx-api/src/main/java/org/apache/seata/integration/tx/api/interceptor/InvocationHandlerType.java diff --git a/integration-tx-api/src/main/java/org/apache/seata/integration/tx/api/interceptor/InvocationHandlerType.java b/integration-tx-api/src/main/java/org/apache/seata/integration/tx/api/interceptor/InvocationHandlerType.java new file mode 100644 index 00000000000..7d909105a09 --- /dev/null +++ b/integration-tx-api/src/main/java/org/apache/seata/integration/tx/api/interceptor/InvocationHandlerType.java @@ -0,0 +1,26 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.seata.integration.tx.api.interceptor; + +/** + * The InvocationHandlerType enum + */ +public enum InvocationHandlerType { + + GlobalTransactional, TwoPhaseAnnotation + +} diff --git a/integration-tx-api/src/main/java/org/apache/seata/integration/tx/api/interceptor/handler/GlobalTransactionalInterceptorHandler.java b/integration-tx-api/src/main/java/org/apache/seata/integration/tx/api/interceptor/handler/GlobalTransactionalInterceptorHandler.java index 387e8794959..ac942636dff 100644 --- a/integration-tx-api/src/main/java/org/apache/seata/integration/tx/api/interceptor/handler/GlobalTransactionalInterceptorHandler.java +++ b/integration-tx-api/src/main/java/org/apache/seata/integration/tx/api/interceptor/handler/GlobalTransactionalInterceptorHandler.java @@ -41,6 +41,7 @@ import org.apache.seata.core.model.GlobalLockConfig; import org.apache.seata.integration.tx.api.annotation.AspectTransactional; import org.apache.seata.integration.tx.api.event.DegradeCheckEvent; +import org.apache.seata.integration.tx.api.interceptor.InvocationHandlerType; import org.apache.seata.integration.tx.api.interceptor.InvocationWrapper; import org.apache.seata.integration.tx.api.interceptor.SeataInterceptorPosition; import org.apache.seata.integration.tx.api.util.ClassUtils; @@ -413,6 +414,6 @@ public SeataInterceptorPosition getPosition() { @Override public String type() { - return "GlobalTransactional"; + return InvocationHandlerType.GlobalTransactional.name(); } } diff --git a/integration-tx-api/src/main/java/org/apache/seata/integration/tx/api/interceptor/parser/DefaultInterfaceParser.java b/integration-tx-api/src/main/java/org/apache/seata/integration/tx/api/interceptor/parser/DefaultInterfaceParser.java index 5e09e322cf6..c93574e8189 100644 --- a/integration-tx-api/src/main/java/org/apache/seata/integration/tx/api/interceptor/parser/DefaultInterfaceParser.java +++ b/integration-tx-api/src/main/java/org/apache/seata/integration/tx/api/interceptor/parser/DefaultInterfaceParser.java @@ -84,11 +84,11 @@ public ProxyInvocationHandler parserInterfaceToProxy(Object target, String objec Collections.sort(invocationHandlerList, Comparator.comparingInt(ProxyInvocationHandler::order)); - ProxyInvocationHandler result = null; + ProxyInvocationHandler first = null; ProxyInvocationHandler last = null; for (ProxyInvocationHandler proxyInvocationHandler : invocationHandlerList) { - if (result == null) { - result = proxyInvocationHandler; + if (first == null) { + first = proxyInvocationHandler; } if (last != null) { last.setNextProxyInvocationHandler(proxyInvocationHandler); @@ -96,7 +96,7 @@ public ProxyInvocationHandler parserInterfaceToProxy(Object target, String objec last = proxyInvocationHandler; } - return result; + return first; } @Override diff --git a/tcc/src/main/java/org/apache/seata/rm/tcc/interceptor/TccActionInterceptorHandler.java b/tcc/src/main/java/org/apache/seata/rm/tcc/interceptor/TccActionInterceptorHandler.java index 506f137d4d2..9b50104c9e0 100644 --- a/tcc/src/main/java/org/apache/seata/rm/tcc/interceptor/TccActionInterceptorHandler.java +++ b/tcc/src/main/java/org/apache/seata/rm/tcc/interceptor/TccActionInterceptorHandler.java @@ -30,6 +30,7 @@ import org.apache.seata.core.model.BranchType; import org.apache.seata.integration.tx.api.fence.config.CommonFenceConfig; import org.apache.seata.integration.tx.api.interceptor.ActionInterceptorHandler; +import org.apache.seata.integration.tx.api.interceptor.InvocationHandlerType; import org.apache.seata.integration.tx.api.interceptor.InvocationWrapper; import org.apache.seata.integration.tx.api.interceptor.SeataInterceptorPosition; import org.apache.seata.integration.tx.api.interceptor.TwoPhaseBusinessActionParam; @@ -171,6 +172,6 @@ public int order() { @Override public String type() { - return "twoPhaseAnnotation"; + return InvocationHandlerType.TwoPhaseAnnotation.name(); } }