This is an automated email from the ASF dual-hosted git repository.

ningjiang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-servicecomb-saga.git

commit 91634874da8703203476db725d90cd8b97c0e687
Author: cherrylzhao <[email protected]>
AuthorDate: Fri Oct 19 18:00:10 2018 +0800

    SCB-963 Make TCC coordinate method transactional.
---
 .../saga/omega/context/CallbackContext.java        |  4 +-
 .../transaction/spring/MethodCheckingCallback.java | 46 +++++++++++++++++++++-
 .../spring/ParticipateAnnotationProcessor.java     |  4 +-
 .../transaction/spring/TccInterceptorTest.java     |  7 +---
 .../omega/transaction/spring/TccUserService.java   | 23 +++++------
 .../spring/TransactionalUserService.java           | 12 +++---
 6 files changed, 69 insertions(+), 27 deletions(-)

diff --git 
a/omega/omega-context/src/main/java/org/apache/servicecomb/saga/omega/context/CallbackContext.java
 
b/omega/omega-context/src/main/java/org/apache/servicecomb/saga/omega/context/CallbackContext.java
index 0fe2613..cf5ab50 100644
--- 
a/omega/omega-context/src/main/java/org/apache/servicecomb/saga/omega/context/CallbackContext.java
+++ 
b/omega/omega-context/src/main/java/org/apache/servicecomb/saga/omega/context/CallbackContext.java
@@ -35,9 +35,9 @@ public class CallbackContext {
     this.omegaContext = omegaContext;
   }
 
