You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@servicecomb.apache.org by li...@apache.org on 2017/12/27 02:10:55 UTC

[incubator-servicecomb-java-chassis] 01/05: JAV-583 pojo consumer support return CompletableFuture

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

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

commit c94697ae22b703267cf8b893b780cf661a1456b8
Author: wujimin <wu...@huawei.com>
AuthorDate: Mon Dec 25 16:18:41 2017 +0800

    JAV-583 pojo consumer support return CompletableFuture
---
 .../java/io/servicecomb/provider/pojo/Invoker.java |  32 +++++-
 .../io/servicecomb/provider/pojo/TestInvoker.java  | 112 +++++++++++++++++++++
 2 files changed, 142 insertions(+), 2 deletions(-)

diff --git a/providers/provider-pojo/src/main/java/io/servicecomb/provider/pojo/Invoker.java b/providers/provider-pojo/src/main/java/io/servicecomb/provider/pojo/Invoker.java
index ba6ff40..14527b8 100644
--- a/providers/provider-pojo/src/main/java/io/servicecomb/provider/pojo/Invoker.java
+++ b/providers/provider-pojo/src/main/java/io/servicecomb/provider/pojo/Invoker.java
@@ -20,6 +20,7 @@ package io.servicecomb.provider.pojo;
 import java.lang.reflect.InvocationHandler;
 import java.lang.reflect.Method;
 import java.lang.reflect.Proxy;
+import java.util.concurrent.CompletableFuture;
 
 import org.springframework.util.StringUtils;
 
