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/servicecomb-java-chassis.git


The following commit(s) were added to refs/heads/master by this push:
     new fdf972fc9 [SCB-2671]support beforeSendRequestAsync so that HttpClient 
filter ca… (#3291)
fdf972fc9 is described below

commit fdf972fc9a0e49c93562614414e5c6c52d55346b
Author: liubao68 <[email protected]>
AuthorDate: Sun Aug 21 22:21:01 2022 +0800

    [SCB-2671]support beforeSendRequestAsync so that HttpClient filter ca… 
(#3291)
---
 .../common/rest/filter/HttpClientFilter.java       | 27 ++++++-
 .../HttpClientFilterBeforeSendRequestExecutor.java | 92 ++++++++++++++++++++++
 .../common/rest/filter/HttpServerFilter.java       |  8 +-
 .../rest/filter/inner/ClientRestArgsFilter.java    | 11 ++-
 .../common/rest/TestAbstractRestInvocation.java    |  1 +
 .../rest/filter/HttpClientFilterBaseForTest.java}  | 24 +++---
 .../common/rest/filter/TestHttpClientFilter.java}  | 28 +++----
 .../common/rest/filter/TestHttpServerFilter.java   |  1 +
 .../org/apache/servicecomb/core/SCBEngine.java     |  2 +-
 .../filter/EdgeSignatureResponseFilter.java        |  9 ++-
 .../jaxrs/server/JaxrsDemoHttpServerFilter.java    |  1 +
 .../demo/signature/ClientSignature.java            |  5 +-
 .../demo/signature/ServerSignature.java            |  1 +
 .../edge/core/EdgeAddHeaderClientFilter.java       |  4 +-
 .../filter/EdgeSignatureResponseFilter.java        |  8 +-
 .../reference/RestTemplateCopyHeaderFilter.java    |  7 +-
 .../TestRestTemplateCopyHeaderFilter.java          | 20 +++--
 .../rest/client/http/DefaultHttpClientFilter.java  |  6 --
 .../rest/client/http/RestClientInvocation.java     | 46 ++++++-----
 19 files changed, 223 insertions(+), 78 deletions(-)

diff --git 
a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/filter/HttpClientFilter.java
 
b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/filter/HttpClientFilter.java
index a139712c1..9fe6d1b57 100644
--- 
a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/filter/HttpClientFilter.java
+++ 
b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/filter/HttpClientFilter.java
@@ -17,6 +17,8 @@
 
 package org.apache.servicecomb.common.rest.filter;
 
+import java.util.concurrent.CompletableFuture;
+
 import org.apache.servicecomb.core.Invocation;
 import org.apache.servicecomb.foundation.vertx.http.HttpServletRequestEx;
 import org.apache.servicecomb.foundation.vertx.http.HttpServletResponseEx;
