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 ab08edf  [SCB-2141] add RestClientTransportContext (#2097)
ab08edf is described below

commit ab08edfb372c30a9c1b8e47bbd1cad53ae501bdf
Author: wujimin <[email protected]>
AuthorDate: Thu Dec 3 20:48:10 2020 +0800

    [SCB-2141] add RestClientTransportContext (#2097)
---
 .../servicecomb/demo/jaxrs/client/JaxrsClient.java |   1 -
 .../transport-rest/transport-rest-client/pom.xml   |  10 ++
 .../transport/rest/client/BoundaryFactory.java     |  30 ++++
 .../rest/client/RestClientExceptionCodes.java      |  21 +++
 .../rest/client/RestClientRequestParameters.java   |  50 ++++++
 .../client/RestClientRequestParametersImpl.java    | 136 +++++++++++++++++
 .../rest/client/RestClientTransportContext.java    |  85 +++++++++++
 .../client/RestClientTransportContextFactory.java  | 105 +++++++++++++
 .../RestClientTransportContextFactoryTest.java     | 168 +++++++++++++++++++++
 .../rest/client/RestFeatureController.java         |  32 ++++
 10 files changed, 637 insertions(+), 1 deletion(-)

diff --git 
a/demo/demo-jaxrs/jaxrs-client/src/main/java/org/apache/servicecomb/demo/jaxrs/client/JaxrsClient.java
 
b/demo/demo-jaxrs/jaxrs-client/src/main/java/org/apache/servicecomb/demo/jaxrs/client/JaxrsClient.java
index 9ee4b40..36f63c0 100644
--- 
a/demo/demo-jaxrs/jaxrs-client/src/main/java/org/apache/servicecomb/demo/jaxrs/client/JaxrsClient.java
+++ 
b/demo/demo-jaxrs/jaxrs-client/src/main/java/org/apache/servicecomb/demo/jaxrs/client/JaxrsClient.java
@@ -477,7 +477,6 @@ public class JaxrsClient {
     TestMgr.check("hello test 15", result);
   }
 
-
   private static void testSpringMvcDefaultValuesJavaPrimitiveRest(RestTemplate 
template) {
     String microserviceName = "jaxrs";
     String cseUrlPrefix = "cse://" + microserviceName + "/JaxRSDefaultValues/";
diff --git a/transports/transport-rest/transport-rest-client/pom.xml 
b/transports/transport-rest/transport-rest-client/pom.xml
index 7d436e8..fdf873d 100644
--- a/transports/transport-rest/transport-rest-client/pom.xml
+++ b/transports/transport-rest/transport-rest-client/pom.xml
@@ -62,5 +62,15 @@
       <artifactId>foundation-test-scaffolding</artifactId>
       <scope>test</scope>
     </dependency>
+    <dependency>
+      <groupId>org.apache.servicecomb</groupId>
+      <artifactId>registry-local</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.servicecomb</groupId>
+      <artifactId>swagger-generator-jaxrs</artifactId>
+      <scope>test</scope>
+    </dependency>
   </dependencies>
 </project>
diff --git 
a/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/BoundaryFactory.java
 
b/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/BoundaryFactory.java
new file mode 100644
index 0000000..a5bb2e8
--- /dev/null
+++ 
b/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/BoundaryFactory.java
@@ -0,0 +1,30 @@
+/*
+ * 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.transport.rest.client;
+
+import java.util.UUID;
+import java.util.concurrent.atomic.AtomicLong;
+
+public interface BoundaryFactory {
+  String BOUNDARY_PREFIX = "boundary-" + UUID.randomUUID().toString() + "-";
+
+  AtomicLong BOUNDARY_INDEX = new AtomicLong();
+
+  BoundaryFactory DEFAULT = () -> BOUNDARY_PREFIX + 
BOUNDARY_INDEX.getAndIncrement();
+
+  String create();
+}
diff --git 
a/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/RestClientExceptionCodes.java
 
b/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/RestClientExceptionCodes.java
new file mode 100644
index 0000000..c30010f
--- /dev/null
+++ 
b/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/RestClientExceptionCodes.java
@@ -0,0 +1,21 @@
+/*
+ * 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.transport.rest.client;
+
+public interface RestClientExceptionCodes {
+  String FAILED_TO_CREATE_REST_CLIENT_TRANSPORT_CONTEXT = 
"scb_rest_client.40000000";
+}
diff --git 
a/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/RestClientRequestParameters.java
 
b/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/RestClientRequestParameters.java
new file mode 100644
index 0000000..72aa232
--- /dev/null
+++ 
b/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/RestClientRequestParameters.java
@@ -0,0 +1,50 @@
+/*
+ * 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.transport.rest.client;
+
+import java.util.Map;
+
+import javax.servlet.http.Part;
+
+import org.apache.servicecomb.common.rest.codec.RestClientRequest;
+
+import com.google.common.collect.Multimap;
+
+import io.vertx.core.buffer.Buffer;
+
+public interface RestClientRequestParameters extends RestClientRequest {
+  Map<String, String> getCookieMap();
+
+  Map<String, Object> getFormMap();
+
+  Multimap<String, Part> getUploads();
+
+  @Override
+  Buffer getBodyBuffer();
+
+  void setBodyBuffer(Buffer bodyBuffer);
+
+  @Override
+  default void write(Buffer bodyBuffer) {
+    setBodyBuffer(bodyBuffer);
+  }
+
+  @Override
+  default void end() {
+    throw new UnsupportedOperationException("should not invoke this method");
+  }
+}
diff --git 
a/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/RestClientRequestParametersImpl.java
 
b/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/RestClientRequestParametersImpl.java
new file mode 100644
index 0000000..526b4ec
--- /dev/null
+++ 
b/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/RestClientRequestParametersImpl.java
@@ -0,0 +1,136 @@
+/*
+ * 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.transport.rest.client;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.annotation.Nonnull;
+import javax.servlet.http.Part;
+
+import org.apache.servicecomb.foundation.common.utils.PartUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.ArrayListMultimap;
+import com.google.common.collect.Multimap;
+
+import io.vertx.core.MultiMap;
+import io.vertx.core.buffer.Buffer;
+
+public class RestClientRequestParametersImpl implements 
RestClientRequestParameters {
+  private static final Logger LOGGER = 
LoggerFactory.getLogger(RestClientRequestParametersImpl.class);
+
+  protected final MultiMap headers;
+
+  protected Map<String, String> cookieMap;
+
+  protected Map<String, Object> formMap;
+
+  protected Multimap<String, Part> uploads;
+
+  protected Buffer bodyBuffer;
+
+  public RestClientRequestParametersImpl(@Nonnull MultiMap headers) {
+    this.headers = headers;
+  }
+
+  @Override
+  public Map<String, String> getCookieMap() {
+    return cookieMap;
+  }
+
+  @Override
+  public void addCookie(String name, String value) {
+    if (cookieMap == null) {
+      cookieMap = new HashMap<>();
+    }
+
+    cookieMap.put(name, value);
+  }
+
+  @Override
+  public Map<String, Object> getFormMap() {
+    return formMap;
+  }
+
+  @Override
+  public void addForm(String name, Object value) {
+    if (formMap == null) {
+      formMap = new HashMap<>();
+    }
+
+    if (value != null) {
+      formMap.put(name, value);
+    }
+  }
+
+  @Override
+  public MultiMap getHeaders() {
+    return headers;
+  }
+
+  @Override
+  public void putHeader(String name, String value) {
+    headers.add(name, value);
+  }
+
+  @Override
+  public Buffer getBodyBuffer() {
+    return bodyBuffer;
+  }
+
+  @Override
+  public void setBodyBuffer(Buffer bodyBuffer) {
+    this.bodyBuffer = bodyBuffer;
+  }
+
+  @Override
+  public Multimap<String, Part> getUploads() {
+    return uploads;
+  }
+
+  @SuppressWarnings("unchecked")
+  @Override
+  public void attach(String name, Object partOrList) {
+    if (partOrList == null) {
+      LOGGER.debug("null file is ignored, file name = [{}]", name);
+      return;
+    }
+
+    if (uploads == null) {
+      uploads = ArrayListMultimap.create();
+    }
+
+    if (partOrList.getClass().isArray()) {
+      for (Object part : (Object[]) partOrList) {
+        uploads.put(name, PartUtils.getSinglePart(name, part));
+      }
+      return;
+    }
+
+    if (partOrList instanceof Collection) {
+      for (Object part : ((Collection<Object>) partOrList)) {
+        uploads.put(name, PartUtils.getSinglePart(name, part));
+      }
+      return;
+    }
+
+    uploads.put(name, PartUtils.getSinglePart(name, partOrList));
+  }
+}
diff --git 
a/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/RestClientTransportContext.java
 
b/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/RestClientTransportContext.java
new file mode 100644
index 0000000..cd9ca2e
--- /dev/null
+++ 
b/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/RestClientTransportContext.java
@@ -0,0 +1,85 @@
+/*
+ * 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.transport.rest.client;
+
+import java.util.Optional;
+
+import org.apache.servicecomb.common.rest.definition.RestOperationMeta;
+import org.apache.servicecomb.swagger.invocation.context.VertxTransportContext;
+
+import io.vertx.core.Context;
+import io.vertx.core.http.HttpClientRequest;
+import io.vertx.core.http.HttpConnection;
+
+public class RestClientTransportContext implements VertxTransportContext {
+  private final RestOperationMeta restOperationMeta;
+
+  private final Context vertxContext;
+
+  private final HttpClientRequest httpClientRequest;
+
+  private final RestClientRequestParameters requestParameters;
+
+  private final BoundaryFactory boundaryFactory;
+
+  private String boundary;
+
+  public RestClientTransportContext(RestOperationMeta restOperationMeta, 
Context vertxContext,
+      HttpClientRequest httpClientRequest, BoundaryFactory boundaryFactory) {
+    this.restOperationMeta = restOperationMeta;
+    this.vertxContext = vertxContext;
+    this.httpClientRequest = httpClientRequest;
+    this.boundaryFactory = boundaryFactory;
+    this.requestParameters = new 
RestClientRequestParametersImpl(httpClientRequest.headers());
+  }
+
+  public RestOperationMeta getRestOperationMeta() {
+    return restOperationMeta;
+  }
+
+  public boolean isDownloadFile() {
+    return restOperationMeta.isDownloadFile();
+  }
+
+  @Override
+  public Context getVertxContext() {
+    return vertxContext;
+  }
+
+  public HttpClientRequest getHttpClientRequest() {
+    return httpClientRequest;
+  }
+
+  public RestClientRequestParameters getRequestParameters() {
+    return requestParameters;
+  }
+
+  public String getOrCreateBoundary() {
+    if (boundary == null) {
+      boundary = boundaryFactory.create();
+    }
+
+    return boundary;
+  }
+
+  public String getLocalAddress() {
+    return Optional.ofNullable(httpClientRequest.connection())
+        .map(HttpConnection::localAddress)
+        .map(Object::toString)
+        .orElse("not connected");
+  }
+}
diff --git 
a/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/RestClientTransportContextFactory.java
 
b/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/RestClientTransportContextFactory.java
new file mode 100644
index 0000000..f8ba5b4
--- /dev/null
+++ 
b/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/RestClientTransportContextFactory.java
@@ -0,0 +1,105 @@
+/*
+ * 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.transport.rest.client;
+
+import static javax.ws.rs.core.Response.Status.BAD_REQUEST;
+import static 
org.apache.servicecomb.transport.rest.client.RestClientExceptionCodes.FAILED_TO_CREATE_REST_CLIENT_TRANSPORT_CONTEXT;
+
+import org.apache.servicecomb.common.rest.RestConst;
+import org.apache.servicecomb.common.rest.definition.RestMetaUtils;
+import org.apache.servicecomb.common.rest.definition.RestOperationMeta;
+import org.apache.servicecomb.core.Invocation;
+import org.apache.servicecomb.foundation.common.net.URIEndpointObject;
+import 
org.apache.servicecomb.foundation.vertx.client.http.HttpClientWithContext;
+import org.apache.servicecomb.foundation.vertx.client.http.HttpClients;
+import org.apache.servicecomb.registry.definition.DefinitionConst;
+import org.apache.servicecomb.swagger.invocation.exception.InvocationException;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+import org.springframework.util.StringUtils;
+
+import io.vertx.core.http.HttpClient;
+import io.vertx.core.http.HttpClientRequest;
+import io.vertx.core.http.HttpMethod;
+import io.vertx.core.http.RequestOptions;
+
+@Component
+public class RestClientTransportContextFactory {
+  private BoundaryFactory boundaryFactory = BoundaryFactory.DEFAULT;
+
+  @Autowired(required = false)
+  public RestClientTransportContextFactory setBoundaryFactory(BoundaryFactory 
boundaryFactory) {
+    this.boundaryFactory = boundaryFactory;
+    return this;
+  }
+
+  public RestClientTransportContext create(Invocation invocation) {
+    try {
+      return doCreate(invocation);
+    } catch (Exception e) {
+      throw new InvocationException(BAD_REQUEST, 
FAILED_TO_CREATE_REST_CLIENT_TRANSPORT_CONTEXT, e.getMessage(), e);
+    }
+  }
+
+  protected RestClientTransportContext doCreate(Invocation invocation) throws 
Exception {
+    RestOperationMeta restOperationMeta = 
RestMetaUtils.getRestOperationMeta(invocation.getOperationMeta());
+
+    HttpClientWithContext httpClientWithContext = 
findHttpClientPool(invocation);
+    HttpClientRequest httpClientRequest = createHttpClientRequest(invocation, 
restOperationMeta,
+        httpClientWithContext.getHttpClient());
+    return new RestClientTransportContext(restOperationMeta,
+        httpClientWithContext.context(),
+        httpClientRequest,
+        boundaryFactory);
+  }
+  
+  protected HttpClientWithContext findHttpClientPool(Invocation invocation) {
+    URIEndpointObject endpoint = (URIEndpointObject) 
invocation.getEndpoint().getAddress();
+    if (endpoint.isHttp2Enabled()) {
+      return 
HttpClients.getClient(Http2TransportHttpClientOptionsSPI.CLIENT_NAME, 
invocation.isSync());
+    }
+
+    return 
HttpClients.getClient(HttpTransportHttpClientOptionsSPI.CLIENT_NAME, 
invocation.isSync());
+  }
+
+  protected HttpClientRequest createHttpClientRequest(Invocation invocation, 
RestOperationMeta restOperationMeta,
+      HttpClient httpClient) throws Exception {
+    URIEndpointObject endpoint = (URIEndpointObject) 
invocation.getEndpoint().getAddress();
+    RequestOptions requestOptions = new RequestOptions()
+        .setHost(endpoint.getHostOrIp())
+        .setPort(endpoint.getPort())
+        .setSsl(endpoint.isSslEnabled())
+        .setURI(createRequestPath(invocation, restOperationMeta));
+    HttpMethod method = HttpMethod.valueOf(restOperationMeta.getHttpMethod());
+    return httpClient.request(method, requestOptions);
+  }
+
+  protected String createRequestPath(Invocation invocation, RestOperationMeta 
restOperationMeta) throws Exception {
+    String path = 
invocation.getLocalContext(RestConst.REST_CLIENT_REQUEST_PATH);
+    if (path == null) {
+      path = 
restOperationMeta.getPathBuilder().createRequestPath(invocation.getSwaggerArguments());
+    }
+
+    URIEndpointObject endpoint = (URIEndpointObject) 
invocation.getEndpoint().getAddress();
+    String urlPrefix = endpoint.getFirst(DefinitionConst.URL_PREFIX);
+    if (StringUtils.isEmpty(urlPrefix) || path.startsWith(urlPrefix)) {
+      return path;
+    }
+
+    return urlPrefix + path;
+  }
+}
diff --git 
a/transports/transport-rest/transport-rest-client/src/test/java/org/apache/servicecomb/transport/rest/client/RestClientTransportContextFactoryTest.java
 
b/transports/transport-rest/transport-rest-client/src/test/java/org/apache/servicecomb/transport/rest/client/RestClientTransportContextFactoryTest.java
new file mode 100644
index 0000000..563bf3b
--- /dev/null
+++ 
b/transports/transport-rest/transport-rest-client/src/test/java/org/apache/servicecomb/transport/rest/client/RestClientTransportContextFactoryTest.java
@@ -0,0 +1,168 @@
+/*
+ * 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.transport.rest.client;
+
+import static 
org.apache.servicecomb.transport.rest.client.RestFeatureController.SCHEMA_ID;
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.util.Arrays;
+import java.util.Map;
+
+import org.apache.servicecomb.common.rest.definition.RestMetaUtils;
+import org.apache.servicecomb.common.rest.definition.RestOperationMeta;
+import org.apache.servicecomb.config.ConfigUtil;
+import org.apache.servicecomb.core.Const;
+import org.apache.servicecomb.core.Endpoint;
+import org.apache.servicecomb.core.Invocation;
+import org.apache.servicecomb.core.SCBEngine;
+import org.apache.servicecomb.core.Transport;
+import org.apache.servicecomb.core.bootstrap.SCBBootstrap;
+import org.apache.servicecomb.core.definition.InvocationRuntimeType;
+import org.apache.servicecomb.core.definition.OperationMeta;
+import org.apache.servicecomb.core.invocation.InvocationFactory;
+import org.apache.servicecomb.core.provider.consumer.ReferenceConfig;
+import org.apache.servicecomb.core.transport.AbstractTransport;
+import org.apache.servicecomb.foundation.common.net.URIEndpointObject;
+import org.apache.servicecomb.foundation.test.scaffolding.config.ArchaiusUtils;
+import org.apache.servicecomb.foundation.vertx.client.http.HttpClients;
+import org.apache.servicecomb.swagger.invocation.AsyncResponse;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+
+import com.google.common.collect.ImmutableMap;
+
+class RestClientTransportContextFactoryTest {
+  static SCBEngine scbEngine;
+
+  static Transport restTransport = new AbstractTransport() {
+    @Override
+    public String getName() {
+      return null;
+    }
+
+    @Override
+    public boolean init() {
+      return false;
+    }
+
+    @Override
+    public void send(Invocation invocation, AsyncResponse asyncResp) {
+
+    }
+
+    @Override
+    public Object parseAddress(String address) {
+      return new URIEndpointObject(address);
+    }
+  };
+
+  static RestClientTransportContextFactory factory = new 
RestClientTransportContextFactory()
+      .setBoundaryFactory(BoundaryFactory.DEFAULT);
+
+  static OperationMeta operationMeta;
+
+  static RestOperationMeta restOperationMeta;
+
+  static ReferenceConfig referenceConfig = new ReferenceConfig(Const.RESTFUL, 
Const.DEFAULT_VERSION_RULE);
+
+  @BeforeAll
+  static void beforeAll() {
+    ConfigUtil.installDynamicConfig();
+    scbEngine = SCBBootstrap.createSCBEngineForTest()
+        .addProducerMeta(SCHEMA_ID, new RestFeatureController())
+        .run();
+    operationMeta = scbEngine.getProducerMicroserviceMeta()
+        .ensureFindSchemaMeta(SCHEMA_ID)
+        .ensureFindOperation("query");
+    restOperationMeta = RestMetaUtils.getRestOperationMeta(operationMeta);
+    HttpClients.load();
+  }
+
+  @AfterAll
+  static void afterAll() {
+    scbEngine.destroy();
+    HttpClients.destroy();
+
+    ArchaiusUtils.resetConfig();
+  }
+
+  Invocation invocation;
+
+  RestClientTransportContext transportContext;
+
+  void initInvocation(Map<String, Object> swaggerArgs, boolean ssl) {
+    invocation = InvocationFactory.forConsumer(
+        referenceConfig, operationMeta, new InvocationRuntimeType(null), 
swaggerArgs);
+
+    String url = "rest://localhost:1234?sslEnabled=" + ssl;
+    invocation.setEndpoint(new Endpoint(restTransport, url));
+  }
+
+  String absoluteURI() {
+    return transportContext.getHttpClientRequest().absoluteURI();
+  }
+
+  @Test
+  void should_create_without_ssl() {
+    initInvocation(null, false);
+
+    transportContext = factory.create(invocation);
+    assertThat(absoluteURI()).isEqualTo("http://localhost:1234/query";);
+  }
+
+  @Test
+  void should_create_with_ssl() {
+    initInvocation(null, true);
+
+    transportContext = factory.create(invocation);
+    assertThat(absoluteURI()).isEqualTo("https://localhost:1234/query";);
+  }
+
+  @Test
+  void should_create_with_query() {
+    initInvocation(ImmutableMap.of("query", "value"), true);
+
+    transportContext = factory.create(invocation);
+    
assertThat(absoluteURI()).isEqualTo("https://localhost:1234/query?query=value";);
+  }
+
+  @Test
+  void should_create_with_query_list() {
+    initInvocation(ImmutableMap.of("query", Arrays.asList("v1", "v2")), true);
+
+    transportContext = factory.create(invocation);
+    
assertThat(absoluteURI()).isEqualTo("https://localhost:1234/query?query=v1&query=v2";);
+  }
+
+  @Test
+  void should_create_with_query_array() {
+    initInvocation(ImmutableMap.of("query", new String[] {"v1", "v2"}), true);
+
+    transportContext = factory.create(invocation);
+    
assertThat(absoluteURI()).isEqualTo("https://localhost:1234/query?query=v1&query=v2";);
+  }
+
+  @Test
+  void should_get_local_address_as_not_connected_before_connect() {
+    initInvocation(null, true);
+
+    transportContext = factory.create(invocation);
+    assertThat(transportContext.getLocalAddress()).isEqualTo("not connected");
+  }
+}
\ No newline at end of file
diff --git 
a/transports/transport-rest/transport-rest-client/src/test/java/org/apache/servicecomb/transport/rest/client/RestFeatureController.java
 
b/transports/transport-rest/transport-rest-client/src/test/java/org/apache/servicecomb/transport/rest/client/RestFeatureController.java
new file mode 100644
index 0000000..a11f10f
--- /dev/null
+++ 
b/transports/transport-rest/transport-rest-client/src/test/java/org/apache/servicecomb/transport/rest/client/RestFeatureController.java
@@ -0,0 +1,32 @@
+/*
+ * 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.transport.rest.client;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.QueryParam;
+
+@Path("/")
+public class RestFeatureController {
+  public static final String SCHEMA_ID = "rest-feature";
+
+  @GET
+  @Path("/query")
+  public String query(@QueryParam("query") String query) {
+    return query;
+  }
+}

Reply via email to