@@ -49,7 +50,7 @@ public class Invoker implements InvocationHandler {
 
   private ReferenceConfig referenceConfig;
 
-  private SwaggerConsumer swaggerConsumer;
+  private volatile SwaggerConsumer swaggerConsumer;
 
   @SuppressWarnings("unchecked")
   public static <T> T createProxy(String microserviceName, String schemaId, Class<?> consumerIntf) {
@@ -86,7 +87,11 @@ public class Invoker implements InvocationHandler {
   @Override
   public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
     if (swaggerConsumer == null) {
-      prepare();
+      synchronized (this) {
+        if (swaggerConsumer == null) {
+          prepare();
+        }
+      }
     }
 
     Invocation invocation =
@@ -95,6 +100,14 @@ public class Invoker implements InvocationHandler {
     SwaggerConsumerOperation consumerOperation = swaggerConsumer.findOperation(method.getName());
     consumerOperation.getArgumentsMapper().toInvocation(args, invocation);
 
+    if (CompletableFuture.class.equals(method.getReturnType())) {
+      return completableFutureInvoke(invocation, consumerOperation);
+    }
+
+    return syncInvoke(invocation, consumerOperation);
+  }
+
+  protected Object syncInvoke(Invocation invocation, SwaggerConsumerOperation consumerOperation) {
     Response response = InvokerUtils.innerSyncInvoke(invocation);
     if (response.isSuccessed()) {
       return consumerOperation.getResponseMapper().mapResponse(response);
@@ -102,4 +115,19 @@ public class Invoker implements InvocationHandler {
 
     throw ExceptionFactory.convertConsumerException(response.getResult());
   }
+
+  protected CompletableFuture<Object> completableFutureInvoke(Invocation invocation,
+      SwaggerConsumerOperation consumerOperation) {
+    CompletableFuture<Object> future = new CompletableFuture<>();
+    InvokerUtils.reactiveInvoke(invocation, response -> {
+      if (response.isSuccessed()) {
+        Object result = consumerOperation.getResponseMapper().mapResponse(response);
+        future.complete(result);
+        return;
+      }
+
+      future.completeExceptionally(response.getResult());
+    });
+    return future;
+  }
 }
diff --git a/providers/provider-pojo/src/test/java/io/servicecomb/provider/pojo/TestInvoker.java b/providers/provider-pojo/src/test/java/io/servicecomb/provider/pojo/TestInvoker.java
index ae47e3a..a9899bc 100644
--- a/providers/provider-pojo/src/test/java/io/servicecomb/provider/pojo/TestInvoker.java
+++ b/providers/provider-pojo/src/test/java/io/servicecomb/provider/pojo/TestInvoker.java
@@ -17,24 +17,42 @@
 
 package io.servicecomb.provider.pojo;
 
+import java.util.concurrent.CompletableFuture;
+
+import org.hamcrest.Matchers;
 import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
+import org.junit.rules.ExpectedException;
 
 import io.servicecomb.core.CseContext;
+import io.servicecomb.core.Invocation;
 import io.servicecomb.core.definition.MicroserviceMeta;
 import io.servicecomb.core.definition.schema.ConsumerSchemaFactory;
 import io.servicecomb.core.provider.consumer.ConsumerProviderManager;
+import io.servicecomb.core.provider.consumer.InvokerUtils;
 import io.servicecomb.core.provider.consumer.ReferenceConfig;
 import io.servicecomb.core.provider.consumer.ReferenceConfigUtils;
 import io.servicecomb.swagger.engine.SwaggerConsumer;
+import io.servicecomb.swagger.engine.SwaggerConsumerOperation;
 import io.servicecomb.swagger.engine.bootstrap.BootstrapNormal;
+import io.servicecomb.swagger.invocation.AsyncResponse;
+import io.servicecomb.swagger.invocation.Response;
+import io.servicecomb.swagger.invocation.exception.InvocationException;
+import io.servicecomb.swagger.invocation.response.consumer.ConsumerResponseMapper;
 import mockit.Deencapsulation;
 import mockit.Expectations;
 import mockit.Injectable;
+import mockit.Mock;
+import mockit.MockUp;
+import mockit.Mocked;
 
 public class TestInvoker {
+  @Rule
+  public ExpectedException expectedException = ExpectedException.none();
+
   @Before
   public void setup() {
     ReferenceConfigUtils.setReady(true);
@@ -138,4 +156,98 @@ public class TestInvoker {
     SwaggerConsumer swaggerConsumer = Deencapsulation.getField(invoker, "swaggerConsumer");
     Assert.assertEquals(IPerson.class, swaggerConsumer.getConsumerIntf());
   }
+
+  @Test
+  public void syncInvoke_normal(@Mocked Invocation invocation,
+      @Mocked SwaggerConsumerOperation consumerOperation,
+      @Mocked ConsumerResponseMapper mapper) {
+    Response response = Response.ok("1");
+    new MockUp<InvokerUtils>() {
+      @Mock
+      Response innerSyncInvoke(Invocation invocation) {
+        return response;
+      }
+    };
+    new Expectations() {
+      {
+        consumerOperation.getResponseMapper();
+        result = mapper;
+        mapper.mapResponse(response);
+        result = 1;
+      }
+    };
+
+    Invoker invoker = new Invoker("test", null, IPerson.class);
+    Object result = invoker.syncInvoke(invocation, consumerOperation);
+    Assert.assertEquals(1, result);
+  }
+
+  @Test
+  public void syncInvoke_failed(@Mocked Invocation invocation,
+      @Mocked SwaggerConsumerOperation consumerOperation,
+      @Mocked ConsumerResponseMapper mapper) {
+    Throwable error = new Error("failed");
+    Response response = Response.createConsumerFail(error);
+    new MockUp<InvokerUtils>() {
+      @Mock
+      Response innerSyncInvoke(Invocation invocation) {
+        return response;
+      }
+    };
+
+    expectedException.expect(InvocationException.class);
+    expectedException.expectCause(Matchers.sameInstance(error));
+
+    Invoker invoker = new Invoker("test", null, IPerson.class);
+    invoker.syncInvoke(invocation, consumerOperation);
+  }
+
+  @Test
+  public void completableFutureInvoke_normal(@Mocked Invocation invocation,
+      @Mocked SwaggerConsumerOperation consumerOperation,
+      @Mocked ConsumerResponseMapper mapper) {
+    Response response = Response.ok("1");
+    new MockUp<InvokerUtils>() {
+      @Mock
+      void reactiveInvoke(Invocation invocation, AsyncResponse asyncResp) {
+        asyncResp.handle(response);;
+      }
+    };
+    new Expectations() {
+      {
+        consumerOperation.getResponseMapper();
+        result = mapper;
+        mapper.mapResponse(response);
+        result = 1;
+      }
+    };
+
+    Invoker invoker = new Invoker("test", null, IPerson.class);
+    CompletableFuture<Object> future = invoker.completableFutureInvoke(invocation, consumerOperation);
+    future.whenComplete((result, ex) -> {
+      Assert.assertEquals(1, result);
+      Assert.assertEquals(null, ex);
+    });
+  }
+
+  @Test
+  public void completableFutureInvoke_failed(@Mocked Invocation invocation,
+      @Mocked SwaggerConsumerOperation consumerOperation,
+      @Mocked ConsumerResponseMapper mapper) {
+    Throwable error = new Error("failed");
+    Response response = Response.createConsumerFail(error);
+    new MockUp<InvokerUtils>() {
+      @Mock
+      void reactiveInvoke(Invocation invocation, AsyncResponse asyncResp) {
+        asyncResp.handle(response);;
+      }
+    };
+
+    Invoker invoker = new Invoker("test", null, IPerson.class);
+    CompletableFuture<Object> future = invoker.completableFutureInvoke(invocation, consumerOperation);
+    future.whenComplete((result, ex) -> {
+      Assert.assertEquals(null, result);
+      Assert.assertSame(error, ex);
+    });
+  }
 }

-- 
To stop receiving notification emails like this one, please contact
"commits@servicecomb.apache.org" <co...@servicecomb.apache.org>.