@@ -29,7 +31,30 @@ public interface HttpClientFilter {
 
   int getOrder();
 
-  void beforeSendRequest(Invocation invocation, HttpServletRequestEx 
requestEx);
+  /**
+   * callback method before send a client request.
+   *
+   * @Deprecated this method may be called in an event-loop thread, do not add 
blocking
+   * methods. Implement #beforeSendRequestAsync instead.
+   */
+  @Deprecated
+  default void beforeSendRequest(Invocation invocation, HttpServletRequestEx 
requestEx) {
+
+  }
+
+  /**
+   *  callback method before send a client request.
+   */
+  default CompletableFuture<Void> beforeSendRequestAsync(Invocation 
invocation, HttpServletRequestEx requestEx) {
+    CompletableFuture<Void> future = new CompletableFuture<>();
+    try {
+      beforeSendRequest(invocation, requestEx);
+      future.complete(null);
+    } catch (Throwable e) {
+      future.completeExceptionally(e);
+    }
+    return future;
+  }
 
   // if finished, then return a none null response
   // if return a null response, then sdk will call next filter.afterReceive
diff --git 
a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/filter/HttpClientFilterBeforeSendRequestExecutor.java
 
b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/filter/HttpClientFilterBeforeSendRequestExecutor.java
new file mode 100644
index 000000000..eab621712
--- /dev/null
+++ 
b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/filter/HttpClientFilterBeforeSendRequestExecutor.java
@@ -0,0 +1,92 @@
+/*
+ * 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.servicecomb.common.rest.filter;
+
+import java.util.List;
+import java.util.concurrent.CompletableFuture;
+
+import org.apache.servicecomb.core.Invocation;
+import org.apache.servicecomb.foundation.vertx.http.HttpServletRequestEx;
+
+public class HttpClientFilterBeforeSendRequestExecutor {
+  private final List<HttpClientFilter> httpClientFilters;
+
+  private final Invocation invocation;
+
+  private final HttpServletRequestEx requestEx;
+
+  private int currentIndex;
+
+  private final CompletableFuture<Void> future = new CompletableFuture<>();
+
+  public HttpClientFilterBeforeSendRequestExecutor(List<HttpClientFilter> 
httpClientFilters, Invocation invocation,
+      HttpServletRequestEx requestEx) {
+    this.httpClientFilters = httpClientFilters;
+    this.invocation = invocation;
+    this.requestEx = requestEx;
+  }
+
+  public CompletableFuture<Void> run() {
+    doRun();
+
+    return future;
+  }
+
+  protected CompletableFuture<Void> safeInvoke(HttpClientFilter 
httpClientFilter) {
+    try {
+      if (httpClientFilter.enabled()) {
+        CompletableFuture<Void> future = 
httpClientFilter.beforeSendRequestAsync(invocation, requestEx);
+        if (future == null) {
+          future = new CompletableFuture<>();
+          future.completeExceptionally(new IllegalStateException(
+              "HttpClientFilter beforeSendRequestAsync can not return null, do 
not override it. Class="
+                  + httpClientFilter.getClass()
+                  .getName()));
+        }
+        return future;
+      } else {
+        CompletableFuture<Void> eFuture = new CompletableFuture<>();
+        eFuture.complete(null);
+        return eFuture;
+      }
+    } catch (Throwable e) {
+      CompletableFuture<Void> eFuture = new CompletableFuture<>();
+      eFuture.completeExceptionally(e);
+      return eFuture;
+    }
+  }
+
+  protected void doRun() {
+    if (currentIndex == httpClientFilters.size()) {
+      future.complete(null);
+      return;
+    }
+
+    HttpClientFilter httpServerFilter = httpClientFilters.get(currentIndex);
+    currentIndex++;
+
+    CompletableFuture<Void> stepFuture = safeInvoke(httpServerFilter);
+    stepFuture.whenComplete((v, e) -> {
+      if (e == null) {
+        doRun();
+        return;
+      }
+
+      future.completeExceptionally(e);
+    });
+  }
+}
diff --git 
a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/filter/HttpServerFilter.java
 
b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/filter/HttpServerFilter.java
index b809660a4..639bd5531 100644
--- 
a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/filter/HttpServerFilter.java
+++ 
b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/filter/HttpServerFilter.java
@@ -43,7 +43,7 @@ public interface HttpServerFilter {
   Response afterReceiveRequest(Invocation invocation, HttpServletRequestEx 
requestEx);
 
   /**
-   * @param invocation maybe null
+   * callback method before send a server response.
    */
   default CompletableFuture<Void> beforeSendResponseAsync(Invocation 
invocation, HttpServletResponseEx responseEx) {
     CompletableFuture<Void> future = new CompletableFuture<>();
@@ -57,8 +57,12 @@ public interface HttpServerFilter {
   }
 
   /**
-   * @param invocation maybe null
+   * callback method before send a server response.
+   *
+   * @Deprecated this method may be called in an event-loop thread, do not add 
blocking
+   * methods. Implement #beforeSendResponseAsync instead.
    */
+  @Deprecated
   default void beforeSendResponse(Invocation invocation, HttpServletResponseEx 
responseEx) {
 
   }
diff --git 
a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/filter/inner/ClientRestArgsFilter.java
 
b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/filter/inner/ClientRestArgsFilter.java
index 8babd9701..a53283343 100644
--- 
a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/filter/inner/ClientRestArgsFilter.java
+++ 
b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/filter/inner/ClientRestArgsFilter.java
@@ -17,6 +17,8 @@
 
 package org.apache.servicecomb.common.rest.filter.inner;
 
+import java.util.concurrent.CompletableFuture;
+
 import org.apache.servicecomb.common.rest.RestConst;
 import org.apache.servicecomb.common.rest.codec.RestCodec;
 import org.apache.servicecomb.common.rest.codec.param.RestClientRequestImpl;
@@ -27,7 +29,6 @@ import org.apache.servicecomb.core.definition.OperationMeta;
 import org.apache.servicecomb.foundation.vertx.http.HttpServletRequestEx;
 import org.apache.servicecomb.foundation.vertx.http.HttpServletResponseEx;
 import org.apache.servicecomb.swagger.invocation.Response;
-import org.apache.servicecomb.swagger.invocation.exception.ExceptionFactory;
 
 public class ClientRestArgsFilter implements HttpClientFilter {
 
@@ -37,8 +38,8 @@ public class ClientRestArgsFilter implements HttpClientFilter 
{
   }
 
   @Override
-  @SuppressWarnings("unchecked")
-  public void beforeSendRequest(Invocation invocation, HttpServletRequestEx 
requestEx) {
+  public CompletableFuture<Void> beforeSendRequestAsync(Invocation invocation, 
HttpServletRequestEx requestEx) {
+    CompletableFuture<Void> result = new CompletableFuture<>();
     RestClientRequestImpl restClientRequest = (RestClientRequestImpl) 
invocation.getHandlerContext()
         .get(RestConst.INVOCATION_HANDLER_REQUESTCLIENT);
     OperationMeta operationMeta = invocation.getOperationMeta();
@@ -47,9 +48,11 @@ public class ClientRestArgsFilter implements 
HttpClientFilter {
       RestCodec.argsToRest(invocation.getSwaggerArguments(), 
swaggerRestOperation,
           restClientRequest);
       requestEx.setBodyBuffer(restClientRequest.getBodyBuffer());
+      result.complete(null);
     } catch (Throwable e) {
-      throw ExceptionFactory.convertConsumerException(e);
+      result.completeExceptionally(e);
     }
+    return result;
   }
 
   @Override
diff --git 
a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/TestAbstractRestInvocation.java
 
b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/TestAbstractRestInvocation.java
index 0b7734dd5..75728a31c 100644
--- 
a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/TestAbstractRestInvocation.java
+++ 
b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/TestAbstractRestInvocation.java
@@ -85,6 +85,7 @@ import org.junit.jupiter.api.Test;
 import org.mockito.MockedStatic;
 import org.mockito.Mockito;
 
+@SuppressWarnings("deprecation")
 public class TestAbstractRestInvocation {
 
   HttpServletRequestEx requestEx = Mockito.mock(HttpServletRequestEx.class);
diff --git 
a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/filter/HttpClientFilter.java
 
b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/filter/HttpClientFilterBaseForTest.java
similarity index 71%
copy from 
common/common-rest/src/main/java/org/apache/servicecomb/common/rest/filter/HttpClientFilter.java
copy to 
common/common-rest/src/test/java/org/apache/servicecomb/common/rest/filter/HttpClientFilterBaseForTest.java
index a139712c1..7903b199e 100644
--- 
a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/filter/HttpClientFilter.java
+++ 
b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/filter/HttpClientFilterBaseForTest.java
@@ -14,24 +14,28 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
 package org.apache.servicecomb.common.rest.filter;
 
+import java.util.concurrent.CompletableFuture;
+
 import org.apache.servicecomb.core.Invocation;
 import org.apache.servicecomb.foundation.vertx.http.HttpServletRequestEx;
 import org.apache.servicecomb.foundation.vertx.http.HttpServletResponseEx;
 import org.apache.servicecomb.swagger.invocation.Response;
 
-public interface HttpClientFilter {
-  default boolean enabled() {
-    return true;
+public class HttpClientFilterBaseForTest implements HttpClientFilter {
+  @Override
+  public int getOrder() {
+    return 0;
   }
 
-  int getOrder();
-
-  void beforeSendRequest(Invocation invocation, HttpServletRequestEx 
requestEx);
+  @Override
+  public CompletableFuture<Void> beforeSendRequestAsync(Invocation invocation, 
HttpServletRequestEx requestEx) {
+    return null;
+  }
 
-  // if finished, then return a none null response
-  // if return a null response, then sdk will call next filter.afterReceive
-  Response afterReceiveResponse(Invocation invocation, HttpServletResponseEx 
responseEx);
+  @Override
+  public Response afterReceiveResponse(Invocation invocation, 
HttpServletResponseEx responseEx) {
+    return null;
+  }
 }
diff --git 
a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/filter/HttpClientFilter.java
 
b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/filter/TestHttpClientFilter.java
similarity index 56%
copy from 
common/common-rest/src/main/java/org/apache/servicecomb/common/rest/filter/HttpClientFilter.java
copy to 
common/common-rest/src/test/java/org/apache/servicecomb/common/rest/filter/TestHttpClientFilter.java
index a139712c1..afc788b92 100644
--- 
a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/filter/HttpClientFilter.java
+++ 
b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/filter/TestHttpClientFilter.java
@@ -14,24 +14,20 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
 package org.apache.servicecomb.common.rest.filter;
 
-import org.apache.servicecomb.core.Invocation;
-import org.apache.servicecomb.foundation.vertx.http.HttpServletRequestEx;
-import org.apache.servicecomb.foundation.vertx.http.HttpServletResponseEx;
-import org.apache.servicecomb.swagger.invocation.Response;
-
-public interface HttpClientFilter {
-  default boolean enabled() {
-    return true;
-  }
+import java.util.Arrays;
+import java.util.concurrent.ExecutionException;
 
-  int getOrder();
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
 
-  void beforeSendRequest(Invocation invocation, HttpServletRequestEx 
requestEx);
-
-  // if finished, then return a none null response
-  // if return a null response, then sdk will call next filter.afterReceive
-  Response afterReceiveResponse(Invocation invocation, HttpServletResponseEx 
responseEx);
+public class TestHttpClientFilter {
+  @Test
+  public void asyncFailed() {
+    HttpClientFilter filter = new HttpClientFilterBaseForTest();
+    HttpClientFilterBeforeSendRequestExecutor executor =
+        new HttpClientFilterBeforeSendRequestExecutor(Arrays.asList(filter), 
null, null);
+    Assertions.assertThrows(ExecutionException.class, () -> 
executor.run().get());
+  }
 }
diff --git 
a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/filter/TestHttpServerFilter.java
 
b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/filter/TestHttpServerFilter.java
index 584a35aaa..37449a3dc 100644
--- 
a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/filter/TestHttpServerFilter.java
+++ 
b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/filter/TestHttpServerFilter.java
@@ -39,6 +39,7 @@ public class TestHttpServerFilter {
   public void asyncFailed() throws InterruptedException, ExecutionException {
     HttpServerFilter filter = new HttpServerFilterBaseForTest() {
       @Override
+      @SuppressWarnings("deprecation")
       public void beforeSendResponse(Invocation invocation, 
HttpServletResponseEx responseEx) {
         throw new RuntimeExceptionWithoutStackTrace();
       }
diff --git a/core/src/main/java/org/apache/servicecomb/core/SCBEngine.java 
b/core/src/main/java/org/apache/servicecomb/core/SCBEngine.java
index 10c443bbc..ea2a539ad 100644
--- a/core/src/main/java/org/apache/servicecomb/core/SCBEngine.java
+++ b/core/src/main/java/org/apache/servicecomb/core/SCBEngine.java
@@ -493,7 +493,7 @@ public class SCBEngine {
     long start = System.currentTimeMillis();
     while (true) {
       long remaining = invocationStartedCounter.get() - 
invocationFinishedCounter.get();
-      if (remaining == 0) {
+      if (remaining <= 0) {
         return;
       }
 
diff --git 
a/demo/demo-edge/edge-service/src/main/java/org/apache/servicecomb/demo/edge/service/encrypt/filter/EdgeSignatureResponseFilter.java
 
b/demo/demo-edge/edge-service/src/main/java/org/apache/servicecomb/demo/edge/service/encrypt/filter/EdgeSignatureResponseFilter.java
index 4d9a3805b..87d3e21df 100644
--- 
a/demo/demo-edge/edge-service/src/main/java/org/apache/servicecomb/demo/edge/service/encrypt/filter/EdgeSignatureResponseFilter.java
+++ 
b/demo/demo-edge/edge-service/src/main/java/org/apache/servicecomb/demo/edge/service/encrypt/filter/EdgeSignatureResponseFilter.java
@@ -17,6 +17,7 @@
 package org.apache.servicecomb.demo.edge.service.encrypt.filter;
 
 import java.nio.charset.StandardCharsets;
+import java.util.concurrent.CompletableFuture;
 
 import org.apache.servicecomb.common.rest.filter.HttpServerFilter;
 import org.apache.servicecomb.core.Invocation;
@@ -48,14 +49,14 @@ public class EdgeSignatureResponseFilter implements 
HttpServerFilter {
   }
 
   @Override
-  public void beforeSendResponse(Invocation invocation, HttpServletResponseEx 
responseEx) {
+  public CompletableFuture<Void> beforeSendResponseAsync(Invocation 
invocation, HttpServletResponseEx responseEx) {
     if (invocation == null) {
-      return;
+      return CompletableFuture.completedFuture(null);
     }
 
     EncryptContext encryptContext = (EncryptContext) 
invocation.getHandlerContext().get(EdgeConst.ENCRYPT_CONTEXT);
     if (encryptContext == null) {
-      return;
+      return CompletableFuture.completedFuture(null);
     }
     Hcr hcr = encryptContext.getHcr();
 
@@ -72,5 +73,7 @@ public class EdgeSignatureResponseFilter implements 
HttpServerFilter {
       body = body.substring(0, body.length() - 1) + ",\"signature\":\"" + 
signature + "\"}";
       responseEx.setBodyBuffer(Buffer.buffer(body));
     }
+
+    return CompletableFuture.completedFuture(null);
   }
 }
diff --git 
a/demo/demo-jaxrs/jaxrs-server/src/main/java/org/apache/servicecomb/demo/jaxrs/server/JaxrsDemoHttpServerFilter.java
 
b/demo/demo-jaxrs/jaxrs-server/src/main/java/org/apache/servicecomb/demo/jaxrs/server/JaxrsDemoHttpServerFilter.java
index 025847445..e89d3daca 100644
--- 
a/demo/demo-jaxrs/jaxrs-server/src/main/java/org/apache/servicecomb/demo/jaxrs/server/JaxrsDemoHttpServerFilter.java
+++ 
b/demo/demo-jaxrs/jaxrs-server/src/main/java/org/apache/servicecomb/demo/jaxrs/server/JaxrsDemoHttpServerFilter.java
@@ -39,6 +39,7 @@ public class JaxrsDemoHttpServerFilter implements 
HttpServerFilter {
   }
 
   @Override
+  @SuppressWarnings("deprecation")
   public void beforeSendResponse(Invocation invocation, HttpServletResponseEx 
responseEx) {
     // in 404 situation, invocation is null and a NPE is thrown
     LOGGER.info("JaxrsDemoHttpServerFilter is called, operation=[{}]", 
invocation.getOperationName());
diff --git 
a/demo/demo-signature/src/main/java/org/apache/servicecomb/demo/signature/ClientSignature.java
 
b/demo/demo-signature/src/main/java/org/apache/servicecomb/demo/signature/ClientSignature.java
index aa715d2bc..84bbe6713 100644
--- 
a/demo/demo-signature/src/main/java/org/apache/servicecomb/demo/signature/ClientSignature.java
+++ 
b/demo/demo-signature/src/main/java/org/apache/servicecomb/demo/signature/ClientSignature.java
@@ -17,6 +17,8 @@
 
 package org.apache.servicecomb.demo.signature;
 
+import java.util.concurrent.CompletableFuture;
+
 import javax.ws.rs.core.Response.Status;
 
 import org.apache.servicecomb.common.rest.filter.HttpClientFilter;
@@ -36,9 +38,10 @@ public class ClientSignature implements HttpClientFilter {
   }
 
   @Override
-  public void beforeSendRequest(Invocation invocation, HttpServletRequestEx 
requestEx) {
+  public CompletableFuture<Void> beforeSendRequestAsync(Invocation invocation, 
HttpServletRequestEx requestEx) {
     String signature = SignatureUtils.genSignature(requestEx);
     requestEx.setHeader("signature", signature);
+    return CompletableFuture.completedFuture(null);
   }
 
   @Override
diff --git 
a/demo/demo-signature/src/main/java/org/apache/servicecomb/demo/signature/ServerSignature.java
 
b/demo/demo-signature/src/main/java/org/apache/servicecomb/demo/signature/ServerSignature.java
index 8f6e181d3..1b623c35c 100644
--- 
a/demo/demo-signature/src/main/java/org/apache/servicecomb/demo/signature/ServerSignature.java
+++ 
b/demo/demo-signature/src/main/java/org/apache/servicecomb/demo/signature/ServerSignature.java
@@ -57,6 +57,7 @@ public class ServerSignature implements HttpServerFilter {
   }
 
   @Override
+  @SuppressWarnings("deprecation")
   public void beforeSendResponse(Invocation invocation, HttpServletResponseEx 
responseEx) {
     String signature = SignatureUtils.genSignature(responseEx);
     responseEx.addHeader("signature", signature);
diff --git 
a/edge/edge-core/src/main/java/org/apache/servicecomb/edge/core/EdgeAddHeaderClientFilter.java
 
b/edge/edge-core/src/main/java/org/apache/servicecomb/edge/core/EdgeAddHeaderClientFilter.java
index c31539390..49258fab9 100644
--- 
a/edge/edge-core/src/main/java/org/apache/servicecomb/edge/core/EdgeAddHeaderClientFilter.java
+++ 
b/edge/edge-core/src/main/java/org/apache/servicecomb/edge/core/EdgeAddHeaderClientFilter.java
@@ -19,6 +19,7 @@ package org.apache.servicecomb.edge.core;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
+import java.util.concurrent.CompletableFuture;
 import java.util.function.BiConsumer;
 
 import org.apache.commons.lang3.StringUtils;
@@ -77,8 +78,9 @@ public class EdgeAddHeaderClientFilter implements 
HttpClientFilter {
   }
 
   @Override
-  public void beforeSendRequest(Invocation invocation, HttpServletRequestEx 
requestEx) {
+  public CompletableFuture<Void> beforeSendRequestAsync(Invocation invocation, 
HttpServletRequestEx requestEx) {
     addHeaders(invocation, requestEx::addHeader);
+    return CompletableFuture.completedFuture(null);
   }
 
   public void addHeaders(Invocation invocation, BiConsumer<String, String> 
headerAdder) {
diff --git 
a/integration-tests/it-edge/src/main/java/org/apache/servicecomb/it/edge/encrypt/filter/EdgeSignatureResponseFilter.java
 
b/integration-tests/it-edge/src/main/java/org/apache/servicecomb/it/edge/encrypt/filter/EdgeSignatureResponseFilter.java
index b62513574..281b11272 100644
--- 
a/integration-tests/it-edge/src/main/java/org/apache/servicecomb/it/edge/encrypt/filter/EdgeSignatureResponseFilter.java
+++ 
b/integration-tests/it-edge/src/main/java/org/apache/servicecomb/it/edge/encrypt/filter/EdgeSignatureResponseFilter.java
@@ -17,6 +17,7 @@
 package org.apache.servicecomb.it.edge.encrypt.filter;
 
 import java.nio.charset.StandardCharsets;
+import java.util.concurrent.CompletableFuture;
 
 import org.apache.servicecomb.common.rest.filter.HttpServerFilter;
 import org.apache.servicecomb.core.Invocation;
@@ -48,14 +49,14 @@ public class EdgeSignatureResponseFilter implements 
HttpServerFilter {
   }
 
   @Override
-  public void beforeSendResponse(Invocation invocation, HttpServletResponseEx 
responseEx) {
+  public CompletableFuture<Void> beforeSendResponseAsync(Invocation 
invocation, HttpServletResponseEx responseEx) {
     if (invocation == null) {
-      return;
+      return CompletableFuture.completedFuture(null);
     }
 
     EncryptContext encryptContext = (EncryptContext) 
invocation.getHandlerContext().get(EdgeConst.ENCRYPT_CONTEXT);
     if (encryptContext == null) {
-      return;
+      return CompletableFuture.completedFuture(null);
     }
     Hcr hcr = encryptContext.getHcr();
 
@@ -72,5 +73,6 @@ public class EdgeSignatureResponseFilter implements 
HttpServerFilter {
       body = body.substring(0, body.length() - 1) + ",\"signature\":\"" + 
signature + "\"}";
       responseEx.setBodyBuffer(Buffer.buffer(body));
     }
+    return CompletableFuture.completedFuture(null);
   }
 }
diff --git 
a/providers/provider-springmvc/src/main/java/org/apache/servicecomb/provider/springmvc/reference/RestTemplateCopyHeaderFilter.java
 
b/providers/provider-springmvc/src/main/java/org/apache/servicecomb/provider/springmvc/reference/RestTemplateCopyHeaderFilter.java
index c37a3c352..e8b674d2d 100644
--- 
a/providers/provider-springmvc/src/main/java/org/apache/servicecomb/provider/springmvc/reference/RestTemplateCopyHeaderFilter.java
+++ 
b/providers/provider-springmvc/src/main/java/org/apache/servicecomb/provider/springmvc/reference/RestTemplateCopyHeaderFilter.java
@@ -17,6 +17,8 @@
 
 package org.apache.servicecomb.provider.springmvc.reference;
 
+import java.util.concurrent.CompletableFuture;
+
 import org.apache.servicecomb.common.rest.RestConst;
 import org.apache.servicecomb.common.rest.filter.HttpClientFilter;
 import org.apache.servicecomb.core.Invocation;
@@ -36,10 +38,10 @@ public class RestTemplateCopyHeaderFilter implements 
HttpClientFilter {
   }
 
   @Override
-  public void beforeSendRequest(Invocation invocation, HttpServletRequestEx 
requestEx) {
+  public CompletableFuture<Void> beforeSendRequestAsync(Invocation invocation, 
HttpServletRequestEx requestEx) {
     HttpHeaders httpHeaders = (HttpHeaders) 
invocation.getHandlerContext().get(RestConst.CONSUMER_HEADER);
     if (httpHeaders == null) {
-      return;
+      return CompletableFuture.completedFuture(null);
     }
 
     httpHeaders.forEach((key, values) -> {
@@ -57,6 +59,7 @@ public class RestTemplateCopyHeaderFilter implements 
HttpClientFilter {
         requestEx.addHeader(key, value);
       }
     });
+    return CompletableFuture.completedFuture(null);
   }
 
   @Override
diff --git 
a/providers/provider-springmvc/src/test/java/org/apache/servicecomb/provider/springmvc/reference/TestRestTemplateCopyHeaderFilter.java
 
b/providers/provider-springmvc/src/test/java/org/apache/servicecomb/provider/springmvc/reference/TestRestTemplateCopyHeaderFilter.java
index e94bb9f9d..7e02c75ea 100644
--- 
a/providers/provider-springmvc/src/test/java/org/apache/servicecomb/provider/springmvc/reference/TestRestTemplateCopyHeaderFilter.java
+++ 
b/providers/provider-springmvc/src/test/java/org/apache/servicecomb/provider/springmvc/reference/TestRestTemplateCopyHeaderFilter.java
@@ -20,6 +20,7 @@ package org.apache.servicecomb.provider.springmvc.reference;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.Map;
+import java.util.concurrent.ExecutionException;
 
 import org.apache.servicecomb.common.rest.RestConst;
 import org.apache.servicecomb.core.Invocation;
@@ -42,7 +43,7 @@ public class TestRestTemplateCopyHeaderFilter {
   }
 
   @Test
-  public void beforeSendRequestNoHeader(@Mocked Invocation invocation) {
+  public void beforeSendRequestNoHeader(@Mocked Invocation invocation) throws 
ExecutionException, InterruptedException {
     Map<String, Object> context = new HashMap<>();
     new Expectations() {
       {
@@ -52,12 +53,13 @@ public class TestRestTemplateCopyHeaderFilter {
     };
 
     HttpServletRequestEx requestEx = new CommonToHttpServletRequest(null, 
null, new HttpHeaders(), null, false);
-    filter.beforeSendRequest(invocation, requestEx);
+    filter.beforeSendRequestAsync(invocation, requestEx).get();
     Assertions.assertFalse(requestEx.getHeaderNames().hasMoreElements());
   }
 
   @Test
-  public void beforeSendRequestWithNullHeader(@Mocked Invocation invocation) {
+  public void beforeSendRequestWithNullHeader(@Mocked Invocation invocation)
+      throws ExecutionException, InterruptedException {
     Map<String, Object> context = new HashMap<>(1);
     HttpHeaders httpHeaders = new HttpHeaders();
     context.put(RestConst.CONSUMER_HEADER, httpHeaders);
@@ -72,14 +74,15 @@ public class TestRestTemplateCopyHeaderFilter {
     };
 
     HttpServletRequestEx requestEx = new CommonToHttpServletRequest(null, 
null, new HttpHeaders(), null, false);
-    filter.beforeSendRequest(invocation, requestEx);
+    filter.beforeSendRequestAsync(invocation, requestEx).get();
     Assertions.assertEquals("headerValue0", 
requestEx.getHeader("headerName0"));
     Assertions.assertEquals("headerValue2", 
requestEx.getHeader("headerName2"));
     Assertions.assertNull(requestEx.getHeader("headerName1"));
   }
 
   @Test
-  public void beforeSendRequestHaveHeader(@Mocked Invocation invocation) {
+  public void beforeSendRequestHaveHeader(@Mocked Invocation invocation)
+      throws ExecutionException, InterruptedException {
     HttpHeaders httpHeaders = new HttpHeaders();
     httpHeaders.add("name", "value");
 
@@ -93,12 +96,13 @@ public class TestRestTemplateCopyHeaderFilter {
     };
 
     HttpServletRequestEx requestEx = new CommonToHttpServletRequest(null, 
null, new HttpHeaders(), null, false);
-    filter.beforeSendRequest(invocation, requestEx);
+    filter.beforeSendRequestAsync(invocation, requestEx).get();
     MatcherAssert.assertThat(Collections.list(requestEx.getHeaders("name")), 
Matchers.contains("value"));
   }
 
   @Test
-  public void beforeSendRequestSkipContentLength(@Mocked Invocation 
invocation) {
+  public void beforeSendRequestSkipContentLength(@Mocked Invocation invocation)
+      throws ExecutionException, InterruptedException {
     HttpHeaders httpHeaders = new HttpHeaders();
     httpHeaders.add(HttpHeaders.CONTENT_LENGTH, "0");
 
@@ -112,7 +116,7 @@ public class TestRestTemplateCopyHeaderFilter {
     };
 
     HttpServletRequestEx requestEx = new CommonToHttpServletRequest(null, 
null, new HttpHeaders(), null, false);
-    filter.beforeSendRequest(invocation, requestEx);
+    filter.beforeSendRequestAsync(invocation, requestEx).get();
     Assertions.assertNull((requestEx.getHeader(HttpHeaders.CONTENT_LENGTH)));
   }
 
diff --git 
a/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/http/DefaultHttpClientFilter.java
 
b/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/http/DefaultHttpClientFilter.java
index d41b15668..30cc9b74d 100644
--- 
a/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/http/DefaultHttpClientFilter.java
+++ 
b/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/http/DefaultHttpClientFilter.java
@@ -28,7 +28,6 @@ import 
org.apache.servicecomb.common.rest.definition.RestOperationMeta;
 import org.apache.servicecomb.common.rest.filter.HttpClientFilter;
 import org.apache.servicecomb.core.Invocation;
 import org.apache.servicecomb.core.definition.OperationMeta;
-import org.apache.servicecomb.foundation.vertx.http.HttpServletRequestEx;
 import org.apache.servicecomb.foundation.vertx.http.HttpServletResponseEx;
 import org.apache.servicecomb.swagger.invocation.Response;
 import org.apache.servicecomb.swagger.invocation.context.HttpStatus;
@@ -56,11 +55,6 @@ public class DefaultHttpClientFilter implements 
HttpClientFilter {
     return enabled;
   }
 
-  @Override
-  public void beforeSendRequest(Invocation invocation, HttpServletRequestEx 
requestEx) {
-
-  }
-
   protected ProduceProcessor findProduceProcessor(RestOperationMeta 
restOperation,
       HttpServletResponseEx responseEx) {
     String contentType = responseEx.getHeader(HttpHeaders.CONTENT_TYPE);
diff --git 
a/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/http/RestClientInvocation.java
 
b/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/http/RestClientInvocation.java
index 18339c153..6ddf1e23b 100644
--- 
a/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/http/RestClientInvocation.java
+++ 
b/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/http/RestClientInvocation.java
@@ -18,6 +18,7 @@
 package org.apache.servicecomb.transport.rest.client.http;
 
 import java.util.List;
+import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.TimeoutException;
 
 import javax.ws.rs.core.Response.Status;
@@ -27,6 +28,7 @@ import org.apache.servicecomb.common.rest.RestConst;
 import org.apache.servicecomb.common.rest.codec.param.RestClientRequestImpl;
 import org.apache.servicecomb.common.rest.definition.RestOperationMeta;
 import org.apache.servicecomb.common.rest.filter.HttpClientFilter;
+import 
org.apache.servicecomb.common.rest.filter.HttpClientFilterBeforeSendRequestExecutor;
 import org.apache.servicecomb.core.Const;
 import org.apache.servicecomb.core.Invocation;
 import org.apache.servicecomb.core.definition.OperationConfig;
@@ -121,28 +123,25 @@ public class RestClientInvocation {
       }
       HttpServletRequestEx requestEx = new 
VertxClientRequestToHttpServletRequest(clientRequest, requestBodyBuffer);
       invocation.getInvocationStageTrace().startClientFiltersRequest();
-      for (HttpClientFilter filter : httpClientFilters) {
-        if (filter.enabled()) {
-          filter.beforeSendRequest(invocation, requestEx);
-        }
-      }
 
-      // 从业务线程转移到网络线程中去发送
-      invocation.onStartSendRequest();
-      httpClientWithContext.runOnContext(httpClient -> {
-        
clientRequest.setTimeout(operationMeta.getConfig().getMsRequestTimeout());
-        clientRequest.response().onComplete(asyncResult -> {
-          if (asyncResult.failed()) {
-            fail(asyncResult.cause());
-            return;
-          }
-          handleResponse(asyncResult.result());
+      return 
Future.fromCompletionStage(executeHttpClientFilters(requestEx).thenCompose((v) 
-> {
+        // 从业务线程转移到网络线程中去发送
+        invocation.onStartSendRequest();
+        httpClientWithContext.runOnContext(httpClient -> {
+          
clientRequest.setTimeout(operationMeta.getConfig().getMsRequestTimeout());
+          clientRequest.response().onComplete(asyncResult -> {
+            if (asyncResult.failed()) {
+              fail(asyncResult.cause());
+              return;
+            }
+            handleResponse(asyncResult.result());
+          });
+          processServiceCombHeaders(invocation, operationMeta);
+          restClientRequest.end()
+              .onComplete((t) -> 
invocation.getInvocationStageTrace().finishWriteToBuffer(System.nanoTime()));
         });
-        processServiceCombHeaders(invocation, operationMeta);
-        restClientRequest.end()
-            .onComplete((t) -> 
invocation.getInvocationStageTrace().finishWriteToBuffer(System.nanoTime()));
-      });
-      return Future.succeededFuture();
+        return CompletableFuture.completedFuture((Void) null);
+      }));
     }).onFailure(failure -> {
       invocation.getTraceIdLogger()
           .error(LOGGER, "Failed to send request, alreadyFailed:{}, local:{}, 
remote:{}, message={}.",
@@ -152,6 +151,13 @@ public class RestClientInvocation {
     });
   }
 
+  private CompletableFuture<Void> 
executeHttpClientFilters(HttpServletRequestEx requestEx) {
+    HttpClientFilterBeforeSendRequestExecutor exec =
+        new HttpClientFilterBeforeSendRequestExecutor(httpClientFilters, 
invocation, requestEx);
+    return exec.run();
+  }
+
+
   /**
    * If this is a 3rd party invocation, ServiceComb related headers should be 
removed by default to hide inner
    * implementation. Otherwise, the InvocationContext will be set into the 
request headers.

Reply via email to