-  public void addCallbackContext(Method compensationMethod, Object target) {
+  public void addCallbackContext(String key, Method compensationMethod, Object 
target) {
     compensationMethod.setAccessible(true);
-    contexts.put(compensationMethod.toString(), new 
CallbackContextInternal(target, compensationMethod));
+    contexts.put(key, new CallbackContextInternal(target, compensationMethod));
   }
 
   public void apply(String globalTxId, String localTxId, String 
callbackMethod, Object... payloads) {
diff --git 
a/omega/omega-spring-tx/src/main/java/org/apache/servicecomb/saga/omega/transaction/spring/MethodCheckingCallback.java
 
b/omega/omega-spring-tx/src/main/java/org/apache/servicecomb/saga/omega/transaction/spring/MethodCheckingCallback.java
index 8a2ac13..6c52313 100644
--- 
a/omega/omega-spring-tx/src/main/java/org/apache/servicecomb/saga/omega/transaction/spring/MethodCheckingCallback.java
+++ 
b/omega/omega-spring-tx/src/main/java/org/apache/servicecomb/saga/omega/transaction/spring/MethodCheckingCallback.java
@@ -18,11 +18,15 @@
 package org.apache.servicecomb.saga.omega.transaction.spring;
 
 import java.lang.invoke.MethodHandles;
+import java.lang.reflect.Field;
 import java.lang.reflect.Method;
 import org.apache.servicecomb.saga.omega.context.CallbackContext;
 import org.apache.servicecomb.saga.omega.transaction.OmegaException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
+import org.springframework.aop.framework.AdvisedSupport;
+import org.springframework.aop.framework.AopProxy;
+import org.springframework.aop.support.AopUtils;
 import org.springframework.util.ReflectionUtils.MethodCallback;
 
 public abstract class MethodCheckingCallback implements MethodCallback {
@@ -45,12 +49,50 @@ public abstract class MethodCheckingCallback implements 
MethodCallback {
     for (String each : candidates) {
       try {
         Method signature = bean.getClass().getDeclaredMethod(each, 
method.getParameterTypes());
-        callbackContext.addCallbackContext(signature, bean);
+        String key = getTargetBean(bean).getClass().getDeclaredMethod(each, 
method.getParameterTypes()).toString();
+        callbackContext.addCallbackContext(key, signature, bean);
         LOG.debug("Found callback method [{}] in {}", each, 
bean.getClass().getCanonicalName());
-      } catch (NoSuchMethodException ex) {
+      } catch (Exception ex) {
         throw new OmegaException(
             "No such " + callbackType + " method [" + each + "] found in " + 
bean.getClass().getCanonicalName(), ex);
       }
     }
   }
+
+  private Object getTargetBean(Object proxy) throws Exception {
+    if(!AopUtils.isAopProxy(proxy)) {
+      return proxy;
+    }
+
+    if(AopUtils.isJdkDynamicProxy(proxy)) {
+      return getJdkDynamicProxyTargetObject(proxy);
+    } else {
+      return getCglibProxyTargetObject(proxy);
+    }
+  }
+
+  private Object getCglibProxyTargetObject(Object proxy) throws Exception {
+    Field h = proxy.getClass().getDeclaredField("CGLIB$CALLBACK_0");
+    h.setAccessible(true);
+    Object dynamicAdvisedInterceptor = h.get(proxy);
+
+    Field advised = 
dynamicAdvisedInterceptor.getClass().getDeclaredField("advised");
+    advised.setAccessible(true);
+
+    Object result = 
((AdvisedSupport)advised.get(dynamicAdvisedInterceptor)).getTargetSource().getTarget();
+    return result;
+  }
+
+
+  private Object getJdkDynamicProxyTargetObject(Object proxy) throws Exception 
{
+    Field h = proxy.getClass().getSuperclass().getDeclaredField("h");
+    h.setAccessible(true);
+    AopProxy aopProxy = (AopProxy) h.get(proxy);
+
+    Field advised = aopProxy.getClass().getDeclaredField("advised");
+    advised.setAccessible(true);
+
+    Object result = 
((AdvisedSupport)advised.get(aopProxy)).getTargetSource().getTarget();
+    return result;
+  }
 }
diff --git 
a/omega/omega-spring-tx/src/main/java/org/apache/servicecomb/saga/omega/transaction/spring/ParticipateAnnotationProcessor.java
 
b/omega/omega-spring-tx/src/main/java/org/apache/servicecomb/saga/omega/transaction/spring/ParticipateAnnotationProcessor.java
index 5cef9ff..80583bd 100644
--- 
a/omega/omega-spring-tx/src/main/java/org/apache/servicecomb/saga/omega/transaction/spring/ParticipateAnnotationProcessor.java
+++ 
b/omega/omega-spring-tx/src/main/java/org/apache/servicecomb/saga/omega/transaction/spring/ParticipateAnnotationProcessor.java
@@ -36,13 +36,13 @@ class ParticipateAnnotationProcessor implements 
BeanPostProcessor {
 
   @Override
   public Object postProcessBeforeInitialization(Object bean, String beanName) 
throws BeansException {
-    checkMethod(bean);
-    checkFields(bean);
     return bean;
   }
 
   @Override
   public Object postProcessAfterInitialization(Object bean, String beanName) 
throws BeansException {
+    checkMethod(bean);
+    checkFields(bean);
     return bean;
   }
 
diff --git 
a/omega/omega-spring-tx/src/test/java/org/apache/servicecomb/saga/omega/transaction/spring/TccInterceptorTest.java
 
b/omega/omega-spring-tx/src/test/java/org/apache/servicecomb/saga/omega/transaction/spring/TccInterceptorTest.java
index bc9148b..7f43476 100644
--- 
a/omega/omega-spring-tx/src/test/java/org/apache/servicecomb/saga/omega/transaction/spring/TccInterceptorTest.java
+++ 
b/omega/omega-spring-tx/src/test/java/org/apache/servicecomb/saga/omega/transaction/spring/TccInterceptorTest.java
@@ -69,9 +69,6 @@ public class TccInterceptorTest {
   private List<String> messages;
 
   @Autowired
-  private OmegaContext omegaContext;
-
-  @Autowired
   private TccUserServiceMain tccUserServiceMain;
 
   @Autowired
@@ -95,7 +92,6 @@ public class TccInterceptorTest {
   public void tearDown() throws Exception {
     messages.clear();
     userRepository.deleteAll();
-    omegaContext.clear();
   }
 
   @AfterClass
@@ -152,7 +148,8 @@ public class TccInterceptorTest {
     );
 
     User result = userRepository.findByUsername(user.username());
-    assertThat(result, is(nullValue()));
+    assertThat(result.username(), is(user.username()));
+    assertThat(result.email(), is(user.email()));
 
     result = userRepository.findByUsername(jack.username());
     assertThat(result, is(nullValue()));
diff --git 
a/omega/omega-spring-tx/src/test/java/org/apache/servicecomb/saga/omega/transaction/spring/TccUserService.java
 
b/omega/omega-spring-tx/src/test/java/org/apache/servicecomb/saga/omega/transaction/spring/TccUserService.java
index 8223a87..31da4c9 100644
--- 
a/omega/omega-spring-tx/src/test/java/org/apache/servicecomb/saga/omega/transaction/spring/TccUserService.java
+++ 
b/omega/omega-spring-tx/src/test/java/org/apache/servicecomb/saga/omega/transaction/spring/TccUserService.java
@@ -20,26 +20,28 @@ package 
org.apache.servicecomb.saga.omega.transaction.spring;
 import static org.hamcrest.CoreMatchers.is;
 import static org.hamcrest.MatcherAssert.assertThat;
 
-import java.util.HashMap;
-import java.util.Map;
-
-import org.apache.servicecomb.saga.omega.context.OmegaContext;
+import javax.annotation.Resource;
 import org.apache.servicecomb.saga.omega.transaction.annotations.Participate;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Component;
+import org.springframework.transaction.annotation.Transactional;
 
 @Component
-class TccUserService {
+@Transactional
+public class TccUserService {
   static final String ILLEGAL_USER = "Illegal User";
-  private final UserRepository userRepository;
+
 
   @Autowired
   TccUserService(UserRepository userRepository) {
     this.userRepository = userRepository;
   }
 
+  @Resource
+  private UserRepository userRepository;
+
   @Participate(confirmMethod = "confirm", cancelMethod = "cancel")
-  User add(User user) {
+  public User add(User user) {
     // Only for the validation check
     if (ILLEGAL_USER.equals(user.username())) {
       throw new IllegalArgumentException("User is illegal");
@@ -47,15 +49,14 @@ class TccUserService {
     return userRepository.save(user);
   }
 
-  void confirm(User user) {
+  public void confirm(User user) {
     User result = userRepository.findByUsername(user.username());
     // Just make sure we can get the resource and keep doing other business
     assertThat(result, is(user));
   }
 
-  void cancel(User user) {
+  public void cancel(User user) {
     userRepository.delete(user);
+    throw new RuntimeException("transaction test");
   }
-
-
 }
diff --git 
a/omega/omega-spring-tx/src/test/java/org/apache/servicecomb/saga/omega/transaction/spring/TransactionalUserService.java
 
b/omega/omega-spring-tx/src/test/java/org/apache/servicecomb/saga/omega/transaction/spring/TransactionalUserService.java
index 0618109..11bc437 100644
--- 
a/omega/omega-spring-tx/src/test/java/org/apache/servicecomb/saga/omega/transaction/spring/TransactionalUserService.java
+++ 
b/omega/omega-spring-tx/src/test/java/org/apache/servicecomb/saga/omega/transaction/spring/TransactionalUserService.java
@@ -20,9 +20,11 @@ package org.apache.servicecomb.saga.omega.transaction.spring;
 import org.apache.servicecomb.saga.omega.transaction.annotations.Compensable;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Component;
+import org.springframework.transaction.annotation.Transactional;
 
 @Component
-class TransactionalUserService {
+@Transactional
+public class TransactionalUserService {
   static final String ILLEGAL_USER = "Illegal User";
   private final UserRepository userRepository;
 
@@ -38,19 +40,19 @@ class TransactionalUserService {
   }
 
   @Compensable(compensationMethod = "delete")
-  User add(User user) {
+  public User add(User user) {
     if (ILLEGAL_USER.equals(user.username())) {
       throw new IllegalArgumentException("User is illegal");
     }
     return userRepository.save(user);
   }
 
-  void delete(User user) {
+  public void delete(User user) {
     userRepository.delete(user);
   }
 
   @Compensable(retries = 2, compensationMethod = "delete")
-  User add(User user, int count) {
+  public User add(User user, int count) {
     if (this.count < count) {
       this.count += 1;
       throw new IllegalStateException("Retry harder");
@@ -59,7 +61,7 @@ class TransactionalUserService {
     return userRepository.save(user);
   }
 
-  void delete(User user, int count) {
+  public void delete(User user, int count) {
     resetCount();
     userRepository.delete(user);
   }

Reply via email to