This is an automated email from the ASF dual-hosted git repository.
jimin pushed a commit to branch 2.x
in repository https://gitbox.apache.org/repos/asf/incubator-seata.git
The following commit(s) were added to refs/heads/2.x by this push:
new 06ec3fe4e2 refactor: Refactor Alibaba Dubbo and HSF (#7617)
06ec3fe4e2 is described below
commit 06ec3fe4e201299b08f6d85b8de2fb8bed297141
Author: jimin <[email protected]>
AuthorDate: Thu Oct 9 11:35:48 2025 +0800
refactor: Refactor Alibaba Dubbo and HSF (#7617)
---
changes/en-us/2.x.md | 2 +-
changes/zh-cn/2.x.md | 2 +-
.../AlibabaDubboTransactionConsumerFilter.java | 29 ++-
.../AlibabaDubboTransactionProviderFilter.java | 137 +++++++---
.../AlibabaDubboTransactionProviderFilterTest.java | 277 +++++++++++++++++++++
.../hsf/HsfTransactionConsumerFilter.java | 61 ++++-
.../hsf/HsfTransactionProviderFilter.java | 173 ++++++++++---
7 files changed, 591 insertions(+), 90 deletions(-)
diff --git a/changes/en-us/2.x.md b/changes/en-us/2.x.md
index 63aaa16183..b0400c79a5 100644
--- a/changes/en-us/2.x.md
+++ b/changes/en-us/2.x.md
@@ -81,7 +81,7 @@ Add changes here for all PR submitted to the 2.x branch.
### refactor:
-- [[#PR_NO](https://github.com/seata/seata/pull/PR_NO)] refactor for XXX
+- [[#7617](https://github.com/seata/seata/pull/7617)] Refactor Alibaba Dubbo
and HSF
### doc:
diff --git a/changes/zh-cn/2.x.md b/changes/zh-cn/2.x.md
index f3783f8234..981153aff7 100644
--- a/changes/zh-cn/2.x.md
+++ b/changes/zh-cn/2.x.md
@@ -81,7 +81,7 @@
### refactor:
-- [[#PR_NO](https://github.com/seata/seata/pull/PR_NO)] 重构 XXX
+- [[#7617](https://github.com/seata/seata/pull/7617)] 重构 Alibaba Dubbo 和 HSF 模块
### doc:
diff --git
a/integration/dubbo-alibaba/src/main/java/org/apache/seata/integration/dubbo/alibaba/AlibabaDubboTransactionConsumerFilter.java
b/integration/dubbo-alibaba/src/main/java/org/apache/seata/integration/dubbo/alibaba/AlibabaDubboTransactionConsumerFilter.java
index e3aa8244fe..4549dfd5dc 100644
---
a/integration/dubbo-alibaba/src/main/java/org/apache/seata/integration/dubbo/alibaba/AlibabaDubboTransactionConsumerFilter.java
+++
b/integration/dubbo-alibaba/src/main/java/org/apache/seata/integration/dubbo/alibaba/AlibabaDubboTransactionConsumerFilter.java
@@ -44,21 +44,38 @@ public class AlibabaDubboTransactionConsumerFilter
implements Filter {
if (!DubboConstants.ALIBABADUBBO) {
return invoker.invoke(invocation);
}
+ return doInvoke(invoker, invocation);
+ }
+
+ private Result doInvoke(Invoker<?> invoker, Invocation invocation) throws
RpcException {
String xid = RootContext.getXID();
BranchType branchType = RootContext.getBranchType();
-
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("consumer xid in RootContext[{}], branchType in
RootContext[{}]", xid, branchType);
}
+ try {
+ propagateTransactionContext(xid, branchType);
+ return invoker.invoke(invocation);
+ } finally {
+ clearTransactionContext();
+ }
+ }
+
+ private void propagateTransactionContext(String xid, BranchType
branchType) {
if (xid != null) {
RpcContext.getContext().setAttachment(RootContext.KEY_XID, xid);
RpcContext.getContext().setAttachment(RootContext.KEY_BRANCH_TYPE,
branchType.name());
+ if (LOGGER.isDebugEnabled()) {
+ LOGGER.debug("transaction context propagated: xid={},
branchType={}", xid, branchType);
+ }
}
- try {
- return invoker.invoke(invocation);
- } finally {
- RpcContext.getContext().removeAttachment(RootContext.KEY_XID);
-
RpcContext.getContext().removeAttachment(RootContext.KEY_BRANCH_TYPE);
+ }
+
+ private void clearTransactionContext() {
+ RpcContext.getContext().removeAttachment(RootContext.KEY_XID);
+ RpcContext.getContext().removeAttachment(RootContext.KEY_BRANCH_TYPE);
+ if (LOGGER.isDebugEnabled()) {
+ LOGGER.debug("transaction context cleared");
}
}
}
diff --git
a/integration/dubbo-alibaba/src/main/java/org/apache/seata/integration/dubbo/alibaba/AlibabaDubboTransactionProviderFilter.java
b/integration/dubbo-alibaba/src/main/java/org/apache/seata/integration/dubbo/alibaba/AlibabaDubboTransactionProviderFilter.java
index f361f1c457..7c8a4fddf9 100644
---
a/integration/dubbo-alibaba/src/main/java/org/apache/seata/integration/dubbo/alibaba/AlibabaDubboTransactionProviderFilter.java
+++
b/integration/dubbo-alibaba/src/main/java/org/apache/seata/integration/dubbo/alibaba/AlibabaDubboTransactionProviderFilter.java
@@ -45,54 +45,100 @@ public class AlibabaDubboTransactionProviderFilter
implements Filter {
if (!DubboConstants.ALIBABADUBBO) {
return invoker.invoke(invocation);
}
+
+ return doInvoke(invoker, invocation);
+ }
+
+ private Result doInvoke(Invoker<?> invoker, Invocation invocation) throws
RpcException {
String rpcXid = getRpcXid();
String rpcBranchType =
RpcContext.getContext().getAttachment(RootContext.KEY_BRANCH_TYPE);
+
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("xid in RpcContext[{}], branchType in
RpcContext[{}]", rpcXid, rpcBranchType);
}
- boolean bind = false;
+
+ TransactionContextBinding binding = bindTransactionContext(rpcXid,
rpcBranchType);
+
+ try {
+ return invoker.invoke(invocation);
+ } finally {
+ unbindTransactionContext(binding);
+ clearServerContextAttachments();
+ }
+ }
+
+ private TransactionContextBinding bindTransactionContext(String rpcXid,
String rpcBranchType) {
+ TransactionContextBinding binding = new TransactionContextBinding();
+
if (rpcXid != null) {
RootContext.bind(rpcXid);
+ binding.wasBound = true;
+ binding.bindXid = rpcXid;
+
if (StringUtils.equals(BranchType.TCC.name(), rpcBranchType)) {
RootContext.bindBranchType(BranchType.TCC);
+ binding.wasBranchTypeBound = true;
+ }
+
+ if (LOGGER.isDebugEnabled()) {
+ LOGGER.debug("bind xid [{}] branchType [{}] to RootContext",
rpcXid, rpcBranchType);
}
- bind = true;
}
- try {
- return invoker.invoke(invocation);
- } finally {
- if (bind) {
- BranchType previousBranchType = RootContext.getBranchType();
- String unbindXid = RootContext.unbind();
- if (BranchType.TCC == previousBranchType) {
- RootContext.unbindBranchType();
- }
- if (LOGGER.isDebugEnabled()) {
- LOGGER.debug("unbind xid [{}] branchType [{}] from
RootContext", unbindXid, previousBranchType);
- }
- if (!rpcXid.equalsIgnoreCase(unbindXid)) {
- LOGGER.warn(
- "xid in change during RPC from {} to {},branchType
from {} to {}",
- rpcXid,
- unbindXid,
- rpcBranchType != null ? rpcBranchType :
BranchType.AT,
- previousBranchType);
- if (unbindXid != null) {
- RootContext.bind(unbindXid);
- LOGGER.warn("bind xid [{}] back to RootContext",
unbindXid);
- if (BranchType.TCC == previousBranchType) {
- RootContext.bindBranchType(BranchType.TCC);
- LOGGER.warn("bind branchType [{}] back to
RootContext", previousBranchType);
- }
- }
- }
+ return binding;
+ }
+
+ private void unbindTransactionContext(TransactionContextBinding binding) {
+ if (!binding.wasBound) {
+ return;
+ }
+
+ BranchType previousBranchType = RootContext.getBranchType();
+ String unbindXid = RootContext.unbind();
+ binding.unbindXid = unbindXid;
+ binding.unbindBranchType = previousBranchType;
+
+ if (binding.wasBranchTypeBound && BranchType.TCC ==
previousBranchType) {
+ RootContext.unbindBranchType();
+ }
+
+ if (LOGGER.isDebugEnabled()) {
+ LOGGER.debug("unbind xid [{}] branchType [{}] from RootContext",
unbindXid, previousBranchType);
+ }
+
+ handleXidChange(binding);
+ }
+
+ private void handleXidChange(TransactionContextBinding binding) {
+ if (!binding.bindXid.equalsIgnoreCase(binding.unbindXid)) {
+ LOGGER.warn(
+ "xid in change during RPC from {} to {},branchType from {}
to {}",
+ binding.bindXid,
+ binding.unbindXid,
+ binding.bindBranchType != null ? binding.bindBranchType :
BranchType.AT,
+ binding.unbindBranchType);
+
+ if (binding.unbindXid != null) {
+ restoreTransactionContext(binding);
}
-
RpcContext.getServerContext().removeAttachment(RootContext.KEY_XID);
-
RpcContext.getServerContext().removeAttachment(RootContext.KEY_BRANCH_TYPE);
}
}
+ private void restoreTransactionContext(TransactionContextBinding binding) {
+ RootContext.bind(binding.unbindXid);
+ LOGGER.warn("bind xid [{}] back to RootContext", binding.unbindXid);
+
+ if (BranchType.TCC == binding.unbindBranchType) {
+ RootContext.bindBranchType(BranchType.TCC);
+ LOGGER.warn("bind branchType [{}] back to RootContext",
binding.unbindBranchType);
+ }
+ }
+
+ private void clearServerContextAttachments() {
+ RpcContext.getServerContext().removeAttachment(RootContext.KEY_XID);
+
RpcContext.getServerContext().removeAttachment(RootContext.KEY_BRANCH_TYPE);
+ }
+
/**
* get rpc xid
*
@@ -105,4 +151,31 @@ public class AlibabaDubboTransactionProviderFilter
implements Filter {
}
return rpcXid;
}
+
+ private static class TransactionContextBinding {
+ /**
+ * The Was bound.
+ */
+ boolean wasBound = false;
+ /**
+ * The Was branch type bound.
+ */
+ boolean wasBranchTypeBound = false;
+ /**
+ * The Bind xid.
+ */
+ String bindXid;
+ /**
+ * The Bind branch type.
+ */
+ String bindBranchType;
+ /**
+ * The Unbind xid.
+ */
+ String unbindXid;
+ /**
+ * The Unbind branch type.
+ */
+ BranchType unbindBranchType;
+ }
}
diff --git
a/integration/dubbo-alibaba/src/test/java/org/apache/seata/integration/dubbo/alibaba/AlibabaDubboTransactionProviderFilterTest.java
b/integration/dubbo-alibaba/src/test/java/org/apache/seata/integration/dubbo/alibaba/AlibabaDubboTransactionProviderFilterTest.java
new file mode 100644
index 0000000000..067f3a2649
--- /dev/null
+++
b/integration/dubbo-alibaba/src/test/java/org/apache/seata/integration/dubbo/alibaba/AlibabaDubboTransactionProviderFilterTest.java
@@ -0,0 +1,277 @@
+/*
+ * 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.dubbo.alibaba;
+
+import com.alibaba.dubbo.rpc.Invocation;
+import com.alibaba.dubbo.rpc.Invoker;
+import com.alibaba.dubbo.rpc.Result;
+import com.alibaba.dubbo.rpc.RpcContext;
+import com.alibaba.dubbo.rpc.RpcException;
+import org.apache.seata.core.constants.DubboConstants;
+import org.apache.seata.core.context.RootContext;
+import org.apache.seata.core.model.BranchType;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.mockito.MockedStatic;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.mockStatic;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+public class AlibabaDubboTransactionProviderFilterTest {
+ private AlibabaDubboTransactionProviderFilter filter;
+ private Invoker invoker;
+ private Invocation invocation;
+ private RpcContext rpcContext;
+ private RpcContext rpcServerContext;
+ private MockedStatic<RpcContext> rpcContextMock;
+
+ @BeforeEach
+ void setUp() {
+ filter = new AlibabaDubboTransactionProviderFilter();
+ invoker = mock(Invoker.class);
+ invocation = mock(Invocation.class);
+
+ // Mock RpcContext
+ rpcContextMock = mockStatic(RpcContext.class);
+ rpcContext = mock(RpcContext.class);
+ rpcServerContext = mock(RpcContext.class);
+
+ rpcContextMock.when(RpcContext::getContext).thenReturn(rpcContext);
+
rpcContextMock.when(RpcContext::getServerContext).thenReturn(rpcServerContext);
+ }
+
+ @AfterEach
+ void tearDown() {
+ // Clear RootContext
+ RootContext.unbind();
+ RootContext.unbindBranchType();
+
+ if (rpcContextMock != null) {
+ rpcContextMock.close();
+ }
+ }
+
+ @Test
+ void testInvokeWhenNotAlibabaDubbo() {
+ // Arrange
+ Result expectedResult = mock(Result.class);
+ when(invoker.invoke(invocation)).thenReturn(expectedResult);
+
+ // Test when DubboConstants.ALIBABADUBBO is false
+ // We need to use reflection to change the value of the static final
field
+ try {
+ // Use a different approach - test the actual behavior by checking
if the filter returns early
+ // Create a new filter and directly test its behavior
+ AlibabaDubboTransactionProviderFilter filterWithFalse = new
AlibabaDubboTransactionProviderFilter() {
+ // Override the invoke method to simulate ALIBABADUBBO = false
+ @Override
+ public Result invoke(Invoker<?> invoker, Invocation
invocation) throws RpcException {
+ // Simulate ALIBABADUBBO = false
+ try {
+ java.lang.reflect.Field field =
DubboConstants.class.getDeclaredField("ALIBABADUBBO");
+ field.setAccessible(true);
+ field.setBoolean(null, false);
+ } catch (Exception e) {
+ // Ignore
+ }
+ return super.invoke(invoker, invocation);
+ }
+ };
+
+ // Act
+ Result result = filterWithFalse.invoke(invoker, invocation);
+
+ // Assert
+ assertEquals(expectedResult, result);
+ verify(invoker).invoke(invocation);
+ } finally {
+ // Restore the original value
+ try {
+ java.lang.reflect.Field field =
DubboConstants.class.getDeclaredField("ALIBABADUBBO");
+ field.setAccessible(true);
+ field.setBoolean(null, true);
+ } catch (Exception e) {
+ // Ignore
+ }
+ }
+ }
+
+ @Test
+ void testInvokeWhenXidIsNull() {
+ // Arrange
+ Result expectedResult = mock(Result.class);
+ when(invoker.invoke(invocation)).thenReturn(expectedResult);
+ when(rpcContext.getAttachment(RootContext.KEY_XID)).thenReturn(null);
+
when(rpcContext.getAttachment(RootContext.KEY_XID.toLowerCase())).thenReturn(null);
+
+ // Act
+ Result result = filter.invoke(invoker, invocation);
+
+ // Assert
+ assertEquals(expectedResult, result);
+ verify(invoker).invoke(invocation);
+ verify(rpcContext).getAttachment(RootContext.KEY_XID);
+ verify(rpcContext).getAttachment(RootContext.KEY_XID.toLowerCase());
+ assertNull(RootContext.getXID());
+ }
+
+ @Test
+ void testInvokeWhenXidIsPresent() {
+ // Arrange
+ String xid = "test-xid-123";
+ Result expectedResult = mock(Result.class);
+ when(invoker.invoke(invocation)).thenReturn(expectedResult);
+ when(rpcContext.getAttachment(RootContext.KEY_XID)).thenReturn(xid);
+
when(rpcServerContext.getAttachment(RootContext.KEY_BRANCH_TYPE)).thenReturn(null);
+
+ // Act
+ Result result = filter.invoke(invoker, invocation);
+
+ // Assert
+ assertEquals(expectedResult, result);
+ verify(invoker).invoke(invocation);
+ // After execution, context should be cleared
+ assertNull(RootContext.getXID());
+ }
+
+ @Test
+ void testInvokeWhenXidAndTccBranchTypeArePresent() {
+ // Arrange
+ String xid = "test-xid-123";
+ String branchType = BranchType.TCC.name();
+ Result expectedResult = mock(Result.class);
+ when(invoker.invoke(invocation)).thenReturn(expectedResult);
+ when(rpcContext.getAttachment(RootContext.KEY_XID)).thenReturn(xid);
+
when(rpcServerContext.getAttachment(RootContext.KEY_BRANCH_TYPE)).thenReturn(branchType);
+
+ // Act
+ Result result = filter.invoke(invoker, invocation);
+
+ // Assert
+ assertEquals(expectedResult, result);
+ verify(invoker).invoke(invocation);
+ // After execution, context should be cleared
+ assertNull(RootContext.getXID());
+ assertNull(RootContext.getBranchType());
+ }
+
+ @Test
+ void testInvokeWhenXidAndAtBranchTypeArePresent() {
+ // Arrange
+ String xid = "test-xid-123";
+ String branchType = BranchType.AT.name();
+ Result expectedResult = mock(Result.class);
+ when(invoker.invoke(invocation)).thenReturn(expectedResult);
+ when(rpcContext.getAttachment(RootContext.KEY_XID)).thenReturn(xid);
+
when(rpcServerContext.getAttachment(RootContext.KEY_BRANCH_TYPE)).thenReturn(branchType);
+
+ // Act
+ Result result = filter.invoke(invoker, invocation);
+
+ // Assert
+ assertEquals(expectedResult, result);
+ verify(invoker).invoke(invocation);
+ // After execution, context should be cleared
+ assertNull(RootContext.getXID());
+ assertNull(RootContext.getBranchType());
+ }
+
+ @Test
+ void testInvokeWhenXidChangedDuringExecution() {
+ // Arrange
+ String originalXid = "original-xid-123";
+ String changedXid = "changed-xid-456";
+ Result expectedResult = mock(Result.class);
+
+ // Mock the invocation to simulate XID change during execution
+ when(invoker.invoke(invocation)).thenAnswer(invocationOnMock -> {
+ // Simulate XID change during invocation
+ RootContext.bind(changedXid);
+ return expectedResult;
+ });
+
+
when(rpcContext.getAttachment(RootContext.KEY_XID)).thenReturn(originalXid);
+
when(rpcContext.getAttachment(RootContext.KEY_BRANCH_TYPE)).thenReturn(null);
+
+ // Act
+ Result result = filter.invoke(invoker, invocation);
+
+ // Assert
+ assertEquals(expectedResult, result);
+ verify(invoker).invoke(invocation);
+ // According to the source code, when XID changes during execution,
+ // the filter should restore the changed XID (not the original one)
+ assertEquals(changedXid, RootContext.getXID());
+ }
+
+ @Test
+ void testGetRpcXidWhenXidExists() {
+ // Arrange
+ String xid = "test-xid-123";
+ when(rpcContext.getAttachment(RootContext.KEY_XID)).thenReturn(xid);
+
+ // Act - Using reflection to test private method
+ String result = invokePrivateMethod("getRpcXid");
+
+ // Assert
+ assertEquals(xid, result);
+ }
+
+ @Test
+ void testGetRpcXidWhenXidIsNullButLowerCaseExists() {
+ // Arrange
+ String xid = "test-xid-123";
+ when(rpcContext.getAttachment(RootContext.KEY_XID)).thenReturn(null);
+
when(rpcContext.getAttachment(RootContext.KEY_XID.toLowerCase())).thenReturn(xid);
+
+ // Act - Using reflection to test private method
+ String result = invokePrivateMethod("getRpcXid");
+
+ // Assert
+ assertEquals(xid, result);
+ }
+
+ @Test
+ void testGetRpcXidWhenBothXidAreNull() {
+ // Arrange
+ when(rpcContext.getAttachment(RootContext.KEY_XID)).thenReturn(null);
+
when(rpcContext.getAttachment(RootContext.KEY_XID.toLowerCase())).thenReturn(null);
+
+ // Act - Using reflection to test private method
+ String result = invokePrivateMethod("getRpcXid");
+
+ // Assert
+ assertNull(result);
+ }
+
+ // Helper method to test private methods using reflection
+ private String invokePrivateMethod(String methodName) {
+ try {
+ java.lang.reflect.Method method =
AlibabaDubboTransactionProviderFilter.class.getDeclaredMethod(methodName);
+ method.setAccessible(true);
+ return (String) method.invoke(filter);
+ } catch (Exception e) {
+ throw new RuntimeException("Failed to invoke private method: " +
methodName, e);
+ }
+ }
+}
diff --git
a/integration/hsf/src/main/java/org/apache/seata/integration/hsf/HsfTransactionConsumerFilter.java
b/integration/hsf/src/main/java/org/apache/seata/integration/hsf/HsfTransactionConsumerFilter.java
index 9e1df9837e..418b5a0865 100644
---
a/integration/hsf/src/main/java/org/apache/seata/integration/hsf/HsfTransactionConsumerFilter.java
+++
b/integration/hsf/src/main/java/org/apache/seata/integration/hsf/HsfTransactionConsumerFilter.java
@@ -36,24 +36,65 @@ public class HsfTransactionConsumerFilter implements
ClientFilter {
@Override
public ListenableFuture<RPCResult> invoke(InvocationHandler nextHandler,
Invocation invocation) throws Throwable {
- String xid = RootContext.getXID();
- BranchType branchType = RootContext.getBranchType();
+ return doInvoke(nextHandler, invocation);
+ }
+
+ private ListenableFuture<RPCResult> doInvoke(InvocationHandler
nextHandler, Invocation invocation)
+ throws Throwable {
+ TransactionContext context = extractTransactionContext();
if (LOGGER.isDebugEnabled()) {
- LOGGER.debug("xid in RootContext[{}], branchType in
RootContext[{}]", xid, branchType);
- }
- if (xid != null) {
- RPCContext.getClientContext().putAttachment(RootContext.KEY_XID,
xid);
-
RPCContext.getClientContext().putAttachment(RootContext.KEY_BRANCH_TYPE,
branchType.name());
+ LOGGER.debug("xid in RootContext[{}], branchType in
RootContext[{}]", context.xid, context.branchType);
}
+
try {
+ propagateTransactionContext(context);
return nextHandler.invoke(invocation);
} finally {
-
RPCContext.getClientContext().removeAttachment(RootContext.KEY_XID);
-
RPCContext.getClientContext().removeAttachment(RootContext.KEY_BRANCH_TYPE);
+ clearTransactionContext();
+ }
+ }
+
+ private TransactionContext extractTransactionContext() {
+ TransactionContext context = new TransactionContext();
+ context.xid = RootContext.getXID();
+ context.branchType = RootContext.getBranchType();
+ return context;
+ }
+
+ private void propagateTransactionContext(TransactionContext context) {
+ if (context.xid != null) {
+ RPCContext.getClientContext().putAttachment(RootContext.KEY_XID,
context.xid);
+
RPCContext.getClientContext().putAttachment(RootContext.KEY_BRANCH_TYPE,
context.branchType.name());
+
+ if (LOGGER.isDebugEnabled()) {
+ LOGGER.debug("transaction context propagated: xid={},
branchType={}", context.xid, context.branchType);
+ }
+ }
+ }
+
+ private void clearTransactionContext() {
+ RPCContext.getClientContext().removeAttachment(RootContext.KEY_XID);
+
RPCContext.getClientContext().removeAttachment(RootContext.KEY_BRANCH_TYPE);
+
+ if (LOGGER.isDebugEnabled()) {
+ LOGGER.debug("transaction context cleared");
}
}
@Override
- public void onResponse(Invocation invocation, RPCResult rpcResult) {}
+ public void onResponse(Invocation invocation, RPCResult rpcResult) {
+ // No operation needed
+ }
+
+ private static class TransactionContext {
+ /**
+ * The Xid.
+ */
+ String xid;
+ /**
+ * The Branch type.
+ */
+ BranchType branchType;
+ }
}
diff --git
a/integration/hsf/src/main/java/org/apache/seata/integration/hsf/HsfTransactionProviderFilter.java
b/integration/hsf/src/main/java/org/apache/seata/integration/hsf/HsfTransactionProviderFilter.java
index e60460877e..b87d59a475 100644
---
a/integration/hsf/src/main/java/org/apache/seata/integration/hsf/HsfTransactionProviderFilter.java
+++
b/integration/hsf/src/main/java/org/apache/seata/integration/hsf/HsfTransactionProviderFilter.java
@@ -37,57 +37,150 @@ public class HsfTransactionProviderFilter implements
ServerFilter {
@Override
public ListenableFuture<RPCResult> invoke(InvocationHandler nextHandler,
Invocation invocation) throws Throwable {
+ return doInvoke(nextHandler, invocation);
+ }
+
+ private ListenableFuture<RPCResult> doInvoke(InvocationHandler
nextHandler, Invocation invocation)
+ throws Throwable {
+ RpcTransactionContext rpcContext = extractRpcTransactionContext();
- Object rpcXid =
RPCContext.getServerContext().getAttachment(RootContext.KEY_XID);
- Object rpcBranchType =
RPCContext.getServerContext().getAttachment(RootContext.KEY_BRANCH_TYPE);
if (LOGGER.isDebugEnabled()) {
- LOGGER.debug("xid in RpcContext[{}], branchType in
RpcContext[{}]", rpcXid, rpcBranchType);
+ LOGGER.debug(
+ "xid in RpcContext[{}], branchType in RpcContext[{}]",
rpcContext.rpcXid, rpcContext.rpcBranchType);
}
- boolean bind = false;
- if (rpcXid != null) {
- RootContext.bind(rpcXid.toString());
- if (StringUtils.equals(BranchType.TCC.name(),
rpcBranchType.toString())) {
+
+ TransactionContextBinding binding = bindTransactionContext(rpcContext);
+
+ try {
+ return nextHandler.invoke(invocation);
+ } finally {
+ unbindTransactionContext(binding);
+ clearServerContextAttachments();
+ }
+ }
+
+ private RpcTransactionContext extractRpcTransactionContext() {
+ RpcTransactionContext context = new RpcTransactionContext();
+ context.rpcXid =
RPCContext.getServerContext().getAttachment(RootContext.KEY_XID);
+ context.rpcBranchType =
RPCContext.getServerContext().getAttachment(RootContext.KEY_BRANCH_TYPE);
+ return context;
+ }
+
+ private TransactionContextBinding
bindTransactionContext(RpcTransactionContext rpcContext) {
+ TransactionContextBinding binding = new TransactionContextBinding();
+
+ if (rpcContext.rpcXid != null) {
+ String xidStr = rpcContext.rpcXid.toString();
+ RootContext.bind(xidStr);
+ binding.wasBound = true;
+ binding.bindXid = xidStr;
+
+ if (rpcContext.rpcBranchType != null
+ && StringUtils.equals(BranchType.TCC.name(),
rpcContext.rpcBranchType.toString())) {
RootContext.bindBranchType(BranchType.TCC);
+ binding.wasBranchTypeBound = true;
}
- bind = true;
+
if (LOGGER.isDebugEnabled()) {
- LOGGER.debug("bind xid [{}] branchType [{}] to RootContext",
rpcXid, rpcBranchType);
+ LOGGER.debug(
+ "bind xid [{}] branchType [{}] to RootContext",
rpcContext.rpcXid, rpcContext.rpcBranchType);
}
}
- try {
- return nextHandler.invoke(invocation);
- } finally {
- if (bind) {
- BranchType previousBranchType = RootContext.getBranchType();
- String unbindXid = RootContext.unbind();
- if (BranchType.TCC == previousBranchType) {
- RootContext.unbindBranchType();
- }
- if (LOGGER.isDebugEnabled()) {
- LOGGER.debug("unbind xid [{}] branchType [{}] from
RootContext", unbindXid, previousBranchType);
- }
- if (!rpcXid.toString().equalsIgnoreCase(unbindXid)) {
- LOGGER.warn(
- "xid in change during RPC from {} to {},branchType
from {} to {}",
- rpcXid,
- unbindXid,
- rpcBranchType != null ? rpcBranchType : "AT",
- previousBranchType);
- if (unbindXid != null) {
- RootContext.bind(unbindXid);
- LOGGER.warn("bind xid [{}] back to RootContext",
unbindXid);
- if (BranchType.TCC == previousBranchType) {
- RootContext.bindBranchType(BranchType.TCC);
- LOGGER.warn("bind branchType [{}] back to
RootContext", previousBranchType);
- }
- }
- }
+
+ return binding;
+ }
+
+ private void unbindTransactionContext(TransactionContextBinding binding) {
+ if (!binding.wasBound) {
+ return;
+ }
+
+ BranchType previousBranchType = RootContext.getBranchType();
+ String unbindXid = RootContext.unbind();
+ binding.unbindXid = unbindXid;
+ binding.unbindBranchType = previousBranchType;
+
+ if (binding.wasBranchTypeBound && BranchType.TCC ==
previousBranchType) {
+ RootContext.unbindBranchType();
+ }
+
+ if (LOGGER.isDebugEnabled()) {
+ LOGGER.debug("unbind xid [{}] branchType [{}] from RootContext",
unbindXid, previousBranchType);
+ }
+
+ handleXidChange(binding);
+ }
+
+ private void handleXidChange(TransactionContextBinding binding) {
+ if (!binding.bindXid.equalsIgnoreCase(binding.unbindXid)) {
+ LOGGER.warn(
+ "xid in change during RPC from {} to {},branchType from {}
to {}",
+ binding.bindXid,
+ binding.unbindXid,
+ binding.bindBranchType != null ? binding.bindBranchType :
"AT",
+ binding.unbindBranchType);
+
+ if (binding.unbindXid != null) {
+ restoreTransactionContext(binding);
}
-
RPCContext.getServerContext().removeAttachment(RootContext.KEY_XID);
-
RPCContext.getServerContext().removeAttachment(RootContext.KEY_BRANCH_TYPE);
}
}
+ private void restoreTransactionContext(TransactionContextBinding binding) {
+ RootContext.bind(binding.unbindXid);
+ LOGGER.warn("bind xid [{}] back to RootContext", binding.unbindXid);
+
+ if (BranchType.TCC == binding.unbindBranchType) {
+ RootContext.bindBranchType(BranchType.TCC);
+ LOGGER.warn("bind branchType [{}] back to RootContext",
binding.unbindBranchType);
+ }
+ }
+
+ private void clearServerContextAttachments() {
+ RPCContext.getServerContext().removeAttachment(RootContext.KEY_XID);
+
RPCContext.getServerContext().removeAttachment(RootContext.KEY_BRANCH_TYPE);
+ }
+
@Override
- public void onResponse(Invocation invocation, RPCResult rpcResult) {}
+ public void onResponse(Invocation invocation, RPCResult rpcResult) {
+ // No operation needed
+ }
+
+ private static class RpcTransactionContext {
+ /**
+ * The Rpc xid.
+ */
+ Object rpcXid;
+ /**
+ * The Rpc branch type.
+ */
+ Object rpcBranchType;
+ }
+
+ private static class TransactionContextBinding {
+ /**
+ * The Was bound.
+ */
+ boolean wasBound = false;
+ /**
+ * The Was branch type bound.
+ */
+ boolean wasBranchTypeBound = false;
+ /**
+ * The Bind xid.
+ */
+ String bindXid;
+ /**
+ * The Bind branch type.
+ */
+ String bindBranchType;
+ /**
+ * The Unbind xid.
+ */
+ String unbindXid;
+ /**
+ * The Unbind branch type.
+ */
+ BranchType unbindBranchType;
+ }
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]