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;
+ }
+}